Jump to content

PierreC

Members
  • Content Count

    9
  • Joined

  • Last visited

Everything posted by PierreC

  1. Hello everyone, I have another question: is there a way to get the prompt argument of the python input() function? For example if the python code is input("Please, give me a number") I would like to get this string when dealing with the OnReceiveData or OnReceiveUniData events.
  2. PierreC

    Get the propt value of input()

    Ok, thank you. I will have a look at this possibility.
  3. Hello, In my quest to integrate python scripting into my application, I encounter another problem. I have to use P4D in a kind of plugin of my Windows application, which forces me to instantiate and release the python library several times in the same process (but never simultaneously). This is not a problem except when some modules are imported. For example, if I import numpy or win32com, the second call to import triggers an exception: EPyTypeError for win32com, Access violation for numpy. Here is an ultra-simplified example of what I do: program LoadTwice; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, PythonEngine; var pythonEngine: TPythonEngine; begin pythonEngine:= TPyThonEngine.Create(nil); pythonEngine.LoadDll; pythonEngine.ExecString('import numpy'); pythonEngine.Free; pythonEngine:= TPyThonEngine.Create(nil); pythonEngine.LoadDll; pythonEngine.ExecString('import numpy'); pythonEngine.Free; end. Do you have any idea what I'm doing wrong?
  4. PierreC

    Unable to instantiate the library twice

    I just discovered a post that details the same problem. It seems that multiple loading is not supported by P4D or rather by the python library. Sorry for the inconvenience. https://github.com/pyscripter/python4delphi/issues/287
  5. PierreC

    Marshalling COM Objects

    Hello, First of all, I want to congratulate the creator of P4D for the excellent work done. I am currently trying to use P4D to add scripting functions to an existing application. This one already has interfaces and co-class to manipulate it. I can't manage to make these COM objects available to the python code, would you have a clue ? I don't know if it is possible to do late-binding in python (calls by the Invoke method of the IUnknown interface) or if it is mandatory to use ComTypes or Win32Types to generate the corresponding python classes. But in this case, how to transtype the objects from Delphi ? If it is necessary, I can build an example project. Pierre
  6. PierreC

    Marshalling COM Objects

    Hello, I have been having a lot of trouble getting this mechanism to work in my application. RTTI doesn't seem to be able to enumerate the methods of my instances, this is certainly due to the fact that there is no "correctly" registered type library. So I looked at another possibility which is to : On the Delphi side: 1 - define a variable of type integer in a module, 2 - store the IDispatch interface address of the instance in this variable, On the Python side 3 - retrieve this value, 4 - Using pythoncom.ObjectFromAddress(), retrieve a python object instance from this address. 5 - Wrap the python object in IDispatch class using the win32com.client.Dispatch() method This may not be perfect (I'm a total beginner in python) but it seems to works well and allows me to use the IDispatch mechanism, which is fine for me because I have objects implementing dynamic methods and properties through GetIDOfNames and Invoke. Here is a simple demo that may help someone else who is looking for this kind of information: program MiniIDispatchDemo; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, PythonEngine, ComObj, ActiveX; var pythonEngine: TPythonEngine; delphiModule: TPythonModule; regExp: IDispatch; addressAsInt: NativeInt; pyAddress: PPyObject; begin // We are using COM, so we need to initialize it first CoInitialize(nil); try // Let's create a PythonEngine pythonEngine:= TPyThonEngine.Create(nil); // And a module to store our variable delphiModule := TPythonModule.Create(nil); delphiModule.Name := 'DelphiModule'; delphiModule.Engine := pythonEngine; delphiModule.ModuleName := 'delphi'; // Initialize the Python library pythonEngine.LoadDll; // Here we instanciate a RegExp object as a simple IDispatch interface // This can be replaced by any other IDispatch interface regExp:= CreateOleObject('VBScript.RegExp'); // Then we get the address as an int addressAsInt:= NativeInt(regExp); // Get an integer Python object with the same value pyAddress:= pythonEngine.PyLong_FromLong(addressAsInt); // and store the value in a variable of our module delphiModule.SetVar('regexpAddress', pyAddress); // Don't forget the decrease the ref count pythonEngine.Py_DecRef(pyAddress); try pythonEngine.ExecString( // Imports all needed modules incuing our own module named "delphi" 'from delphi import regexpAddress' + sLineBreak + 'import pythoncom' + sLineBreak + 'from win32com.client import Dispatch' + sLineBreak + // Get a python object containing from the address of the interface 're = pythoncom.ObjectFromAddress(regexpAddress, pythoncom.IID_IDispatch)' + sLineBreak + // Cast this object to an IDispatch object 'regexp = Dispatch(re)' + sLineBreak + // And use it's properties and methods 'regexp.Pattern = "delphi"' + sLineBreak + 'print(regexp.Replace("Using regexp in delphi", "python"))'); // This prints: Using regexp in python finally delphiModule.Free; pythonEngine.Free; end; finally CoUninitialize(); end; end. Pierre
  7. PierreC

    Marshalling COM Objects

    You are absolutely right, I had missed this directive. The example is working correctly now. I will continue to dig into it to see if it can help me achieve what I need. Thanks again for your help. Pierre
  8. PierreC

    Marshalling COM Objects

    Hy again, I was able to reproduce the example given in WrapDelphiTest.pas without difficulty but I think that it does not suit my situation. If I'm not mistaken, it seems to me that this method can only work if you have the Delphi class that implements the interface because it is RTTI that enumerates the members of the class and makes them available to the wrapper. In my case, I don't have the Delphi classes at my disposal because they are defined in other dlls. Does my reasoning seem correct to you? Here is an example of what I would like to do, I made it as short as possible and it uses an interface and a co-class normally available on any Windows machine. uses Rtti, VarPyth, ComObj; {$R *.dfm} const IID_IRegExp: TGUID = '{3F4DACA0-160D-11D2-A8E9-00104B365C9F}'; CLASS_RegExp: TGUID = '{3F4DACA4-160D-11D2-A8E9-00104B365C9F}'; type IRegExp = interface(IDispatch) ['{3F4DACA0-160D-11D2-A8E9-00104B365C9F}'] function Get_Pattern: WideString; safecall; procedure Set_Pattern(const pPattern: WideString); safecall; function Get_IgnoreCase: WordBool; safecall; procedure Set_IgnoreCase(pIgnoreCase: WordBool); safecall; function Get_Global: WordBool; safecall; procedure Set_Global(pGlobal: WordBool); safecall; function Execute(const sourceString: WideString): IDispatch; safecall; function Test(const sourceString: WideString): WordBool; safecall; function Replace(const sourceString: WideString; const replaceString: WideString): WideString; safecall; property Pattern: WideString read Get_Pattern write Set_Pattern; property IgnoreCase: WordBool read Get_IgnoreCase write Set_IgnoreCase; property Global: WordBool read Get_Global write Set_Global; end; CoVBScriptRegExp = class class function Create: IRegExp; end; class function CoVBScriptRegExp.Create: IRegExp; begin Result := CreateComObject(CLASS_RegExp) as IRegExp; end; procedure TForm1.Button2Click(Sender: TObject); var pythonEngine: TPythonEngine; delphiModule: TPythonModule; pyDelphiWrapper: TPyDelphiWrapper; Py : PPyObject; regExp: IRegExp; begin pythonEngine:= TPyThonEngine.Create(nil); delphiModule := TPythonModule.Create(nil); delphiModule.Name := 'DelphiModule'; delphiModule.Engine := pythonEngine; delphiModule.ModuleName := 'delphi'; pyDelphiWrapper := TPyDelphiWrapper.Create(nil); PyDelphiWrapper.Name := 'PyDelphiWrapper'; PyDelphiWrapper.Engine := pythonEngine; PyDelphiWrapper.Module := delphiModule; pythonEngine.LoadDll; regExp:= CoVBScriptRegExp.Create; regExp.Pattern:= 'i'; ShowMessage(regExp.Replace('This is a beautiful day', '##')); Py := pyDelphiWrapper.WrapInterface(TValue.From(regExp)); delphiModule.SetVar('regexp', Py); pythonEngine.Py_DecRef(Py); try pythonEngine.ExecString( 'from delphi import regexp' + sLineBreak + 'print(regexp.Replace("This is a beautiful day", "##"))'); { This raises the following error: AttributeError: Error in getting property "Replace". Error: Unknown attribute. } finally pyDelphiWrapper.Free; delphiModule.Free; pythonEngine.Free; end; end; Do you think it is possible to map the pointer on the interface to a corresponding object in python whose class would have been generated by importing a type library with ComTypes or to a Dispatch class of Win32Com? I'm sorry if I'm not using the right terms or if my question is a bit obscure but I know very little about python and even less about its API. Best regards, Pierre
  9. PierreC

    Marshalling COM Objects

    Hy pyscripter, Thank you so much. I will have a look at this. Pierre
×