2

I am trying to pass struct as a parameter from C# application to the C++ MFC DLL. DLL fills records in the struct object and return back to the C# application. So here I used "out" keyword in C# application to call C++ method. When I execute it, it fails with error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." I am allocating memory at C++ DLL to store the records and assign it to out parameter. I could send data in struct object and print it in C++ DLL but not able to do modification in struct object at DLL side and return back to C# application.

Could anybody please help on this.

NativeDLLHelper.cs

class NativeDLLHelper
    {
        const int FIELD_LENGTH = 255;

        [StructLayout(LayoutKind.Sequential)]
        public struct APPDATA
        {
            public int ID;
            public int Version;
            [MarshalAs(UnmanagedType.LPTStr, SizeConst = FIELD_LENGTH)]
            public string AppName;
        };

        [DllImport("Parser.dll", EntryPoint = "?FillLstStructData@DLLWrapper@@QAEXAAPAU_APPDATA@1@@Z")]
        public static extern void FillLstStructData(out APPDATA[] AppDataStruct);
}

Main.cs

NativeDLLHelper.APPDATA[] lstFillAppDataStruct;
NativeDLLHelper.FillLstStructData(out lstFillAppDataStruct);
for (int i = 0; i < lstFillAppDataStruct.Length; i++)
{
    Console.WriteLine(" ID[{0:G}]:{1:G}", i, lstFillAppDataStruct[i].ID);
    Console.WriteLine(" Version[{0:G}]:{1:G}", i, lstFillAppDataStruct[i].Version);
    Console.WriteLine(" AppName[{0:G}]:{1:G}", i, lstFillAppDataStruct[i].AppName);
}

C++ DLL:

static const int FIELD_LENGTH = 128;
typedef struct _APPDATA
{
    int ID;
    double Version;
    TCHAR AppName[FIELD_LENGTH];
}APPDATA;

extern "C" __declspec(dllexport) FillLstStructData(APPDATA* &pAppData)
{
    APPDATA *localAppDataStruct = new APPDATA[2];

    localAppDataStruct[0].ID = 1;
    localAppDataStruct[0].Version = 1.1;
    _tcscpy(localAppDataStruct[0].AppName, L"MS Visual Studio 2010");

    localAppDataStruct[1].ID = 2;
    localAppDataStruct[1].Version = 2.1;
    _tcscpy(localAppDataStruct[1].AppName, L"MS Office 2010");

    pAppData = localAppDataStruct;
}
0

1 Answer 1

2

Your exported function unmangles to:

  void __thiscall DLLWrapper::FillLstStructData(struct DLLWrapper::_APPDATA * &)

That makes it an instance method of a C++ class. You cannot pinvoke such methods, they require the C++ object to be created first and you cannot do this reliably with pinvoke. Only static C++ member functions can be pinvoked. Do note that this function doesn't need to be an instance method at all, it doesn't actually use instance members of the class.

That isn't the only problem, there's also a nasty memory management issue. The function allocates memory with ::operator new and memory needs to be released by the caller. But a C# program cannot do this, it doesn't have access to the ::operator delete that the C++ code uses. This kind of function is very hard to use reliably from a C++ program for that reason, it doesn't get better when you do it from C#. The proper way to do it is to allow the caller to pass the array. In other words, APPDATA[] and an extra argument that says how long the passed array is.

If you can't rewrite this function then you must write a wrapper for this class using the C++/CLI language. Very important that this wrapper uses the exact same compiler and CRT version as the C++ DLL.

Sign up to request clarification or add additional context in comments.

4 Comments

I think you meant "free" functions (those which are not members of a class) rather than "static" functions (which cannot have "C" linkage, they are either static and free, which have no linkage, or static members, which are C++ linkage and makes p/invoke fragile). Of course it is trivial to write a free function that forwards to any public static member function.
I certainly can't agree with a recommendation to p/invoke C++ member functions, even static ones which have ordinary C++-linkage function type. p/invoke is for functions with "C" linkage only.
That's nonsense. Name decoration is an excellent bug prevention.
I agree with "fail fast, fail early", and mangling tends to cause that. But it's better to not fail at all.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.