@@ -1181,6 +1181,8 @@ TDynamicDll = class(TComponent)
11811181 procedure DoOpenDll (const aDllName : string); virtual ;
11821182 function GetDllPath : string;
11831183
1184+ function HasHostSymbols (): boolean;
1185+ procedure LoadFromHostSymbols ();
11841186 public
11851187 // Constructors & Destructors
11861188 constructor Create(AOwner: TComponent); override;
@@ -2727,6 +2729,8 @@ procedure Register;
27272729function PyType_HasFeature (AType : PPyTypeObject; AFlag : Integer) : Boolean;
27282730function SysVersionFromDLLName (const DLLFileName : string): string;
27292731procedure PythonVersionFromDLLName (LibName: string; out MajorVersion, MinorVersion: integer);
2732+ function SpliVersionFromRegVersion (const ARegVersion: string;
2733+ out AMajorVersion, AMinorVersion: integer): boolean;
27302734
27312735{ Helper functions}
27322736(*
@@ -3083,15 +3087,62 @@ function TDynamicDll.IsHandleValid : Boolean;
30833087{ $ENDIF}
30843088end ;
30853089
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+
30863131procedure TDynamicDll.LoadDll ;
30873132begin
30883133 OpenDll( DllName );
30893134end ;
30903135
30913136procedure TDynamicDll.LoadDllInExtensionModule ;
30923137begin
3138+ // We want to look in for host symbols at first
3139+ FDLLHandle := 0 ;
3140+
30933141 FInExtensionModule := True;
3094- LoadDLL;
3142+ if HasHostSymbols() then
3143+ LoadFromHostSymbols()
3144+ else
3145+ LoadDLL;
30953146end ;
30963147
30973148procedure TDynamicDll.UnloadDll ;
@@ -3126,6 +3177,17 @@ function TDynamicDll.GetQuitMessage : string;
31263177 Result := Format( ' Dll %s could not be loaded. We must quit.' , [DllName]);
31273178end ;
31283179
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+
31293191procedure TDynamicDll.Quit ;
31303192begin
31313193 if not ( csDesigning in ComponentState ) then begin
@@ -3182,7 +3244,10 @@ constructor TPythonInterface.Create(AOwner: TComponent);
31823244procedure TPythonInterface.AfterLoad ;
31833245begin
31843246 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.' );
31863251
31873252 FBuiltInModuleName := ' builtins' ;
31883253
@@ -3578,7 +3643,7 @@ procedure TPythonInterface.MapDll;
35783643 Py_GetPrefix := Import (' Py_GetPrefix' );
35793644 Py_GetProgramName := Import (' Py_GetProgramName' );
35803645
3581- if (FMajorVersion = 3 ) and (MinorVersion < 10 ) then
3646+ if (FMajorVersion = 3 ) and (FMinorVersion < 10 ) then
35823647 begin
35833648 PyParser_SimpleParseStringFlags := Import (' PyParser_SimpleParseStringFlags' );
35843649 PyNode_Free := Import (' PyNode_Free' );
@@ -9188,6 +9253,18 @@ procedure PythonVersionFromDLLName(LibName: string; out MajorVersion, MinorVersi
91889253 MinorVersion:= StrToIntDef(LibName, DefaultMinor);
91899254end ;
91909255
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 ;
91919268
91929269end .
91939270
0 commit comments