Search code examples
c#c++pinvokemarshallingdllimport

Crash With DllImport C#


Gang,

I'm using a third-party API written in (what looks like) MFC C++. My application is a WinForms app in C#. The API's company has a C# demo application, and I used their code verbatim. The relevant code looks like this...

API's C++ Function:

int PASCAL CppFunction(BYTE *pbAdapterID, BYTE *pbTargetID, char *pcVendor, char *pcProduct, char *pcRelease, int iMessageBox)
{
    // The function definition is all I can see in the API's documentation
}

The DllImport Statement:

[DllImport("api.dll")]
extern public static int CppFunction(ref byte pbAdapter, ref byte pbTargetID, string pcVendor, string pcProduct, string pcRelease, int iMessageBox);

My C# Logic:

public void CallCppFunction()
{
    try
    {
        int result = 0;
        string strVendorBuffer = string.Empty;
        string strProductBuffer = string.Empty;
        string strReleaseBuffer = string.Empty;
        string strSerial = string.Empty;
        byte bAdapt = 0;
        byte bTarg = 0;

        result = CppFunction(ref bAdapt, ref bTarg, strVendorBuffer, strProductBuffer, strReleaseBuffer, 0);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

This is the code as it exists in their C# sample. When run, it crashes with a "FatalExecutionEngineError" even in a try/catch.

enter image description here

I don't know PInvoke very well, but don't those variables have to be marshaled as an unmanaged type? Any help would be appreciated.


Solution

  • I am taking a wild guess here, but I am pretty sure it will be the right answer

    Lets take a look to the function definition:

    int PASCAL CppFunction(
        BYTE *pbAdapterID, 
        BYTE *pbTargetID, 
        char *pcVendor, 
        char *pcProduct, 
        char *pcRelease, 
        int iMessageBox);
    

    And the corresponding DllImport declaration:

    [DllImport("api.dll")]
    extern public static int CppFunction(
        ref byte pbAdapter, 
        ref byte pbTargetID, 
        string pcVendor, 
        string pcProduct, 
        string pcRelease,
        int iMessageBox);
    

    There are a lot of parameters there, some of them caught my attention:

        char *pcVendor, 
        char *pcProduct, 
        char *pcRelease,
    

    They are not passed by reference, are they being modified by the library?

    Note: That why I asked you to give details about the function.

    I that's the case, you cannot marshal strings because the datatype string is immutable, you must use the StringBuilder class, just make sure the StringBuilderhas enough Capacity.

    int result = 0;
    StringBuilder strVendorBuffer = new StringBuilder(1024); // up to 1024 chars
    StringBuilder strProductBuffer = new StringBuilder(1024); // up to 1024 chars
    StringBuilder strReleaseBuffer = new StringBuilder(1024); // up to 1024 chars
    StringBuilder strSerial = string.Empty;
    byte bAdapt = 0;
    byte bTarg = 0;
    
    result = CppFunction(ref bAdapt, ref bTarg, strVendorBuffer, strProductBuffer, strReleaseBuffer, 0);