Pass char* to C# callback function

S

SB

What is the proper way to pass a character array (char *) from a "C" dll to
a C# method (delegate) in my app? Getting the dll (which simulates a third
party dll) to call my delegate works fine. However, as soon as I try to add
any "char *" parameters, I start getting exceptions in my C# app.

So far I've tried (among others):
public delegate int Test(char[] version);
and
public delegate int Test(string version); // won't work because string is a
managed type I suppose


I've read many articles on sending data from C# to a C dll...but not much is
written about going the other way around. In short, I'm basically sending
the C dll a callback address...and the C dll is supposed to fire the
callback and pass back a char array....then my app needs to convert it to a
string to work with.

TIA!
sb
 
N

Nurchi BECHED

"public delegate int Test(char[] version);"
doesn't work because char[] is managed as well!!!

Now, this might not be the best solution (it most probably isn't)!

How about open project properties and allow unsafe blocks,
and then do what you need in unsafe block with pointers:
<code>
unsafe
{
public delegate int Test(char* version);
//something else...
}
</code>

What is the proper way to pass a character array (char *) from a "C" dll
to
a C# method (delegate) in my app? Getting the dll (which simulates a
third
party dll) to call my delegate works fine. However, as soon as I try to
add
any "char *" parameters, I start getting exceptions in my C# app.

So far I've tried (among others):
public delegate int Test(char[] version);
and
public delegate int Test(string version); // won't work because string
is a
managed type I suppose


I've read many articles on sending data from C# to a C dll...but not
much is
written about going the other way around. In short, I'm basically
sending
the C dll a callback address...and the C dll is supposed to fire the
callback and pass back a char array....then my app needs to convert it
to a
string to work with.

TIA!
sb



--
Regards,
Nurchi BECHED

P.S.
C makes it easy to shoot yourself in the foot;
C++ makes it harder, but when you do,
it blows away your whole leg."
--Bjarne Stroustrup
 
S

SB

Isn't it something that as soon as you hit Post, you have a new idea?

