C# program calling a C++ DLL

L

Laurent

Hello,


I received a C++ DLL and I must include it in my C# programm. The
problem is that I don't know how to convert the parameters from C++ to C#,
specialy when there are pointers in it. There are 2 fonctions I would like
to convert.

The first one has only one parameter, but I don't know how to deal with
the void type.

[C++]
long myFunction1(void ** parameter);

I tried this, but it does not work:

[C#]
[DllImport("MyDLL.dll")]
public static extern long myFunction1(ref IntPtr parameter);




The second one has a double pointer to a structure. I think I dealed
with the structure, but what about the double pointer ?

[C++]
long myFunction2(myStruct** parameter);

with myStruct defined as:

struct FF_AO_ImageList
{
char structParameter1[30];
long structParameter2;
}

[C#]
[DllImport("MyDLL.dll")]
public static extern long myFunction2(??????);

with myStruct defined as:

public struct FF_AO_ImageList
{
[MarshalAs(UnmanagedType.ByValTStr), SizeConst = 30]
public string structParameter1;
public long structParameter2;
}


I hope it's not too difficult to understand, however I'll explain again.
I hope someone can help me ! Thanks...


Laurent
 
K

Kofi

Laurent, your code example for the void pointer looks okay. The thing
with P/Invoke is you need to have a bit more understanding of the
unmanaged types and you seem to have got it with the first function.

void** is roughly equivalent to passing your IntPtr by ref - but then
again does the DLL expect the pointer to be pointing to some valid
data? In which case you will need to use the Marshal COMInterop class
to do some tweaky Writes directly to unmanaged memory.

The second function is a little more tricky. It expects a pointer to a
pointer to a value type (struct). Now as long as the structure layout
is as expected by the DLL, you should actually create a *class* (which
is implicitly passed by reference always) and pass your class i.e. the
FF_AO_ImageList (declare as class, not "struct"), by ref.

Two other things I noticed - ensure you explicitly set the
CallingConvention attribute (CDecl? StdCall?); Also decorate your
class with the StructLayoutAttribute (most likely layout type is
"Sequential"). See Adam Nathan's www.PInvoke.net as well for plenty of
examples.
 
L

Laurent

Hi Kofi,


Thanks for your answer. I'm trying to use only the first function with
the void** parameter. I think the DLL will allocate the memory so I don't
have to do it by myself. Anyway, the code always throws a
System.EntryPointNotFoundException with the following message: "Unable to
find the Entry Point "xxxx" in the DLL "xxxx.dll".

I opened a DLL using "DLL Depends 2.1"... The tool shows me the function
I would like to call with an entry point adress. Prehaps the DLL has not
been well compiled ?

I don't know what I did wrong. I tried to use an unsafe code and a
void** parameter, but the same error occured. I'll try using a C++ code to
call my DLL, just to see if I can access the function...


If anyone has an idea...
 
K

Kofi

Hi Laurent,

If you can see the DLL function with Depends then it is likely you
should be able to call it ok. Doing a quick check calling it from C++
is a good idea - I notice you did not mention whether you used the
CallingConvention attribute in your last post, it might be an idea to
use the ExactSpelling attribute as well. Plus (I'm sorry, dumb
question but you never know), is your DLL in the correct directory?
i.e. the bin/Debug directory most likely, while you're debugging? It
is a few months since I last used P/Invoke but I always found that you
end up frustrated for a few days and then once you get things working
you remember all the gotchas.

On the void** issue, another thing I can suggest is to try using the
OutAttribute on your function prototype instead like so:

[C#]
[DllImport("MyDLL.dll", EntryPoint="myFunction1", ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)] public static extern long
myFunction1([Out] IntPtr parameter);

Note that your calling convention above may not be StdCall...

Hope this helps!
 
L

Laurent

Hi Kofi,



I found a sample code in C++, but to make it work I had to use the .lib
file. It's a long time since I programmed in C++ so I don't remember well
how it works. Anyway I can access the function.

For my C# code, I tried like this:

[DllImport("myLib.dll", EntryPoint="myFunction1", ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static extern unsafe long myFunction1(void** outInstance);

[DllImport("myLib.dll", EntryPoint="myFunction1", ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static extern long myFunction1(out IntPtr outInstance);


The error is always the same: Cannot find EntryPoint. I don't know what
to do next. Thanks for your help anyway !
 
K

Kofi

Quite a while since I did any hardcore C++ too, but looks like what you
have is some name-mangling issues. BTW the function signature I put in
my last post was just an example, and there are other choices of
calling convention to try - I expect that your dll is more likely to be
"CallingConvention.CDecl". Having said that, considering the error you
are getting I don't believe that to be the problem anyway, but bear it
in mind. Try calling the DLL from C# using just the entry point
ordinal only:-

[DllImport("dllname", EntryPoint="#123")]

Where #123 is the ordinal position of the function. (I am not quite
sure how you determine this if you don't have the code yourself.
Depending on how the DLL was constructed, that kind of info normally
goes into a .DEF file - but I am showing my age...)

I'm afraid I have reached a dead end now I think...
 
L

Laurent

Hi Kofi,


Thanks again for your answer and your patience. I think you found a
clue: I can access my function using the ordinal !

I used the commande dumpbin -exports myLib.dll, and I saw that the
functions where given strange names. I think that the guy who compiled the
DLL did not use the extern "C" function to compile his DLL.

You were very helpful, thanks again !
 
J

Jeff Louie

Laurent.... You can call the function using the mangled name as in:

To call a function using its fully decorated name "?fnWin32Test2@@YAJXZ"
as
"Win32Test2" you can specify the static entry point as
"?fnWin32Test2@@YAJXY":

[DllImport("Win32Test.dll", EntryPoint= "?fnWin32Test2@@YAJXZ")]
public static extern int fnWin32Test2();

And call it as:

System.Console.WriteLine(fnWin32Test2());

To look at the undecorated name use the undname tool as in:
undname ?fnWin32Test@@3HA
This converts the decorated name to "long fnWin32Test".

Regards,
Jeff
 

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