views:

4536

answers:

5

I have built a C++ dll that I would like to call from C# code. I'm able to call one function, but the other throws an exception when the C# code tries to load the dll.

The header looks like this:

extern "C" __declspec(dllexport) BOOL Install();
extern "C" __declspec(dllexport) BOOL PPPConnect();

This produces a dll with slightly confusing exports table (what does foo = foo mean in the name field?):

File Type: DLL

Section contains the following exports for PPPManager.dll

00000000 characteristics
499F44F0 time date stamp Fri Feb 20 16:04:00 2009
    0.00 version
       1 ordinal base
       2 number of functions
       2 number of names

ordinal hint RVA      name

      1    0 000078E4 Install = Install
      2    1 000079DC PPPConnect = PPPConnect

My P/Invoke declarations look like this:

[DllImport("PPPManager.dll")]
private static extern bool Install();

[DllImport("PPPManager.dll")]
private static extern bool PPPConnect();

The call to Install returns with no exception, but when I call PPPConnect, I get a MissingMethodException - "Can't find an Entry Point 'PPPConnect' in a PInvoke DLL 'PPPManager.dll'."

I've tried removing the extern and declspec directives from the Install function declaration, so that PPPConnect is the only function exported, and this still doesn't let me call PPPConnect.

I have also tried doing the DllImport by ordinal; this gives the same result as calling by name - Install returns, but PPPConnect throws the exception "Can't find an Entry Point '#2'...".

The interop log gives:

[pinvokeimpl][preservesig]
bool  invivodata.Common.System.IPAQUtils::Install();
BOOLEAN (I1_WINBOOL_VAL) Install();

JIT ERROR FOR PINVOKE METHOD (Managed -> Native): 
[pinvokeimpl][preservesig]
bool  invivodata.Common.System.IPAQUtils::PPPConnect();
BOOLEAN (I1_WINBOOL_VAL) PPPConnect();

This is well outside my area of expertise, so any suggestions or thoughts would be welcome.

Thanks, Paul

edit: It turns out that this code does work; the problem was with the latest dll not being propagated to the device. D'oh!

A: 

Great information, but as you mention, everything is in order here. Try installing Debugging Tools for Windows and running:

kd -z \path\to\PPPManager.dll -y \path\to\PPPManager.pdb -c "x pppmodule!*"

to get a better dump of the symbols table; it's a blind shot as well, but you could also try:

extern "C" 
{
    __declspec(dllexport) BOOL Install();
    __declspec(dllexport) BOOL PPPConnect();
};

in case the __declspec is doing something weird.

Paul Betts
+1  A: 

It could be something as simple as PPPConnect failing in a way that gets misinterpreted by the OS. Try implementing both Install and PPPConnect as no-ops (just have them return TRUE without doing anything else) and see if the error persists. If so, try swapping the order in which they are exported (still as no-ops) and see if the problem is tied to ordering (unlikely) or to something else.

You can also use the graphical tool depends to confirm what the DLL's exports table looks like, but I doubt the problem is coming from those quarters.

vladr
These are good ideas for isolating the real problem. You could also try adding a third function and seeing what happens with that one.
Charlie
+1  A: 

According to your description Install and PPPConnect differs only in names. I guess you simply use old .dll version with your C# application. A one without PPPConnect defined.

The declarations looks right (as far as I can judge without sources).

alex2k8
+4  A: 

Are you using a .def file in your dll project to export those functions? If so, remove it and try again. This is just a guess because it looks like your exports are not what they should be when you do an extern "C" declspec(dllexports).

I tried this out with a simple C++ dll using

extern "C" __declspec(dllexport) BOOL Install();
extern "C" __declspec(dllexport) BOOL PPPConnect();

and a simple C# app using your PInvoke declarations and it worked fine.

When I did a dumpbin/exports on the dll I saw:

Dump of file PPPManager.dll

File Type: DLL

Section contains the following exports for PPPManager.dll

00000000 characteristics
499F6C2D time date stamp Fri Feb 20 20:51:25 2009
    0.00 version
       1 ordinal base
       2 number of functions
       2 number of names

ordinal hint RVA      name

      1    0 000110CD Install = @ILT+200(_Install)
      2    1 00011069 PPPConnect = @ILT+100(_PPPConnect)

Notice that the exported names are different in my case.

m-sharp
In the end it turns out that I wasn't copying the latest dll over, due to my misunderstanding what the 'Add file to project' command in VS does.Your idea to try a stripped down dll was the seed I needed to go and figure that out. Thanks!
Symmetric
Great! Glad I could help.
m-sharp
A: 

use dependency walker and open your DLL to verify what methods are available

iterationx