2

I'm trying to call an function in an unmanaged c++ dll in .net cf 3.5 in a windows ce 6.0 environment.

The struct is defined as:

typedef struct TagOperatorInfo
{
    DWORD dwMode;       
    DWORD dwFormat;     //Operator name format
    DWORD dwAct;        //Network type(Available in 3G module£ºGSM or 3G),
    TCHAR szOper[32];   
}OperatorInfo,*LPOperatorInfo;

and the function call is:

BOOL GetCurOperatorInfo(LPOperatorInfo pinfo);

I defined in .net the TagOperatorInfo as follows:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    public struct TagOperatorInfo
    {

        /// DWORD->unsigned int
        public uint dwMode;

        /// DWORD->unsigned int
        public uint dwFormat;

        /// DWORD->unsigned int
        public uint dwAct;

        /// TCHAR[32]
        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 32)]
        public string szOper;
    }

and after seeing some articles and msdn documentation i call the native function as:

[System.Runtime.InteropServices.DllImportAttribute(gsmaAdapterDLLName, EntryPoint = "#30", CallingConvention = CallingConvention.Winapi)]
    [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
    internal static extern bool GetCurOperatorInfo([MarshalAs(UnmanagedType.LPStruct)] ref NativeHelper.TagOperatorInfo operatorInfo);

Note: I call the function with an entry point defined with the ordinal because the c++ mangled names.

The problem that i have is that i always get the notSupportedException throw. I don't understand because the ref parameter should give it the Pointer to the struct.

My .net function that calls it is:

/// <summary>
    /// Gets the current operator information.
    /// </summary>
    /// <param name="operatorInfo">The operator info.</param>
    /// <returns></returns>
    public static bool GetOperatorInformation(out NativeHelper.TagOperatorInfo operatorInfo)
    {
        operatorInfo = new NativeHelper.TagOperatorInfo();

        if (NativeImports.GetCurOperatorInfo(ref operatorInfo) == true)
        {
            return true;
        }
        else
        {
            return false;
        }

    }

What i'm missing for this to work.

UPDATE

New .Net Compact Framework method call

[System.Runtime.InteropServices.DllImportAttribute(gsmaAdapterDLLName, EntryPoint = "?GetCurOperatorInfo@CGSMAdapter@@YAHPAUTagOperatorInfo@@@Z", CallingConvention = CallingConvention.Winapi)]
    [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
    internal static extern bool GetCurOperatorInfo([MarshalAs(UnmanagedType.LPStruct)]ref NativeHelper.TagOperatorInfo operatorInfo);
Sorcerer86pt
  • 427
  • 9
  • 21
  • Are you sure you need the ordinal? Try it with the name. Almost all C++ API's will use `extern "C"` for unmangled names. – H H Jan 26 '11 at 12:35
  • CGSMAdapter sounds like a class name, not a namespace name. Is it a static method? – Hans Passant Jan 26 '11 at 14:08
  • It is an class name for an gsm/gprs modem adapter that the manufacter of the pda gave us for making calls, sending/receiving sms and creating gprs connections. – Sorcerer86pt Jan 26 '11 at 14:18

1 Answers1

7

You can only call functions that have been exported as C style functions. As far as I am aware you cannot call straight C++ functions via P/Invoke, e.g.:

How to set up a C++ function so that it can be used by p/invoke?

Update

Actually, it does appear you can use mangled names when calling a function via P/Invoke. This is something I could never get working in the past, so I stand corrected. Using names rather than ordinals should be more resilient too:

Reference: Entry Point Not Found Exception

So something like:

[DllImport(gsmaAdapterDLLName,
    EntryPoint="?GetCurOperatorInfo@CGSMAdapter@@YAHPAUTagOperatorInfo@@@Z", 
    ExactSpelling = true,
    CallingConvention = CallingConvention.Cdecl)]
public static extern bool GetCurOperatorInfo(out TagOperatorInfo info);

And for .Net CF:

DllImport(gsmaAdapterDLLName,
    EntryPoint="?GetCurOperatorInfo@CGSMAdapter@@YAHPAUTagOperatorInfo@@@Z", 
    CallingConvention = CallingConvention.WinApi)]
public static extern bool GetCurOperatorInfo(out TagOperatorInfo info);
Community
  • 1
  • 1
Tim Lloyd
  • 37,954
  • 10
  • 100
  • 130
  • It is exported in an declspec(dllexprt), and if i do an dumpbin i get the following entry: 30 1D 000067DC ?GetCurOperatorInfo@CGSMAdapter@@YAHPAUTagOperatorInfo@@@Z – Sorcerer86pt Jan 26 '11 at 12:40
  • @Sorcerer86pt As far as I am aware it also needs to be `extern "C"` as you cannot call functions with mangled names. – Tim Lloyd Jan 26 '11 at 12:45
  • #define DLLGSMADAPTER _declspec(dllexport);;;DLLGSMADAPTER BOOL GetCurOperatorInfo(LPOperatorInfo pInfo); This is the function complete signature – Sorcerer86pt Jan 26 '11 at 12:47
  • 2 things: Since i'm programming for .net CF i don't have acess to the ExactSpelling and the only menber of CallingConvention is the WinApi one that defaults to the calling convention of the SO. Nevertheless will see if it works and then will say something – Sorcerer86pt Jan 26 '11 at 15:11
  • It worked like an charm, if we substitute the calling convention and take of the exact spelling – Sorcerer86pt Jan 26 '11 at 15:20
  • I'll update. Glad to be of help. If you don't have access to the source to fix the names by applying `extern "C"`, this is very handy to know. – Tim Lloyd Jan 26 '11 at 15:26
  • Agreed, but then there is also the dumpbin /EXPORTS to the rescue – Sorcerer86pt Jan 26 '11 at 16:15
  • @Sorcerer86pt I am referring more to having "nice" names, mangled names are not nice :) – Tim Lloyd Jan 26 '11 at 16:22
  • Mangled names are so unfriendly, I'd be highly inclined to create a new C DLL that does export nice names that in turn makes the calls to the function for me. – ctacke Jan 26 '11 at 16:23
  • Since i'm mostly an c# programmer the less i murk in c/C++ code the less mistakes i make. It's so easy in this things to miss an pointer or perform an invalid cast. Also i'm lazy as hell :-) – Sorcerer86pt Jan 27 '11 at 10:09
  • @Sorcerer86pt **Tip** If you want to address a specific user, include their @username in your comment, otherwise they will not get notified of your update, so may never read it. Cheers, @chibacity. :) – Tim Lloyd Jan 27 '11 at 10:13
  • @Tim Lloyd, the statement of "You can only call functions that have been exported as C style functions." is not really true. You might want to take a look at the blogs I wrote if you are interested in creating C# wrapper assembly automatically for native C++ style DLL. – xInterop Feb 23 '14 at 03:40
  • @xInterop Agreed, I added an update to my answer. Do you have a link to your blog articles, would like to take a look. Thanks. – Tim Lloyd Feb 23 '14 at 18:08
  • @Tim Lloyd, I am glad you agreed, developers were convinced in the past that is not the case although Microsoft never stated that, it is hard to think a different way. Please take a look at http://www.xinterop.com/index.php/category/net/ to see all the blogs if you are interested. – xInterop Feb 23 '14 at 20:54
  • Wouldn't it be `CallingConvention = CallingConvention.ThisCall` for calling methods on C++ objects? That's what I'm using in my code. – ulatekh Mar 09 '16 at 21:06