@@ -1197,8 +1197,13 @@   TDynamicDll = class(TComponent)
11971197    procedure  DoOpenDll (const  aDllName : string); virtual ;
11981198    function   GetDllPath  : string;
11991199
1200+     procedure  LoadPythonInfoFromModule ;
1201+     function  GetPythonModuleFromProcess (): NativeUInt;
12001202    function  HasHostSymbols (): boolean;
12011203    procedure  LoadFromHostSymbols ();
1204+     // Loading strategies
1205+     function  TryLoadFromHostSymbols (): boolean;
1206+     function  TryLoadFromCurrentProcess (): boolean;
12021207  public 
12031208    //  Constructors & Destructors
12041209    constructor  Create(AOwner: TComponent); override;
@@ -2783,6 +2788,7 @@ implementation
27832788{ $ENDIF} 
27842789{ $IFDEF MSWINDOWS} 
27852790  Registry,
2791+   PsAPI,
27862792{ $ENDIF} 
27872793  Math;
27882794
@@ -3019,6 +3025,123 @@ function  TDynamicDll.GetDllPath : string;
30193025  end ;
30203026end ;
30213027
3028+ function  TDynamicDll.GetPythonModuleFromProcess (): NativeUInt;
3029+ 
3030+ { $IFNDEF FPC} 
3031+ 
3032+ function  HasSymbols (const  AModule: NativeUInt): boolean;
3033+   var 
3034+     LPy_GetBuildInfo: function : PAnsiChar; cdecl;
3035+     LPy_IsInitialized: function: integer; cdecl;
3036+   begin 
3037+     FDLLHandle := AModule;
3038+     try 
3039+       LPy_GetBuildInfo := Import (' Py_GetBuildInfo' 
3040+       LPy_IsInitialized := Import (' Py_IsInitialized' 
3041+       Result := Assigned(LPy_GetBuildInfo) and  Assigned(LPy_GetBuildInfo())
3042+         and  Assigned(LPy_IsInitialized) and  (LPy_IsInitialized() <> 0 );
3043+     finally 
3044+       FDLLHandle := 0 ;
3045+     end ;
3046+   end ;
3047+ 
3048+ { $IFDEF LINUX} 
3049+   function  GetPythonModule : NativeUInt;
3050+   type 
3051+     plink_map = ^link_map;
3052+     link_map = record 
3053+       l_addr: Pointer;
3054+       l_name: PAnsiChar;
3055+       l_ld: Pointer;
3056+       l_next, l_prev: plink_map;
3057+     end ;
3058+   var 
3059+     LPseudoHandle: NativeUInt;
3060+     LPLinkMap: plink_map;
3061+     LModuleName: string;
3062+     LModuleHandle: NativeUInt;
3063+   begin 
3064+     // In Linux pseudo handle is in fact a pointer to the the corresponding link_map structure
3065+     // The dlopen(nil, RTLD_NOW) result is the pseudo handle for the main executable (similar to GetModuleHandle(nil) in Windows).
3066+     LPseudoHandle := dlopen(nil , RTLD_NOW);
3067+     // Points to the first link_map
3068+     LPLinkMap := plink_map(LPseudoHandle).l_next.l_next;
3069+     while  Assigned(LPLinkMap) do  begin 
3070+       LModuleName := String(LPLinkMap.l_name);
3071+       LModuleHandle := LoadLibrary(PChar(LModuleName));
3072+       if  HasSymbols(LModuleHandle) then 
3073+         Exit(LModuleHandle);
3074+       LPLinkMap := LPLinkMap.l_next;
3075+     end ;
3076+     Result := 0 ;
3077+   end ;
3078+ { $ENDIF LINUX} 
3079+ 
3080+ { $IFDEF OSX} 
3081+   function  GetPythonModule : NativeUInt;
3082+   var 
3083+     LIndex: integer;
3084+     LName: PAnsiChar;
3085+     LModuleName: string;
3086+     LModuleHandle: NativeUInt;
3087+   begin 
3088+     LIndex := 0 ;
3089+     LName := _dyld_get_image_name(LIndex);
3090+     while  (LName <> nil ) do  begin 
3091+       LModuleName := String(LName);
3092+       LModuleHandle := LoadLibrary(PChar(LModuleName));
3093+       if  HasSymbols(LModuleHandle) then 
3094+         Exit(LModuleHandle);
3095+       Inc(LIndex);
3096+       LName := _dyld_get_image_name(LIndex);
3097+     end ;
3098+     Result := 0 ;
3099+   end ;
3100+ { $ENDIF OSX} 
3101+ 
3102+ { $IFDEF MSWINDOWS} 
3103+   function  GetPythonModule : NativeUInt;
3104+   var 
3105+     LHProcess: NativeUInt;
3106+     LHModules: array  of  NativeUInt;
3107+     LCbNeeded: Cardinal;
3108+     I: Integer;
3109+     LModName: array [0 ..1024 ] of  char;
3110+   begin 
3111+     SetLength(LHModules, 1024 );
3112+     LHProcess := OpenProcess(PROCESS_QUERY_INFORMATION + PROCESS_VM_READ, false, GetCurrentProcessId());
3113+     if  LHProcess > 0  then  begin 
3114+       try 
3115+         if  EnumProcessModules(LHProcess, @LHModules[0 ], 1024  * SizeOf(HMODULE), LCbNeeded) then  begin 
3116+           SetLength(LHModules, LCbNeeded div  SizeOf(THandle));
3117+           for  I := 0  to  Length(LHModules) -1  do  begin 
3118+             GetModuleBaseName(LHProcess, LHModules[I], LModName, SizeOf(LModName));
3119+             if  HasSymbols(LHModules[I]) then  begin 
3120+               Exit(LHModules[I]);
3121+             end ;
3122+           end ;
3123+         end ;
3124+       finally 
3125+         CloseHandle(LHProcess);
3126+       end ;
3127+     end ;
3128+     Result := 0 ;
3129+   end ;
3130+ { $ENDIF MSWINDOWS} 
3131+ { $ENDIF FPC} 
3132+ 
3133+ begin 
3134+   { $IF DEFINED(LINUX) OR DEFINED(OSX) OR DEFINED(MSWINDOWS)} 
3135+     { $IFNDEF FPC} 
3136+     Result := GetPythonModule();
3137+     { $ELSE} 
3138+     Result := 0 ;
3139+     { $ENDIF} 
3140+   { $ELSE} 
3141+   Result := 0 ;
3142+   { $IFEND} 
3143+ end ;
3144+ 
30223145procedure   TDynamicDll.OpenDll (const  aDllName : string);
30233146var 
30243147  s : string;
@@ -3107,15 +3230,42 @@ function  TDynamicDll.IsHandleValid : Boolean;
31073230{ $ENDIF} 
31083231end ;
31093232
3233+ function  TDynamicDll.TryLoadFromCurrentProcess : boolean;
3234+ begin 
3235+   FDLLHandle := GetPythonModuleFromProcess();
3236+   if  not  IsHandleValid() then 
3237+     Exit(false);
3238+ 
3239+   BeforeLoad();
3240+   LoadPythonInfoFromModule();
3241+   AfterLoad();
3242+   Result := true;
3243+ end ;
3244+ 
3245+ function  TDynamicDll.TryLoadFromHostSymbols : boolean;
3246+ begin 
3247+   // We want to look in for host symbols at first
3248+   FDLLHandle := 0 ;
3249+   Result := HasHostSymbols();
3250+   if  Result then 
3251+     LoadFromHostSymbols();
3252+ end ;
3253+ 
31103254procedure  TDynamicDll.LoadFromHostSymbols ;
3255+ begin 
3256+   BeforeLoad();
3257+   LoadPythonInfoFromModule();
3258+   AfterLoad();
3259+ end ;
3260+ 
3261+ procedure  TDynamicDll.LoadPythonInfoFromModule ;
31113262var 
31123263  LPy_GetVersion: function: PAnsiChar; cdecl;
31133264  LPy_GetProgramFullPath: function: PAnsiChar; cdecl;
31143265  LVersion: string;
31153266  LInfo: TPythonVersionProp;
31163267  LFound: boolean;
31173268begin 
3118-   BeforeLoad();
31193269  // According to the doc:
31203270  // Return the full program name of the Python executable.
31213271  // The value is available to Python code as sys.executable.
@@ -3143,9 +3293,7 @@ procedure TDynamicDll.LoadFromHostSymbols;
31433293    end ;
31443294
31453295  if  not  LFound then 
3146-     raise EDLLLoadError.Create(' Undetermined Python version from host symbols.' 
3147- 
3148-   AfterLoad();
3296+     raise EDLLLoadError.Create(' Undetermined Python version from loaded module.' 
31493297end ;
31503298
31513299procedure  TDynamicDll.LoadDll ;
@@ -3155,14 +3303,18 @@ procedure TDynamicDll.LoadDll;
31553303
31563304procedure  TDynamicDll.LoadDllInExtensionModule ;
31573305begin 
3158-   // We want to look in for host symbols at first 
3159-   FDLLHandle :=  0 ;
3306+   if   not  ModuleIsLib  then 
3307+     Exit ;
31603308
31613309  FInExtensionModule := True;
3162-   if  HasHostSymbols() then 
3163-     LoadFromHostSymbols()
3164-   else 
3165-     LoadDLL;
3310+ 
3311+   if  TryLoadFromHostSymbols() then 
3312+     Exit;
3313+ 
3314+   if  TryLoadFromCurrentProcess() then 
3315+     Exit;
3316+ 
3317+   LoadDLL();
31663318end ;
31673319
31683320procedure  TDynamicDll.UnloadDll ;
@@ -3201,9 +3353,6 @@ function TDynamicDll.HasHostSymbols: boolean;
32013353var 
32023354  LPy_IsInitialized: function: integer; cdecl;
32033355begin 
3204-   if  not  ModuleIsLib then 
3205-     Exit(false);
3206- 
32073356  LPy_IsInitialized := Import (' Py_IsInitialized' 
32083357  Result := Assigned(LPy_IsInitialized) and  (LPy_IsInitialized() <> 0 );
32093358end ;
@@ -9241,6 +9390,7 @@ function IsPythonVersionRegistered(PythonVersion : string;
92419390  except 
92429391  end ;
92439392end ;
9393+ 
92449394{ $ENDIF} 
92459395
92469396procedure  PythonVersionFromDLLName (LibName: string; out MajorVersion, MinorVersion: integer);
0 commit comments