I think I'm a bit closer now. The code below works...sort of. I can access
the char array from my C# method now...however I don't seem to be getting
the right return value inside the C dll. I am also getting this exception:
"Attempted to read or write protected memory. This is often an indication
that other memory has been corrupted."...so something is still wrong. I've
checked the calling convention for the dll and it looks like it's set to
__cdecl (/Gd compiler switch)...which matches my DllImport (see below).
[DllImport("mytest.dll", EntryPoint = "MyEvent", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void MyEvent(ref MyEventData _ data);

....

public delegate int TestDelegate(IntPtr buffer);

....

public int Test(IntPtr buffer)
{
string s = Marshal.PtrToStringAnsi(buffer);
System.Windows.Forms.MessageBox.Show(s);
return 55; // this is just a test return value
}

The C dll (test dll) code looks like this:

extern "C" __declspec(dllexport) void MyEvent(MyEventData *data)
{
int i = data->Test("one");
...
}

TIA,
SB
 
S

SB

See my notes inline:

Nurchi BECHED said:
"public delegate int Test(char[] version);"
doesn't work because char[] is managed as well!!!

Yep..I knew that too...I guess I was just hoping the compiler would take
care of marshalling it properly. See my other post which has an updated
approach which I believe it heading in the right direction.
Now, this might not be the best solution (it most probably isn't)!

How about open project properties and allow unsafe blocks,
and then do what you need in unsafe block with pointers:
<code>
unsafe
{
public delegate int Test(char* version);
//something else...
}
</code>


I thought about using an unsafe block yesterday...but I'm convinced that
it's not necessary. I think I'm just doing something wrong. In addition,
the number of call backs in this dll is really about 60...that's a lot of
"unsafe" code blocks that would have to be written!

sb
 
S

SB

After a few more hours, I have narrowed the problem quite a bit. Inside the
C dll, if I try to access the callback directly through a reference that is
passed in, it works great. However, if I place a reference to the callback
inside a struct and pass that struct in by ref, I get exceptions...and the
return values are incorrect (stack issue?).

**** The "C" dll code ****
typedef int (CALLBACK *CallbackFunction)(char *version);
....
extern "C" __declspec(dllexport) void MyDllFunction(EventDataStruct *data,
char* buffer, CallbackFunction callbackfn)
{
int res = (*callbackfn)(buffer); // this line works great...no
problems
// int res = (data->MyCallbackFunction) (buffer); // this line
throws an exception every time...even though the debugger shows that this
points to the same address as the above line
...
}
********


**** C# CODE ****
[DllImport("mybot.dll")]
public static extern void MyDllFunction(ref EventDataStruct data, string
value, MyCallbackFunction callbackFn);
....
public delegate int MyCallbackFunction (string buffer);
....
private void testButton_Click(object sender, EventArgs e)
{
MyClass mc = new MyClass(); // class creates delegate of
MyCallbackFunction in constructor...to be used to pass in reference to dll
// the above class' constructor creates an instance of
MyCallbackFunction delegate...ie m_MyData.TestCallback= new
MyCallbackFunction (TestCallback);
MyDllFunction(ref mc.m_MyData, "abc", mc.m_MyData.TestCallback);
}
....
// ---- Callback code -----
public static int TestCallback(string buffer)
{
System.Windows.Forms.MessageBox.Show(buffer);
return 89;
}
********

I don't get it. The only difference between them is that one is a direct
reference that is passed in, and the second is passed in through a struct.

....not sure where to go from here...need sleep :) Hopefully I transcribed
everything write above.

sb
 
M

Morten Nielsen

Usually I just use a string type for passing char *. C doesn't have strings
but use character-arrays instead (don't we just love C#? ;-).
This has always woked fine in my case.

Otherwise, try the .interop newsgroup.

/Morten
 
S

SB

Unfortunately, I cannot change the C dll at all....many users use the dll in
other applications. As I mentioned, the functions are compiled with the /GD
switch...which (unless I'm wrong), means that if unspecified, the calling
convention will be __cdecl.

:(
sb

Manu said:
Try this:

typedef int (__stdcall *CallbackFunction)(char*);

SB said:
After a few more hours, I have narrowed the problem quite a bit. Inside
the C dll, if I try to access the callback directly through a reference
that is passed in, it works great. However, if I place a reference to
the callback inside a struct and pass that struct in by ref, I get
exceptions...and the return values are incorrect (stack issue?).

**** The "C" dll code ****
typedef int (CALLBACK *CallbackFunction)(char *version);
...
extern "C" __declspec(dllexport) void MyDllFunction(EventDataStruct
*data, char* buffer, CallbackFunction callbackfn)
{
int res = (*callbackfn)(buffer); // this line works great...no
problems
// int res = (data->MyCallbackFunction) (buffer); // this line
throws an exception every time...even though the debugger shows that this
points to the same address as the above line
...
}
********


**** C# CODE ****
[DllImport("mybot.dll")]
public static extern void MyDllFunction(ref EventDataStruct data, string
value, MyCallbackFunction callbackFn);
...
public delegate int MyCallbackFunction (string buffer);
...
private void testButton_Click(object sender, EventArgs e)
{
MyClass mc = new MyClass(); // class creates delegate of
MyCallbackFunction in constructor...to be used to pass in reference to
dll
// the above class' constructor creates an instance of
MyCallbackFunction delegate...ie m_MyData.TestCallback= new
MyCallbackFunction (TestCallback);
MyDllFunction(ref mc.m_MyData, "abc", mc.m_MyData.TestCallback);
}
...
// ---- Callback code -----
public static int TestCallback(string buffer)
{
System.Windows.Forms.MessageBox.Show(buffer);
return 89;
}
********

I don't get it. The only difference between them is that one is a direct
reference that is passed in, and the second is passed in through a
struct.

...not sure where to go from here...need sleep :) Hopefully I
transcribed everything write above.

sb
 
Joined
Jan 3, 2008
Messages
1
Reaction score
0
Similar Problem

Hi,

I have a similar problem, i created a wrapper for a third party DLL, and one of the functions is:

6.1.5.4 GetUsbDevicesNameEnum
PROTOTYPE
I C_MORPHO_Device::GetUsbDevicesNameEnum (
UL i_ul_Index,
PC & o_pc_MsoName,
PC & o_pc_MsoProperties);

DESCRIPTION
InitUsbDevicesNameEnum must be call before using this function.
This function returns a string containing the name of the MSO.

PARAMETERS
i_ul_Index: This index is between 0 and the number of connected device returned by the function InitUsbDevicesNameEnum.
o_pc_MsoName: A string containing the name of the MSO (product number-serial number).
o_pc_MsoProperties: A string containing the type of the MSO (MSO100, MSO300...) and other information.

RETURN VALUE
MORPHO_OK
The execution of the function was successful.
MORPHOERR_BADPARAMETER
The index is unknown.

now, in my wrapper, i created this function as:

int GetUsbDevicesNameEnum(unsigned long ulIndex, char* &pcMsoName, char* &pcMsoProperties);

from my C# application, i accessed this function like this:

unsafe
{
uint UsbDevices;

sbyte[] szTempName = new sbyte[255];
sbyte[] szTempType = new sbyte[255];


//enumerate the number of connected Morpho USB Devices
nReturn = dllMorphoBridge.InitUsbDevicesNameEnum(&UsbDevices);

if (nReturn == 0 && UsbDevices > 0)
{
for (int i = 0; i < UsbDevices; i++)
{
fixed (sbyte* MsoName = szTempName)
{
fixed (sbyte* MsoType = szTempType)
{
//returns the name of the USB Device
dllMorphoBridge.GetUsbDevicesNameEnum(0, &MsoName, &MsoType);


when i build my code, i get the error: "Cannot take the address of a read-only local variable."

can somebody help me regarding this?

I really, really need help.

Thanks!

Heaven help me,

Marj
 

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