2

I hav a function in c++ DLL that has following prototype

int function(RefPar &params);

how can i call this function from a c# program using "DLLImport".

when i tried like below, AccessViolationException happened while running in visual studio 2008..

[DllImport("VistaGMMDLL.dll", EntryPoint = "function"]
unsafe static extern int function(ref RefPar params);

and called as..

int ret=function(ref params);

Note:RefPar structure has many unsigned integer values and 1 enum value as its members.

pls anyone help me to call the function correctly..

Stecya
  • 22,896
  • 10
  • 72
  • 102
Jamkan
  • 59
  • 6
  • I have very little experience with marshalling to native code, but you may need to pass it as an `IntPtr`. You also are going to have to be very careful with how you define your structure in both C# and C++, since the structure layout/packing is completely different between the languages. – Merlyn Morgan-Graham Mar 23 '11 at 08:22
  • I am using [StructLayout(LayoutKind.Sequential)] for layout packing. – Jamkan Mar 23 '11 at 10:32
  • I think you may need to use some special keywords in C++ also to ensure (portably) a specific object layout. – Merlyn Morgan-Graham Mar 23 '11 at 10:43

3 Answers3

0

Try in this way:

[StructLayout(LayoutKind.Sequential)]
public struct RefPar
{
    UInt32 uint1;
    UInt32 unti2;
    ....
} 


[DllImport("VistaGMMDLL.dll", EntryPoint = "function"]
unsafe static extern int function(IntPtr params);

//calling

//fill the refParStructure
//create the IntPtr  

refParStruct rs = new RefPar();

IntPtr refparPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(refPar)));


Marshal.StructureToPtr(refParStruct, refparPtr,false);
ret=function(refParPtr);

Let Me know if you need more details

Kevin
  • 552
  • 2
  • 8
  • 17
  • Hi.. thanks for the reply.. I am new to c#.. i Did wat u said.Created an IntPtr in this way. IntPtr refptr=new IntPtr(); Marshal.StructureToPtr(refparstruct,refptr, true); ArgumentNullException is coming for refptr, pls tell do i have to initialize IntPtr differently?? – Jamkan Mar 24 '11 at 04:07
  • Hello, you have to allocate the pointer using refptr=Marshal.AllocHGlobal(Marshal.SizeOf(size)); – Kevin Mar 24 '11 at 08:43
0

A couple of things jump out at me. First of all I don't see why you need to use unsafe. Secondly, you probably have a calling convention mismatch, cdecl in the C++ and stdcall in the C#.

I'd do it like this:

C++

struct RESOURCE_PARAMETERS{
    unsigned int uSurfaceHeight;
    unsigned int uSurfaceDepth;
    unsigned int uSurfaceWidth;
    unsigned int uMSAAHeight;
    unsigned int uMSAAWidth;
    unsigned int uArraySize;
    unsigned int uNumSamples;
    unsigned int uMaxLod;
    unsigned int uBpp;
    unsigned int uprefFlag;
    unsigned int uusageFlag;
    RESOURCE_TYPE_REC ResourceType;
    int ResourceFormat;
    int iBuildNumber;
};

int function(RefPar &parameters)
{
}

C#

[StructLayout(LayoutKind.Sequential)]
public struct RESOURCE_PARAMETERS
{
    uint uSurfaceHeight;
    uint uSurfaceDepth;
    uint uSurfaceWidth;
    uint uMSAAHeight;
    uint uMSAAWidth;
    uint uArraySize;
    uint uNumSamples;
    uint uMaxLod;
    uint uBpp;
    uint uprefFlag;
    uint uusageFlag;
    [MarshalAs(UnmanagedType.U4)]
    ResourceType ResourceType;
    int ResourceFormat;
    int iBuildNumber;
} 

[DllImport("VistaGMMDLL.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int function(ref RESOURCE_PARAMETERS parameters);

RESOURCE_PARAMETERS parameters = new RESOURCE_PARAMETERS();
int result = function(ref parameters);

I'm not sure how big the enum is on the C++ size. That's why I've put an explicit MarshalAs in the C# code. If it's just a single byte, then use UnmanagedType.U1 instead. I trust you get the idea.

If your C++ function treats its parameter as an in/out parameter then using ref on the C# side is correct. If its actually an out parameter then change the code to be like this:

[DllImport("VistaGMMDLL.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int function(out RESOURCE_PARAMETERS parameters);

RESOURCE_PARAMETERS parameters;
int result = function(out parameters);
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Hi .. I added the Calling convention.Cdecl. My structure is in C++ DLL, struct RESOURCE_PARAMETERS{ unsigned int uSurfaceHeight; unsigned int uSurfaceDepth; unsigned int uSurfaceWidth; unsigned int uMSAAHeight; unsigned int uMSAAWidth; unsigned int uArraySize; unsigned int uNumSamples; unsigned int uMaxLod; unsigned int uBpp; unsigned int uprefFlag; unsigned int uusageFlag; RESOURCE_TYPE_REC ResourceType; int ResourceFormat; int iBuildNumber; } where RESOURCE_TYPE_REC is anEnum – Jamkan Mar 24 '11 at 04:23
  • in c# the structure is In c# [StructLayout(LayoutKind.Sequential)]struct ResourceParameters {public UInt32 uSurfaceHeight; public UInt32 uSurfaceDepth; public UInt32 uSurfaceWidth; public UInt32 uMSAAHeight; public UInt32 uMSAAWidth; public UInt32 uArraySize; public UInt32 uNumSamples; public UInt32 uMaxLod; public UInt32 uBpp; public UInt32 uprefFlag; public UInt32 uusageFlag; public ResourceTypeRec ResourceType; public Int32 ResourceFormat; public Int32 iBuildNumber; } in this also ResourceTypeRec is an enum – Jamkan Mar 24 '11 at 04:25
  • shall i give the enum structure too?? – Jamkan Mar 24 '11 at 04:26
-1

Another very simple way to call this function is:

Create a c++ dll warapper that link your original dll and contains this function

//c++ code

function2(uint param1, uint param2.....)
{
  RefPar refpar;

  refpar.param1=param1

  refpar.param2=param2

  function(&refpar)

}



in this way you have just to import (in C#) the dll wrapper function in this way


[DllImport("wrapperdll.dll", EntryPoint = "function2"]
static extern int function2(Uint32 param1,Uint32 param2....);


that is very simple to call.


Regards
Kevin
  • 552
  • 2
  • 8
  • 17