3
votes

I have a C++ application that I have to convert to a DLL. I have all the source.

my function is extern "C" __declspec(dllexport) int mymain(int i, std::wstring myArgs)

I need to be able to pass in the arguments from a c++ or c# wrapper. I am able to call this from a c++ console application without error. I am now trying to call it from C#.

This is my c# code:

    public static class DllHelper
{

    [DllImport("rep.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int mymain(int iArgs, string aArgs);
}

class Program
{



    static void Main(string[] args)
    {
        string s = "my string data";
        DllHelper.mymain(0, s);
    }
}

}

When I run it I get

System.Runtime.InteropServices.SEHException: 'External component has thrown an exception.'

I am out of ideas.

TIA

3
std::wstring is a C++ class... you cannot expect a C# string to be converted into that "automagically".yms
I implemented your suggestion and left the C# call alone but expect a LPTSTR as the parameter in the C++ dll. I am able to call it but the data I get in the dll is garbage myArgsPtr = 0x000000f3cabfec80 L"倯瑡⁨㩣瑜浥屰獪⹲硴⁴䈯捡畫印捥牵瑩⁹獪⹲p"Jeff

3 Answers

2
votes

Specify Unicode but also, in your C or C++ function, use printf with "%S" (upper-case 'S' means wide-character string).. OR std::wcout.

Without that, it might print weird or terminate at the first null char it finds. Also, you might want to actually pass the length of the string, but that's entirely up to you.

Note the signature of the C++ function uses LPCWSTR (const wchar_t*) for the myArgs parameter..

public static class DllHelper
{

    [DllImport("rep.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    public static extern int mymain(int iArgs, string aArgs);
}

class Program
{
    static void Main(string[] args)
    {
        string s = "my string data";
        DllHelper.mymain(0, s);
    }
}

#ifdef __cplusplus
extern "C" {
#endif

int __declspec(dllexport) mymain(int i, const wchar_t* myArgs)
{
    #ifdef __cplusplus
    std::wcout<<std::wstring(myArgs)<<L"\n";
    #else
    printf(L"%S\n", myArgs);
    #endif
}

#ifdef __cplusplus
}
#endif
1
votes

Based on yr last comment u might need to:

[DllImport("rep.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]

anyway since I dont have rep.dll it's hard to guess

1
votes

The naming used in your code:

mymain(int iArgs, string aArgs);

makes me think that what you are trying to do is probably passing an array of strings (similar to wmain(int argc, wchar_t** argv)).

If this is what you want, then on the native DLL side your function prototype would look like this:

extern "C" int __declspec(dllexport) mymain(int iArgs, wchar_t** aArgs)

And on the C# side, you would write a PInvoke declaration like this:

[DllImport("rep.dll", 
    CallingConvention=CallingConvention.Cdecl, 
    CharSet=CharSet.Unicode)]
public static extern int mymain(int iArgs, [In] string[] aArgs);

that you can invoke in C# like this:

string[] test = { "C64", "Bravo", "Charlie" };
int returnCode = mymain(test.Length, test);