I'm trying to return structure so I can use it in Python. I am beginner programmer so please explain me what am I doing wrong. I've succeeded to return simple ctypes earlier (bool, unsigned int) but struct is too complicated for me. This is what I have:
DLLAPI.h
#define DLLAPI extern "C" __declspec(dllexport)
...
DLLAPI myStruct* DLLApiGetStruct();
DLLAPI.cpp
EDIT1: instead of TString, struct members type is wchar_t* now, but error I get is the same
...
typedef struct myStruct{
wchar_t* id;
wchar_t* content;
wchar_t* message;
} myStruct;
DLLAPI myStruct* DLLApiGetStruct(){
myStruct* test = new myStruct();
test->id = _T("some id");
test->content = _T("some content");
test->message = _T("some message");
return test;
}
here is my Python code:
...
class TestStruct(Structure):
_fields_ = [
("id", c_wchar_p),
("content", c_wchar_p),
("message", c_wchar_p)
]
class SomeClass(object):
....
def test(self):
myDLL = cdll.LoadLibrary('myDLL.dll')
myDLL.DLLApiGetStruct.restype = TestStruct
result = myDLL.DLLApiGetStruct()
print "result type: ", type(result)
print "-"*30
print "result: ",result
print "-"*30
print result.id # line 152
this is what I get:
result type: <class 'Foo.TestStruct'>
------------------------------
result: <Foo.TestStruct object at 0x027E1210>
------------------------------
Traceback (most recent call last):
....
....
....
line 152, in test
print result.id
ValueError: invalid string pointer 0x00000002
TString I've used is std::wstring
Should type in myStruct be pointers or something instead TString?
Please help me, I've spend 5 days trying to make this work.
As the others explained, the problem with version 1 of the question is the use of std::string which is not a valid type for interop.
Looking at version 2 of the question, your C++ and Python declarations do not match. The C++ code returns a pointer to the struct, but the Python code expects the struct to be returned by value.
You could change either C++ or Python to match the other.
C++
DLLAPI myStruct DLLApiGetStruct()
{
myStruct result;
result.id = L"some id";
result.content = L"some content";
result.message = L"some message";
return result;
}
Python
myDLL.DLLApiGetStruct.restype = POINTER(TestStruct)
Obviously you must apply only one of these changes!
Note that in the C++ code I chose to use explicit wide strings with the L prefix rather than the _T() macro. The former matches wchar_t* and the latter is what you use with TCHAR. I would not recommend TCHAR these days, unless you need to support Win98.
http://docs.python.org/3.1/library/ctypes.html
c_wchar_p contains wchar_t *, not std::wstring
The problem is you are returning a structure containing std::string's but you are telling Python that the types are pointers to wchar_t. This has the same effect as doing the following in C++.
struct Foo
{
std::string id;
std::string content;
std::string message;
};
struct Bar
{
wchar_t* id;
wchar_t* content;
wchar_t* message;
};
Foo f;
Bar* = reinterpret_cast<Bar*>(&f);
Related
Sorry if this is a really dumb question but here goes.
I recently got into C++ and I have to modify a driver for a project I am working on. The problem is that my driver needs to take a string I'm storing in a void*. So basically, my question is, how can I cast this, or do this, in a very simple way?
void get_modulebase(int pid, void* value, void* data) {
PEPROCESS t_process;
UNICODE_STRING mod;
KAPC_STATE apc;
DbgPrint("Data: %s \n", data); //this prints the string as i need it
RtlInitUnicodeString(&mod, (PCWSTR)data); //this fails
PsLookupProcessByProcessId((HANDLE)pid, &t_process);
PVOID base_address = BBGetUserModule(t_process, &mod);
KeUnstackDetachProcess(&apc);
RtlCopyMemory(value, &base_address, 8);
ObfDereferenceObject(t_process);
}
This works for me, but I need to store the module name into data:
RtlInitUnicodeString(&mod, L"notepad.exe");
RtlInitUnicodeString is one of the few unsafe string calls left that Windows does not flag.
Refer: char* ( char pointer) and RtlInitUnicodeString() function
I suggest that you can use RTL_CONSTANT_STRING macro in wdk which can be used to create UNICODE_STRING in compile time.
Like this:
static const UNICODE_STRING foo = RTL_CONSTANT_STRING(L"notepad.exe");
I am writing analyser for natural language and I have a wrapper of c++ code in python 3 created with swig. I'd like to use a function which is some kind of stream writer and it takes std::ostream & os as the parameter. So I guess it would work if I somehow import ostringstream(read as which lib.so I should use in my ctypes.CDLL) in my python code then pass it to this function, lest call it create_stream_writer(stream), and then use stream.str() to get string. Is it any way to do this using ctypes or any other library?
I am using docker container running Ubuntu 18.04, python3.6
code should look like this I guess:
def analyse(text, config):
reader = PlainTextReader.create_string_reader(text, config)
stream = ctypes.ostringstream() # some magic hear
writer = TokenWriter.create_stream_writer('plain', stream, reader.tagset())
for sentence in sentences(reader):
writer.write_sentence(sentence)
return stream.str()
You can do this (and make it nice for Python developers too). This answer is essentially a Python 3 version of my older answer on wrapping iostreams.
To simplify things here I used boost's iostreams library. If you can't/don't use boost then you can write this all from standard C++ library components, it's just far more verbose.
I've also aimed higher than mapping io.StringIO to std::stringstream and instead gone for mapping any 'file like' Python object to any iostream. That is to say we use aim to use duck typing on the Python object to just call read() and write() sensibly as and when needed for our C++ stream objects.
%module test
%{
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/categories.hpp>
// This is just a helper that we can use with boost iostreams to proxy everything to a Python object
struct python_stream_device {
typedef char char_type;
typedef boost::iostreams::bidirectional_device_tag category;
std::streamsize read(char* s, std::streamsize n) {
PyObject *p = PyObject_CallMethod(o, "read", "l", static_cast<long int>(n));
if (PyErr_Occurred()) {
// TODO: throw a C++ exception to back out of wherever we are and then re-throw the Python one...
assert(false);
}
assert(p);
char *ptr = nullptr;
Py_ssize_t len = 0;
PyObject *str = PyUnicode_AsUTF8String(p);
PyBytes_AsStringAndSize(str, &ptr, &len);
if (PyErr_Occurred()) {
assert(false); // Let's just pretend this is error handlng...
}
memcpy(s, ptr, len);
Py_DECREF(str);
Py_DECREF(p);
return len;
}
std::streamsize write(const char* s, std::streamsize n) {
PyObject *ret = PyObject_CallMethod(o, "write", "s#", s, static_cast<Py_ssize_t>(n));
if (PyErr_Occurred()) {
// See above
assert(false);
}
std::streamsize r = PyLong_AsSsize_t(ret);
Py_DECREF(ret);
return r;
}
// Using this means we can rely on the default synthesised operator= + copy ctor etc. and saves us some code.
swig::SwigPtr_PyObject o;
python_stream_device(PyObject *o) : o(o) {}
};
typedef boost::iostreams::stream<python_stream_device> python_stream;
%}
// Here is the stuff that wraps it neatly
%typemap(in) std::iostream& (python_stream tmp) {
// Writing the typemap this way lets us get RAII semantics despite the goto in the SWIG macros in the simplest way
tmp.open(python_stream_device($input));
$1 = &tmp;
}
// We can just use the same typemaps for other cases too:
%apply std::iostream& { std::istream&, std::ostream& };
// Below is just for testing:
%{
#include <iostream>
%}
%inline %{
// This is the function you want to call
void fun1(std::ostream& out) {
assert(out.good());
out << "Hello world, from C++";
assert(out.good());
}
// This one is here for completeness because once you've got this far you may as well support this too.
void fun2(std::istream& in) {
std::string tmp;
//in >> tmp;
std::getline(in, tmp);
assert(in.good());
std::cout << "fun2 got: " << tmp << std::endl;
}
%}
This is enough that you can then use some Python like this:
import io
import test
i=io.StringIO()
test.fun1(i)
print('After fun1: %s' % i.getvalue())
i=io.StringIO('hello world, from Python!\n')
test.fun2(i)
As Mark Tolonen pointed in comments it is impossible to do this with ctypes. So I just wrote c++ function that do everything I need, and then created a wrapper using SWIG. Because using typemap in SWIG to map StringIO(Python) to ostreingstream(C++) looks like black magic and I couldn't find the way to do this.
I am attempting to pass a string from python to a c++ library. However, I have been crashing with variations of segfaults std::bad_alloc, and invalid type messages while I have been attempting to do so. Here is the code that I am attempting to use in c++:
#define DLLEXPORT extern "C"
DLLEXPORT std::string returnAString()
{
std::string ret = "Returning string from lib";
return ret;
}
DLLEXPORT char* returnACharArray()
{
return "Returning char* from lib";
}
DLLEXPORT void passInAString(std::string incomingString)
{
printf("Recieved message in passInAString\n");
printf("Recieved incoming message: %s", incomingString);
}
DLLEXPORT void passInACharArray(char* incomingString)
{
printf("Recieved message in passInACharArray\n");
printf("Recieved incoming message: %s", incomingString);
}
Realistically, with what I am doing I can work with either the char* or the std::string once it gets in my c++ code, and I don't really have a preference either way. Here is what I am doing in python:
from ctypes import *
import os
libPath = os.path.join(os.getcwd(), "mylib.so")
lib = cdll.LoadLibrary(libPath)
string = "hello from python"
lib.passInAString(string)
#lib.passInACharArray(string)
#ret = lib.returnAString()
#print("recieved string: " + string)
#ret = lib.returnACharArray()
#print("recieved char*: " + string)
here, I will uncomment whichever line I am attempting to test. When passing in a string, I will get my first printf statement, I will get std::bad_alloc. When I pass in a char*, I get a segfault. When I attempt to receive a message, I get back a number (I am assuming that this is the pointer), but I am unable to decode this message into an actual string message.
I have attempted to use c_char_p to convert my python string into a char* to pass to my library, but when I do that I get "invalid type". Trying to convert the returned message by doing c_char_p(lib.returnACharArray) and then print(str(string.value)) then gives me the hex value of 4 bytes... which is not what I am returning.
What am I missing to make this functionality work?
Your DLL has the wrong argument types.
Since you're passing a string from Python the function should take a char*. You can convert this to a std::string within the function if you want to.
There's a table in the Python docs showing the corresponding types in both C and Python here: https://docs.python.org/3.6/library/ctypes.html#fundamental-data-types
Edit: Just realized the string types differ for Python 3 meaning the function needs to be declared differently.
e.g.
// Python2, or Python3 passing bytes
DLLEXPORT void passInAString(char* incomingString)
{
printf("Received message in passInAString\n");
printf("Received incoming message: %s", incomingString);
std::string myStr = incomingString;
// and do stuff with myStr if needed
printf("Incoming message as std::string is %s", myStr.c_str());
}
// Python3 passing strings
DLLEXPORT void passStringPy3(wchar_t* wideString)
{
printf("Message >>%ls<<\n", wideString);
}
I am looking to convert a [32]C.wchar_t to a go string.
The array is defined as follows in the dll I am talking to:
typedef struct myStruct {
WCHAR someString[32];
}
I am defining the struct in go as follows:
type myStruct struct {
someString [32]C.wchar_t
}
I have a method in the dll:
DLLINTERFACE HRESULT __stdcall GetMyStruct (myStruct* ptrMyStruct);
This method will populate the someString field of myStruct.
I am calling the method like so (this is working correctly, I think, I have not been able to see the contents of someString):
func getMyStruct() (*myStruct, uintptr) {
var getMyStruct = dll.MustFindProc("GetMyStruct")
var args = new(myStruct)
ret, _, _ := getMyStruct .Call(uintptr(unsafe.Pointer(args)))
fmt.Printf("Return: %d\n", (int)(ret))
return args, ret
}
I need to convert someString to a go string. I have tried using "github.com/GeertJohan/cgo.wchar", but it does not have a method for converting []C.whar_t to go string.
Currently I'm not sure if my go struct is correct. I'm also not sure if I am initializing myStruct correctly before sending it to the dll.
Any help will be greatly appreciated.
On Windows, wchar_t is normally UTF-16 (little-endian). They don't normally start with a BOM (which is present so a decoder can detect if they are stored in big or little endian form).
There is a utf16 package but this only translates individual runes. However, there is an additional unicode text encoding package that can help.
You would probably do something like this:
dec:=unicode.UTF16(unicode.LittleEndian,unicode.UseBOM).NewDecoder()
out,err:= dec.Bytes(([]byte)(unsafe.Pointer(args.someString)))
if err!=nil {
//handle error
}
// Strings are null terminated, only want content up to null byte
i:=bytes.IndexByte(out,0)
if i==-1 {
i = len(out)
}
s:=string(out[:i])
However, I'd be tempted to declare someString as [64]byte which is the amount of bytes that a 32 character (16 bites = 2 bytes per character) would need. This would avoid the unsafe typecasting but otherwise should work as above.
I'm doing this off the top of my head so the code above is meant as an example & may not necessarily work - use at your peril :-)
It seems GeertJohan's library hasn't been updated for the more recent cgo changes, but a fork has, try github.com/vitaminwater/cgo.wchar (godoc) instead.
If the C function writes to a C type, pass a variable of the C type.
A (dodgy) example:
package main
/*
#include <wchar.h>
#include <string.h>
typedef struct myStruct {
wchar_t someString[32];
} myStruct;
wchar_t sample[6] = {0x0048, 0x0069, 0x0020, 0x4e16, 0x754c, 0};
void writeSample(myStruct *m) {
memcpy(m->someString, &sample, sizeof(wchar_t) * 6);
}
*/
import "C"
import (
"fmt"
"log"
"unsafe"
"github.com/vitaminwater/cgo.wchar"
)
func main() {
m := C.myStruct{}
C.writeSample(&m)
s, err := wchar.WcharStringPtrToGoString(unsafe.Pointer(&m.someString))
if err != nil {
log.Fatal(err)
}
fmt.Println(s)
}
This outputs:
Hi 世界
Let me start off by saying that VB is not my strong suit.
I am developing a C++ dll to be used in a VB6 application's dll.
I have successfully instantiated the (C++) classes in VB. I am trying to access data members of the class using this syntax: "vbCppObj.dataMemberName".
I can confirm that this works for boolean and enum types and it invokes the getter methods defined in my class.
I have to access a string from the (C++) class as well.
The getter function for the string is given below:
class MyCPPClass
{
private:
WCHAR* CPPErrorString = L"This is a string";
public:
HRESULT __stdcall get_CPPErrorString(BSTR* pVal)
{
BSTR str = ::SysAllocString(CPPErrorString);
if(str)
*pVal = str;
return S_OK;
}
};
I am unable to debug the C++ dll right now.
I access this value in the VB6 code as follows:
ErrorString = vbCppObj.CPPErrorString
Logger.log "[Log]:" & ErrorString
"ErrorString" is a String type in VB. When this line executes, the "ErrorString" object shows "<Out of memory>" (when I hover over it). If I step further, to the logging code, it gives me a "Error 14: Out of string space".
Also, I have typed this code in the browser so, it may not be 100% correct.
As it turns out, I had to convert the string into a "_b_str" and then to a "BSTR". That worked for me.
I had tried it earlier but I don't know why it didn't work at that time.
Why you just don't use LPCTSTR?
I'm not an advanced C/C++ programmer, but this should work
class MyCPPClass
{
private:
LPCTSTR CPPErrorString = "This is a string";
public:
HRESULT __stdcall get_CPPErrorString(LPCTSTR * pVal)
{
// copy the value
*pVal = CPPErrorString;
// return
return S_OK;
}
}