HOWTO: passing an [in,out] char* from Managed C++ to Unmanaged C.

S

Sam Carleton

I am writing Managed C++ code to call in to an Unmanaged C API.
The reason for using Managed C++ over C# is that the Unmanaged C
module is loaded via LoadLibrary(). DllImport cannot be used;
functions pointers and GetProcAddress() is being used.

The API function definition looks like this:

int GetString( [out] char* pszOutStr, [in,out] int *nStrLen)

It looks like the prototyping of the function pointer is straight
forward:

typedef int (*FPGetString)( char* pszOutStr, int *nStrLen);

The question is how do I get a char* with a given length to pass
into this function. Mind you this IS an Ansi call, not Unicode!

Sam
 
S

Sam Carleton

I am writing Managed C++ code to call in to an Unmanaged C API.
The reason for using Managed C++ over C# is that the Unmanaged C
module is loaded via LoadLibrary(). DllImport cannot be used;
functions pointers and GetProcAddress() is being used.

The API function definition looks like this:

int GetString( [out] char* pszOutStr, [in,out] int *nStrLen)

It looks like the prototyping of the function pointer is straight
forward:

typedef int (*FPGetString)( char* pszOutStr, int *nStrLen);

The question is how do I get a char* with a given length to pass
into this function. Mind you this IS an Ansi call, not Unicode!

Sam

Ok, looks like an [out] is simple:

int nStrLen = x;
IntPtr ptrOut = Marshal::AllocHGlobal( nStrLen * sizeof(char));
GetString( (char*) ptrOut.ToPointer(), &nStrLen);
Marshal::FreeCoTaskMem(ptrOut);

This is working fine for me. The problem I am having now is the
[in, out]. There is another method that one of the three
parameters which is an in/out is the username. The size of the
username buffer must the full length possible for a username in
this app. The API call might prompt the user and the user might
change the username, so the new username is returned in the same
string that was passed in. Crasy, but that is what I have to work
with. Here is my best guess, which is blowing up when I call Free
the memory:

StringBuilder * outUser = new StringBuilder( user, USER_LEN+1);
IntPtr ptrUsername = Marshal::StringToHGlobalAnsi(outUser->ToString());
// I don't know if the pin is really needed, but it compiles
char __pin* pszUsername = (char*) ptrUsername.ToPointer();

login( pszUsername, ...);

String * strUser = Marshal::ptrToStringAnsi(ptrUsername);

Marshal::FreeCoTaskMem(ptrUsername);

To tell the truth, the username is freed without any problems, it
is the parameter after it, which is also a [in, out] char* that
blows chunks (unhandled exception) when calling
Marshal::FreeCoTaskMem().

Any thoughts?

Sam
 
W

Willy Denoyette [MVP]

AllocHGlobal should be paired with FreeHGlobal not FreeCoTaskMem!

Willy.

Sam Carleton said:
I am writing Managed C++ code to call in to an Unmanaged C API.
The reason for using Managed C++ over C# is that the Unmanaged C
module is loaded via LoadLibrary(). DllImport cannot be used;
functions pointers and GetProcAddress() is being used.

The API function definition looks like this:

int GetString( [out] char* pszOutStr, [in,out] int *nStrLen)

It looks like the prototyping of the function pointer is straight
forward:

typedef int (*FPGetString)( char* pszOutStr, int *nStrLen);

The question is how do I get a char* with a given length to pass
into this function. Mind you this IS an Ansi call, not Unicode!

Sam

Ok, looks like an [out] is simple:

int nStrLen = x;
IntPtr ptrOut = Marshal::AllocHGlobal( nStrLen * sizeof(char));
GetString( (char*) ptrOut.ToPointer(), &nStrLen);
Marshal::FreeCoTaskMem(ptrOut);

This is working fine for me. The problem I am having now is the
[in, out]. There is another method that one of the three
parameters which is an in/out is the username. The size of the
username buffer must the full length possible for a username in
this app. The API call might prompt the user and the user might
change the username, so the new username is returned in the same
string that was passed in. Crasy, but that is what I have to work
with. Here is my best guess, which is blowing up when I call Free
the memory:

StringBuilder * outUser = new StringBuilder( user, USER_LEN+1);
IntPtr ptrUsername = Marshal::StringToHGlobalAnsi(outUser->ToString());
// I don't know if the pin is really needed, but it compiles
char __pin* pszUsername = (char*) ptrUsername.ToPointer();

login( pszUsername, ...);

String * strUser = Marshal::ptrToStringAnsi(ptrUsername);

Marshal::FreeCoTaskMem(ptrUsername);

To tell the truth, the username is freed without any problems, it
is the parameter after it, which is also a [in, out] char* that
blows chunks (unhandled exception) when calling
Marshal::FreeCoTaskMem().

Any thoughts?

Sam
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top