Question

I am currently writing a Python module using python4delphi. I would like to use the standard C API Function PyArg_ParseTupleAndKeywords.

As you can see from the documentation the signature is so:

int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format,
    char *keywords[], ...)

Now this function is not wrapped in python4delphi so I've added it by myself:

PyArg_ParseTupleAndKeywords: function (args, kw: PPyObject; format: PAnsiChar; 
    keywords: array of PAnsiChar {;...}): Integer; cdecl varargs;
....
PyArg_ParseTupleAndKeywords := Import('PyArg_ParseTupleAndKeywords');

The problem I have is that I am getting an access violation error when I try to use it in way similar to this snippet:

function PyScript_MyFunction(pself, args, keywds : PPyObject) : PPyObject; cdecl;
var
  AAA, BBB : PChar;
  kwlist : array[0..2] of PAnsiChar;
begin
  kwlist[0] := 'AAA';
  kwlist[1] := 'BBB';
  kwlist[2] := nil;

  BBB := 'BBB';
  with GetPythonEngine do
  begin
    if (PyErr_Occurred() = nil) and (PyArg_ParseTupleAndKeywords(args, keywds,
        's|s:Script_MyFunction', kwlist, @AAA, @BBB) <> 0) then
    begin
      Result := VariantAsPyObject(MyFunction(AAA, BBB));
    end
    else
      Result := nil;
  end;
end;

//Module is my Python module I am working with

Module.AddMethodWithKeywords('Wrapped', @PyScript_MyFunction, 'no doc');

How can I fix this? Is there a way to debug such kind of errors?

Était-ce utile?

La solution

Your translation of the keywords parameter is incorrect. You've used a Delphi open array. A Delphi open array results in two things being passed, the index of the final item in the array, and the pointer to the first element of the array. Delphi open arrays are simply never to be used for interop.

You need to declare that parameter like so:

keywords: PPAnsiChar

That is a pointer to PAnsiChar.

Call the function like this:

PyArg_ParseTupleAndKeywords(..., @kwlist[0], ...) 

Personally I would use a dynamic array to prepare your parameter:

var
  kwlist: TArray<PAnsiChar>;

Initialise it like this:

kwlist := TArray<PAnsiChar>.Create('AAA', 'BBB', nil);

And pass it like this:

PPAnsiChar(kwlist)

or like this if you prefer:

@kwlist[0]

The latter is typesafe at least.


I note that you declared AAA and BBB to be of type PChar. Surely that should be PAnsiChar.


I'm far from sure that you've prepared all the other parameters correctly. I'm not familiar with this particular API call. For sure though, what I describe above is the first and most important problem to tackle.

I do wonder how you the caller are expected to deallocate the strings that are returned to you? I presume that you are expected to do that.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top