Search code examples
c++-cliaccess-violation

AccessViolation, when calling C++-DLL from C++/CLI


I've written a C++/CLI wrapper for a C++-DLL to use this DLL in a C# programm.

However, when I call a function, which takes a char* I get a AccessViolation

int Wrapper::Net_methodX(int a, String^ key, long v)
{
    IntPtr ptr = Marshal::StringToHGlobalAnsi(key);
    pin_ptr<char> cKey = static_cast<char*>(ptr.ToPointer());
    int val = methodX(a,cKey, v); // AccessViolation here

    Marshal::FreeHGlobal(ptr);
    return val;
}

The signature of the C++-function is

int methodX(int a, char *Key, long v);

EDIT 1

Just to "pin" like the following didn't work either:

int Wrapper::Net_methodX(int a, String^ key, long v)
{
    IntPtr ptr = Marshal::StringToHGlobalAnsi(key);
    char* cKey = static_cast<char*>(ptr.ToPointer());
    pin_ptr<char> pinned = cKey;
    int val = methodX(a,cKey, v);

    Marshal::FreeHGlobal(ptr);
    return val;
}

EDIT 1 END

EDIT 2

I tried also PtrToStringChars the following way (Thanks Matt, found also some doc here):

int Wrapper::Net_methodX(int a, String^ key, long v)
{
    pin_ptr<const wchar_t> wkey = PtrToStringChars(key);

    size_t convertedChars = 0;
    size_t  sizeInBytes = ((key->Length + 1) * 2);
    errno_t err = 0;
    char * ckey = (char * ) malloc(sizeInBytes);

    err = wcstombs_s(&convertedChars, ckey, sizeInBytes, wkey, sizeInBytes);

    int val = methodX(A_Symbol_Table,ckey, Value);

    return val;
}

AccessViolation still occurs, maybe it's an error in methodX() (which is a Third-party-DLL).

EDIT 2 END

I have read some related questions here, but did not find a solution yet.

Any hints? Thank you.


Solution

  • Simon, I tried out your example and I do not get an Access Violation. Here's my code:

    using namespace System;
    using namespace System::Runtime::InteropServices;
    
    ref class Wrapper
    {
    public:
        static int Net_methodX(int a, String^ key, long v);
    };
    
    int methodX(int a, char * pKey, long v)
    {
        IntPtr ptr = static_cast<IntPtr>(pKey);
        String ^ pString = Marshal::PtrToStringAnsi(ptr);
        System::Console::WriteLine(pString);
        return a;
    }
    
    int Wrapper::Net_methodX(int a, String^ pKey, long v)
    {     
        IntPtr ptr = Marshal::StringToHGlobalAnsi(pKey);     
        pin_ptr<char> cKey = static_cast<char*>(ptr.ToPointer());     
        int val = methodX(a,cKey, v); // AccessViolation here      
        Marshal::FreeHGlobal(ptr);     
        return val; 
    }
    
    void main()
    {
        Wrapper wrapper;
        String ^ p = gcnew String("Hello");
        wrapper.Net_methodX(0, p, 0);
    }
    

    Also, I have a few comments:

    1. Read here: http://support.microsoft.com/kb/311259
    2. You are using a pin_ptr to native memory. The StringToHGlobalAnsi method returns native memory, so I don't think using a pin_ptr makes sense here. A pin_ptr would make sense if you were using a method that gives you back a pointer to managed memory (like PtrToStringChars). Unless you are modifying the string, you probably want to go with the PtrToStringChars approach anyways--to avoid unnecessary allocation and copying.
    3. Would you post an example version of methodX that causes the problem? If I can reproduce the issue, I might be able to be more helpful.