Search code examples
c++c#-4.0pinvokedllimport

P/Invoke, trouble finding/declaring function entry point


I'm having some difficulty with a P/Invoke call on a C++ dll. I get the "unable to find an entry point" error.

In the C++, I'm exposing the function like so...

#ifdef __cplusplus
extern "C" {
#endif

__declspec(dllexport)
long
WINAPI
MgScSCardUIDlgSelectCardW(__inout LPOPENCARDNAMEW_EX pOcne);

#ifdef __cplusplus
}
#endif

The dllimport statement in C# is as follows:

[DllImport("mgsc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 MgScSCardUIDlgSelectCardW([MarshalAs(UnmanagedType.Struct)] [In, Out] ModWinsCard.OPENCARDNAME_EX ocnwex);

I've tried this with no calling convention, standard, and winapi calling convention. Same result with all. I looked at the exposed functions with DependencyWalker, and see it exposed as "_MgScSCardUIDlgSelectCardW@4". I understand the decoration is normal (but that declaring 'extern "C"' was supposed to handle that??), but have never seen any example code where the dllimport had the function looking this way, so it doesn't seem as though that's how I should be calling it.

I've seen answers on here recommending .def files, but I'd rather not have to deal with that, as that's just one more thing for me to learn and screw up on, when I just need to get this done.


Solution

  • Everything is normal with the DLL. You are getting the benefit of the @4 postfix added to the name by the compiler. It describes the size of the argument values passed to the function, 4 bytes for the structure pointer. This catches mistakes in the declaration of the function in the client code, such mismatches can be very difficult to troubleshoot because they imbalance the stack.

    Which works well here too, you almost certainly declared the function wrong. 99% odds that you declared OPENCARDNAME_EX as a struct and not a class. Which requires you to pass the argument by reference, not by value. The [MarshalAs] attribute is wrong too. Fix:

    [DllImport("mgsc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 MgScSCardUIDlgSelectCardW(ref ModWinsCard.OPENCARDNAME_EX ocnwex);