@@ -1197,8 +1197,13 @@ TDynamicDll = class(TComponent)
1197
1197
procedure DoOpenDll (const aDllName : string); virtual ;
1198
1198
function GetDllPath : string;
1199
1199
1200
+ procedure LoadPythonInfoFromModule ;
1201
+ function GetPythonModuleFromProcess (): NativeUInt;
1200
1202
function HasHostSymbols (): boolean;
1201
1203
procedure LoadFromHostSymbols ();
1204
+ // Loading strategies
1205
+ function TryLoadFromHostSymbols (): boolean;
1206
+ function TryLoadFromCurrentProcess (): boolean;
1202
1207
public
1203
1208
// Constructors & Destructors
1204
1209
constructor Create(AOwner: TComponent); override;
@@ -2783,6 +2788,7 @@ implementation
2783
2788
{ $ENDIF}
2784
2789
{ $IFDEF MSWINDOWS}
2785
2790
Registry,
2791
+ PsAPI,
2786
2792
{ $ENDIF}
2787
2793
Math;
2788
2794
@@ -3019,6 +3025,123 @@ function TDynamicDll.GetDllPath : string;
3019
3025
end ;
3020
3026
end ;
3021
3027
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
+
3022
3145
procedure TDynamicDll.OpenDll (const aDllName : string);
3023
3146
var
3024
3147
s : string;
@@ -3107,15 +3230,42 @@ function TDynamicDll.IsHandleValid : Boolean;
3107
3230
{ $ENDIF}
3108
3231
end ;
3109
3232
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
+
3110
3254
procedure TDynamicDll.LoadFromHostSymbols ;
3255
+ begin
3256
+ BeforeLoad();
3257
+ LoadPythonInfoFromModule();
3258
+ AfterLoad();
3259
+ end ;
3260
+
3261
+ procedure TDynamicDll.LoadPythonInfoFromModule ;
3111
3262
var
3112
3263
LPy_GetVersion: function: PAnsiChar; cdecl;
3113
3264
LPy_GetProgramFullPath: function: PAnsiChar; cdecl;
3114
3265
LVersion: string;
3115
3266
LInfo: TPythonVersionProp;
3116
3267
LFound: boolean;
3117
3268
begin
3118
- BeforeLoad();
3119
3269
// According to the doc:
3120
3270
// Return the full program name of the Python executable.
3121
3271
// The value is available to Python code as sys.executable.
@@ -3143,9 +3293,7 @@ procedure TDynamicDll.LoadFromHostSymbols;
3143
3293
end ;
3144
3294
3145
3295
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.' );
3149
3297
end ;
3150
3298
3151
3299
procedure TDynamicDll.LoadDll ;
@@ -3155,14 +3303,18 @@ procedure TDynamicDll.LoadDll;
3155
3303
3156
3304
procedure TDynamicDll.LoadDllInExtensionModule ;
3157
3305
begin
3158
- // We want to look in for host symbols at first
3159
- FDLLHandle := 0 ;
3306
+ if not ModuleIsLib then
3307
+ Exit ;
3160
3308
3161
3309
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();
3166
3318
end ;
3167
3319
3168
3320
procedure TDynamicDll.UnloadDll ;
@@ -3201,9 +3353,6 @@ function TDynamicDll.HasHostSymbols: boolean;
3201
3353
var
3202
3354
LPy_IsInitialized: function: integer; cdecl;
3203
3355
begin
3204
- if not ModuleIsLib then
3205
- Exit(false);
3206
-
3207
3356
LPy_IsInitialized := Import (' Py_IsInitialized' , false);
3208
3357
Result := Assigned(LPy_IsInitialized) and (LPy_IsInitialized() <> 0 );
3209
3358
end ;
@@ -9241,6 +9390,7 @@ function IsPythonVersionRegistered(PythonVersion : string;
9241
9390
except
9242
9391
end ;
9243
9392
end ;
9393
+
9244
9394
{ $ENDIF}
9245
9395
9246
9396
procedure PythonVersionFromDLLName (LibName: string; out MajorVersion, MinorVersion: integer);
0 commit comments