@@ -1181,6 +1181,8 @@ TDynamicDll = class(TComponent)
1181
1181
procedure DoOpenDll (const aDllName : string); virtual ;
1182
1182
function GetDllPath : string;
1183
1183
1184
+ function HasHostSymbols (): boolean;
1185
+ procedure LoadFromHostSymbols ();
1184
1186
public
1185
1187
// Constructors & Destructors
1186
1188
constructor Create(AOwner: TComponent); override;
@@ -2727,6 +2729,8 @@ procedure Register;
2727
2729
function PyType_HasFeature (AType : PPyTypeObject; AFlag : Integer) : Boolean;
2728
2730
function SysVersionFromDLLName (const DLLFileName : string): string;
2729
2731
procedure PythonVersionFromDLLName (LibName: string; out MajorVersion, MinorVersion: integer);
2732
+ function SpliVersionFromRegVersion (const ARegVersion: string;
2733
+ out AMajorVersion, AMinorVersion: integer): boolean;
2730
2734
2731
2735
{ Helper functions}
2732
2736
(*
@@ -3083,15 +3087,62 @@ function TDynamicDll.IsHandleValid : Boolean;
3083
3087
{ $ENDIF}
3084
3088
end ;
3085
3089
3090
+ procedure TDynamicDll.LoadFromHostSymbols ;
3091
+ var
3092
+ LPy_GetVersion: function: PAnsiChar; cdecl;
3093
+ LPy_GetProgramFullPath: function: PAnsiChar; cdecl;
3094
+ LVersion: string;
3095
+ LInfo: TPythonVersionProp;
3096
+ LFound: boolean;
3097
+ begin
3098
+ BeforeLoad();
3099
+ // According to the doc:
3100
+ // Return the full program name of the Python executable.
3101
+ // The value is available to Python code as sys.executable.
3102
+ LPy_GetProgramFullPath := Import (' Py_GetProgramFullPath' );
3103
+ DllName := ExtractFileName(String(LPy_GetProgramFullPath()));
3104
+
3105
+ // According to the doc:
3106
+ // The first word (up to the first space character) is the current Python version
3107
+ LPy_GetVersion := Import (' Py_GetVersion' );
3108
+ LVersion := String(LPy_GetVersion());
3109
+ LVersion := Copy(LVersion, 1 , Pos(' ' , LVersion));
3110
+ // the first three characters are the major and minor version separated by a period.
3111
+ if (Length(LVersion) > 3 ) and (LVersion[4 ] <> ' .' ) then
3112
+ LVersion := Copy(LVersion, 1 , 4 ) // e.g. 3.10
3113
+ else
3114
+ LVersion := Copy(LVersion, 1 , 3 ); // e.g. 3.9
3115
+
3116
+ LFound := false;
3117
+ for LInfo in PYTHON_KNOWN_VERSIONS do
3118
+ if (LInfo.RegVersion = LVersion) then begin
3119
+ RegVersion := LInfo.RegVersion;
3120
+ APIVersion := LInfo.APIVersion;
3121
+ LFound := true;
3122
+ Break;
3123
+ end ;
3124
+
3125
+ if not LFound then
3126
+ raise EDLLLoadError.Create(' Undetermined Python version from host symbols.' );
3127
+
3128
+ AfterLoad();
3129
+ end ;
3130
+
3086
3131
procedure TDynamicDll.LoadDll ;
3087
3132
begin
3088
3133
OpenDll( DllName );
3089
3134
end ;
3090
3135
3091
3136
procedure TDynamicDll.LoadDllInExtensionModule ;
3092
3137
begin
3138
+ // We want to look in for host symbols at first
3139
+ FDLLHandle := 0 ;
3140
+
3093
3141
FInExtensionModule := True;
3094
- LoadDLL;
3142
+ if HasHostSymbols() then
3143
+ LoadFromHostSymbols()
3144
+ else
3145
+ LoadDLL;
3095
3146
end ;
3096
3147
3097
3148
procedure TDynamicDll.UnloadDll ;
@@ -3126,6 +3177,17 @@ function TDynamicDll.GetQuitMessage : string;
3126
3177
Result := Format( ' Dll %s could not be loaded. We must quit.' , [DllName]);
3127
3178
end ;
3128
3179
3180
+ function TDynamicDll.HasHostSymbols : boolean;
3181
+ var
3182
+ LPy_IsInitialized: function: integer; cdecl;
3183
+ begin
3184
+ if not ModuleIsLib then
3185
+ Exit(false);
3186
+
3187
+ LPy_IsInitialized := Import (' Py_IsInitialized' , false);
3188
+ Result := Assigned(LPy_IsInitialized) and (LPy_IsInitialized() <> 0 );
3189
+ end ;
3190
+
3129
3191
procedure TDynamicDll.Quit ;
3130
3192
begin
3131
3193
if not ( csDesigning in ComponentState ) then begin
@@ -3182,7 +3244,10 @@ constructor TPythonInterface.Create(AOwner: TComponent);
3182
3244
procedure TPythonInterface.AfterLoad ;
3183
3245
begin
3184
3246
inherited ;
3185
- PythonVersionFromDLLName(DLLName, FMajorVersion, FMinorVersion);
3247
+ if not FInExtensionModule then
3248
+ PythonVersionFromDLLName(DLLName, FMajorVersion, FMinorVersion)
3249
+ else if not SpliVersionFromRegVersion(RegVersion, FMajorVersion, FMinorVersion) then
3250
+ raise EDLLLoadError.Create(' Undetermined Python version.' );
3186
3251
3187
3252
FBuiltInModuleName := ' builtins' ;
3188
3253
@@ -3578,7 +3643,7 @@ procedure TPythonInterface.MapDll;
3578
3643
Py_GetPrefix := Import (' Py_GetPrefix' );
3579
3644
Py_GetProgramName := Import (' Py_GetProgramName' );
3580
3645
3581
- if (FMajorVersion = 3 ) and (MinorVersion < 10 ) then
3646
+ if (FMajorVersion = 3 ) and (FMinorVersion < 10 ) then
3582
3647
begin
3583
3648
PyParser_SimpleParseStringFlags := Import (' PyParser_SimpleParseStringFlags' );
3584
3649
PyNode_Free := Import (' PyNode_Free' );
@@ -9188,6 +9253,18 @@ procedure PythonVersionFromDLLName(LibName: string; out MajorVersion, MinorVersi
9188
9253
MinorVersion:= StrToIntDef(LibName, DefaultMinor);
9189
9254
end ;
9190
9255
9256
+ function SpliVersionFromRegVersion (const ARegVersion: string;
9257
+ out AMajorVersion, AMinorVersion: integer): boolean;
9258
+ var
9259
+ LSepPos: integer;
9260
+ begin
9261
+ // RegVersion supported format: [x.x or x.xx or x[..].x[..]]
9262
+ LSepPos := Pos(' .' , ARegVersion);
9263
+ AMajorVersion := StrToIntDef(Copy(ARegVersion, 1 , LSepPos - 1 ), 0 );
9264
+ AMinorVersion := StrToIntDef(Copy(ARegVersion, LSepPos + 1 , Length(ARegVersion) - LSepPos), 0 );
9265
+
9266
+ Result := (AMajorVersion > 0 ) and (AMinorVersion > 0 );
9267
+ end ;
9191
9268
9192
9269
end .
9193
9270
0 commit comments