Re: How to pass String BYREF to C function?
TP <[email protected]>
| Newsgroups | gmane.comp.python.ctypes |
|---|---|
| Message-ID | <[email protected]> |
On Wed, Aug 18, 2010 at 5:11 AM, Lynton Grice <[email protected]>wrote: > Hi Andrew, > > > > Thanks for the help on this, great stuff. > > > > If I run the code from a C client I will get “half the first string”.... > > > > If I print out the “exitResult” like you specified below: > > > > print ctypes.c_char_p(exitResult.value).value > > > > I get the following output in WingIDE > > > > helloö > > > > So it works but what are those funny characters at the end of the string? > It is not serious though, I am just curious... > > > > Do I need to change my C code to get rid of those funny characters? > > > > int executeUserExit(char *buffer, char **userExitResultBuffer){ > > int total_len; > > > > total_len = strlen(buffer) / 2; > > *userExitResultBuffer = (char*) malloc(total_len); > > strncpy(*userExitResultBuffer, buffer, total_len); > > return 0; > > } > > > > Thanks again > > > > Lynton > > > > *From:* [email protected] [mailto:[email protected]] *On > Behalf Of *Andrew Wilson > *Sent:* 18 August 2010 02:00 PM > *To:* Lynton Grice > *Cc:* [email protected]; [email protected] > > *Subject:* Re: [ctypes-users] How to pass String BYREF to C function? > > > > Lynton, > The following code is a hack; keep in mind that python strings are > immutable so your c_char_p variables can't be written to by the dll. > Instead you should be using "create_string_buffer" for writeable strings. I > wasn't so sure about the char** variable so I just made it an int pointer > and then cast it back to a string once the result were in. > > > import ctypes > import os > > if __name__ == "__main__": > if os.name=='nt': > userExit = ctypes.cdll.LoadLibrary("libUserExits.dll") > executeUserExit = userExit.executeUserExit > > stream = ctypes.create_string_buffer("hello world") > exitResult = ctypes.c_uint(0) > result = executeUserExit(stream, ctypes.byref(exitResult)) > print result, stream.value, ctypes.c_char_p(exitResult.value).value > print "Finished" > > > > > > > > > > > > > > > > > > > > > On Wed, Aug 18, 2010 at 4:24 AM, Lynton Grice < > [email protected]> wrote: > > Hi there, > > > > Thanks for the comments. Please note that this is just a test script so I > am not fussed about the “os.name”....I can take all that extra out > later....I just wanted to get it working for now. > > > > I tried out something like what you said but still no luck: > > > > import ctypes as c > > > > userExit = c.cdll.LoadLibrary("libUserExits.dll") > > executeUserExit = userExit.executeUserExit > > executeUserExit.argtypes = [c.c_char_p, c.POINTER(c.c_char_p)] > > executeUserExit.restype = c.c_int > > stream = (c.c_char * 20)(*list("hello world")) > > exitResult = c.c_char_p() > > result = executeUserExit(c.byref(stream), c.byref(exitResult)) > > print result > > print "Finished" > > > > > > I will keep trying with a couple options...thanks for the push in the right > direction though, much appreciated > > > > Lynton > > > > *From:* [email protected] [mailto:[email protected]] > *Sent:* 18 August 2010 09:46 AM > > > *To:* Lynton Grice > *Subject:* Re: [ctypes-users] How to pass String BYREF to C function? > > > > > > On Aug 17, 2010, at 8:08 PM, Lynton Grice wrote: > > > > Hi there, > > > > I have the following example C function that basically take 2 arguments and > “halves the first string” and puts that result in the second argument. > > > > int executeUserExit(char *buffer, char **userExitResultBuffer){ > > int total_len; > > > > total_len = strlen(buffer) / 2; > > *userExitResultBuffer = (char*) malloc(total_len); > > strncpy(*userExitResultBuffer, buffer, total_len); > > return 0; > > } > > > > I have call this from C code happily, but am having trouble from Python. > > > > I created a DLL from the code above > > > > import ctypes as c > > import os > > > > if __name__ == "__main__": > > if os.name=='nt': > > userExit = c.cdll.LoadLibrary("libUserExits.dll") > > executeUserExit = userExit.executeUserExit > > executeUserExit.argtypes = [c.c_char_p, c.c_char_p] > > executeUserExit.restype = c.c_int > > stream = c.c_char_p() > > stream.value = "hello world" > > exitResult = c.c_char_p() > > result = executeUserExit(c.pointer(stream), > c.byref(exitResult)) > > print result > > > > print "Finished" > > > > > > > > There is a lot wrong with this on a pure python-level. Please think of why > you use __name__ == "__main__" and os.name for a script you clearly don't > use somewhere else. > > > > But that's just a remark. > > > > The important thing here is that you have to create *arrays* of characters, > the same as with C. Then you can create pointers or byref references for > this. > > > > Something like this (untested): > > > > a = (c_char * 20)(*list("foobarbaz")) > > b = c_char_p() > > result = executeUserExit(byref(a), byref(b)) > > > > > > And of course the declaration of executeUserExit is wrong, you need > argtypes to be [c.c_char_p, POINTER(c.c_char_p)] > > > > Diez > > > > ------------------------------------------------------------------------------ > This SF.net email is sponsored by > > Make an app they can't live without > Enter the BlackBerry Developer Challenge > http://p.sf.net/sfu/RIM-dev2dev > _______________________________________________ > ctypes-users mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/ctypes-users > > > > > ------------------------------------------------------------------------------ > This SF.net email is sponsored by > > Make an app they can't live without > Enter the BlackBerry Developer Challenge > http://p.sf.net/sfu/RIM-dev2dev > _______________________________________________ > ctypes-users mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/ctypes-users > > Seems to me you have an "off by one" error? Looking at the documentation for strncpy at http://msdn.microsoft.com/en-us/library/xdsywd25%28v=VS.90%29.aspx it says: "The strncpy function copies the initial count characters of strSource to strDest and returns strDest. If count is less than or equal to the length of strSource, a null character is not appended automatically to the copied string. If count is greater than the length of strSource, the destination string is padded with null characters up to length count. The behavior of strncpy is undefined if the source and destination strings overlap." You malloc exactly the number of bytes you are copying instead of 1 extra. Thus you don't leave room for a trailing NULL byte like C strings need. Also you should use calloc I think to initialize the buffer to zeros? That way the last byte that isn't copied over will be still be the needed null byte. ------------------------------------------------------------------------------ This SF.net email is sponsored by Make an app they can't live without Enter the BlackBerry Developer Challenge http://p.sf.net/sfu/RIM-dev2dev _______________________________________________ ctypes-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ctypes-users