need help for invoking unmanaged functions

P

philipqiu

hi

I want to call unmanaged functions that are implemented in a dll. The
problem is about the method return values. for example

#include "stdafx.h"

typedef struct toOut
{
int (WINAPI* ONE)(int x, int y);
char (WINAPI* TWO)(char a);
}myToOut;

myToOut x;

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}

int WINAPI sum(int x, int y)
{
return x+y;
}

char WINAPI tochar(char a)
{
char x = a;
return x;
}

myToOut* WINAPI GetOut()
{
x.ONE = sum;
x.TWO = tochar;
MessageBox(NULL, "Ok", "", MB_OK);
return &x;
}

The preceding example return a struct,and the struct contains two point .the
question is how to set the marshaling of the GETOUT method value.

Thanks

philip
 
N

Nicholas Paldino [.NET/C# MVP]

It's not even worth it to do this, because the C++ code is wrong. Once
the call to GetOut ends, the instance on the stack is no longer valid.

If it was returning a valid memory pointer, then you would declare the
return value as IntPtr, and then use the static PtrToStructure method on the
Marshal class to get a managed representation of the structure.

You would also have to take that same pointer and pass it to whatever
function allocated the memory in the call to GetOut. However, as I
mentioned previously, the current implementation of GetOut is incorrect, in
that it returns a value from the stack which is no longer valid. You have
to fix that first.
 
W

Willy Denoyette [MVP]

philipqiu said:
hi

I want to call unmanaged functions that are implemented in a dll. The
problem is about the method return values. for example

#include "stdafx.h"

typedef struct toOut
{
int (WINAPI* ONE)(int x, int y);
char (WINAPI* TWO)(char a);
}myToOut;

myToOut x;

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}

int WINAPI sum(int x, int y)
{
return x+y;
}

char WINAPI tochar(char a)
{
char x = a;
return x;
}

myToOut* WINAPI GetOut()
{
x.ONE = sum;
x.TWO = tochar;
MessageBox(NULL, "Ok", "", MB_OK);
return &x;
}

The preceding example return a struct,and the struct contains two point
.the question is how to set the marshaling of the GETOUT method value.

Thanks

philip


You need to return the pointer as an IntPtr that you can use to marshal the
structure.
The function pointers elements in the structure must be marshaled to a
delegate with appropriate signature before you can call these functions.
Also make sure that the public function is declared with C linkage.
Here is a small sample illustrating the process.

// C#
struct MyOutStruct
{
public IntPtr sum;
public IntPtr tochar;
}
class Program
{
[DllImport("retstruct"), SuppressUnmanagedCodeSecurity]
public static extern IntPtr GetOut();
delegate int Sum(int x, int y);
delegate char ToChar(char b);
static void Main()

{
IntPtr myStruct = GetOut();
MyOutStruct outStruct = (MyOutStruct)Marshal.PtrToStructure(myStruct,
typeof(MyOutStruct));
if(myStruct != IntPtr.Zero)
{
Sum Add = (Sum) Marshal.GetDelegateForFunctionPointer(outStruct.sum,
typeof(Sum));
ToChar ToChar = (ToChar)
Marshal.GetDelegateForFunctionPointer(outStruct.tochar, typeof(ToChar));
Console.WriteLine(Add(5, 9));
Console.WriteLine(ToChar('X'));
}
}
}


Willy.


Willy.
 
W

Willy Denoyette [MVP]

Nicholas Paldino said:
It's not even worth it to do this, because the C++ code is wrong. Once
the call to GetOut ends, the instance on the stack is no longer valid.

Not at all, the structure is a global variable.


Willy.
 
P

philipqiu

Thanks Willy & Nicholas

Through u help I have resolved my problem.
and the following code




public delegate System .Int32 typeone(System.Int32 x,System.Int32 y);
public delegate System.Char typetwo(System.Char a);
[StructLayout(LayoutKind.Sequential)]
public class my
{
[MarshalAs(UnmanagedType.FunctionPtr)]
public typeone one;

[MarshalAs(UnmanagedType.FunctionPtr)]
public typetwo two;
}

class Program
{
[DllImport("try.dll")]
static extern IntPtr GetOut();

static void Main(string[] args)
{
my lucky = (my)Marshal.PtrToStructure(GetOut(), typeof(my));
if(IntPtr.Zero!= lucky)
{
int sssss= lucky.one(1,2);

Console.WriteLine("xxxxx{0},{1}",sssss,lucky.two('k'));
}
}
}
 

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