General Development

calling C function with pointer in C# – Calin

Calin

Member

Posts: 358
From: Moldova
Registered: 12-04-2006

Does any one know how to call a C function with a pointer as argument in C#?
[hopes for ssquared to chime in]. I posted on GameDev as well about this.
http://www.gamedev.net/community/forums/topic.asp?topic_id=441437

------------------
a good gameplay is a right combination between performance and features.

SSquared

Member

Posts: 654
From: Pacific Northwest
Registered: 03-22-2005
This example uses Platform Invoke. You will need to define the structure in C# and use an IntPtr to pass the struct as a pointer.

Here is a simple struct with two values and a C function to pass a pointer.


extern "C"
{
struct AddStruct
{
int one;
int two;
};

int APIENTRY STestCallAddPointer(AddStruct* values) {return values->one + values->two;};
}

You may need to define this in a DEF file like this:


STestCallAddPointer @1

Finally, the C# code. Here is where you need to define your struct and the functions you will use. These go inside of your C# class. They define the function to call, but 'extern' says this function is defined OUTSIDE of this class. In the example, the function is defined in a DLL called MFCDll.dll.

When laying out the struct, you need to use the C# equivalent data types for the C data type. The below example I used Int32 for C's int. If you need help with this, there are mapping tables which tell you what types to use. I can post a link if you are interested.


[StructLayout(LayoutKind.Sequential)]
public struct AddStruct
{
public Int32 one;
public Int32 two;
}

[DllImport("MFCDll.dll")]
public static extern int STestCallAddPointer(IntPtr values);

And finally...to call the function you need to create your struct, set the values, convert to a passable pointer, and then call the function with the pointer buffer.


// Testing pointer
AddStruct values;
values.one = 100;
values.two = 200;
int size = Marshal.SizeOf(values);
IntPtr buffer = Marshal.AllocCoTaskMem(size);
Marshal.StructureToPtr(values, buffer, false);
valueTest = STestCallAddPointer(buffer);
Marshal.FreeCoTaskMem(buffer);

The resulting value for valueTest is 300.

I do not know if it is possible to change some values from the C function and have C# get this updated value.

Hopefully this helps you. Let me know if you have any questions. And you just helped me add another test case to my research/study application. Thanks!

Calin

Member

Posts: 358
From: Moldova
Registered: 12-04-2006
Thanks for reply.

That's pretty much how I did it. I found something relevant on googlegroups. Following the examples there I came up with this way of declaring the C function in C# (which didn't work):


public static extern int ManyMouse_PollEvent([MarshalAs(UnmanagedType.LPStruct)] ManyMouseEvent MouseEvent);

Then I found the method you're using - a IntPtr argument - which finally worked.

Then you posted =]

I guess I have it figured out, however I'm having issues with the C function itself.

------------------
a good gameplay is a right combination between performance and features.

SSquared

Member

Posts: 654
From: Pacific Northwest
Registered: 03-22-2005
Glad to hear you got one part resolved! What's up with the C problem? Is it a function you wrote or from a 3rd party? Do you have the code?
Calin

Member

Posts: 358
From: Moldova
Registered: 12-04-2006
It's a weird issue. I must be missing something. It's a mouse library I've used in the past but can't seem to get working now. I took it here: http://icculus.org/manymouse/
It's made of 5 or 6 files (I have a copy of them here: http://calinnegru.googlepages.com/manymouse.rar ). To use the library just add the files to the project and include "manymouse.h" where you want to use it.

When you use the library you have to initialize it first with ManyMouse_Init(), the function should return at least 1 (if you have a mouse connected).

this is what I'm using as a test


#include <iostream>
#include "manymouse.h"

using namespace std;

int main ()
{

ManyMouseEvent MouseEv;

int result = ManyMouse_Init();

cout << "ManyMouse init result: " << result ;

int Enter;

cin >> Enter;

return 0;
}

For some reason I keep getting 0 from ManyMouse_Init() (which means it can't see a mouse). In another project the function works ok (the number of mouse devices returned is correct). It's probably some IDE settings, I don't know. I'll give it another try tomorrow. If you want to play with it and get it figured out let me know. I'm sure there's an obvious mistake somewhere.

------------------
a good gameplay is a right combination between performance and features.

SSquared

Member

Posts: 654
From: Pacific Northwest
Registered: 03-22-2005
Hmmm, that problem sounds like it's outside of the whole C#/C++ thing.

Are you running in Windows XP? I looked at some documentation and it stated the init call will return 0 if it's not running on XP. Not sure about Vista.

It's strange how it will work in one project and not in another. Maybe use the working project as a baseline for moving forward on the other project.

Calin

Member

Posts: 358
From: Moldova
Registered: 12-04-2006
I'm running XP.
I've even replaced the code in the working project so that it makes an exact match of the non-working project, I'm still getting different results though.

------------------
a good gameplay is a right combination between performance and features.

Calin

Member

Posts: 358
From: Moldova
Registered: 12-04-2006
There was a difference in character set. I got it working with Multi-Byte Character Set.

------------------
a good gameplay is a right combination between performance and features.

Calin

Member

Posts: 358
From: Moldova
Registered: 12-04-2006
I've got the NET wrapper working. If you'd like to use it I've put the binaries (DLLs) on this page:

http://calinnegru.googlepages.com/downloads

------------------
a good gameplay is a right combination between performance and features.