@@ -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' , false);
3040+ LPy_IsInitialized := Import (' Py_IsInitialized' , false);
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' , false);
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