@@ -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('  ' 
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.' 
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' 
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(' .' 
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