locked
Call from native C++ DLL to C# ClassLibrary RRS feed

  • Question

  • My project consists of WCF that uses an unmanaged VC++ DLL via a COM wrapper class. This works perfectly fine.
    Now I need to access a C# ClassLibrary (COM visible) from within the unmanaged VC++ DLL.
    In VC++, when I call the C# function via its interface pointer, i get the exception -
    "An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll
    Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
     
    I can access this C# ClassLibrary from a native win32 VC++ console application (exe) but get error when accessed from native VC++ DLL.
     
    What could be different, between calling from a native DLL and a console app?
    All components have been compiled in Win32.
     
    Please help me!!
    Friday, July 7, 2017 11:56 AM

Answers

  • Calling CoInitialize too often is not a problem, as long as you call CoUninitialize the same amount. But, it's correct, I'd also consider checking the return value. So... try this and tell us what errors you get:

    HRESULT hRes;
    
    if(SUCCEEDED(hRes = CoInitialize(NULL)))
    {
        {
        TestInfo::IGetTestInfoPtr obj(__uuidof(TestInfo::GetTestCode));
    
        if(obj) // or test return value of GetTestCode
        {
            BSTR strResult = SysAllocString(L"hello");
            hRes = obj->GetTestDetails(strInp, &strResult);
            wprintf(L"The result is %s", strResult);
        }
        } // scope for obj -> as alternative you can manually call Release and set to NULL
        CoUninitialize();
    }
    

    Rudolf

    • Marked as answer by Roshni.2013 Tuesday, July 11, 2017 8:04 AM
    Monday, July 10, 2017 3:24 PM

All replies

  • Hi

    Do you get valid pointers when you create the object? (I guess you use CoCreateInstance?). Maybe a problem with the apartments? How did you initialize Com (CoInitialize(Ex))?

    Rudolf

    Friday, July 7, 2017 1:15 PM
  • Or put another way, what are you doing differently between the code in the native C++ Win32 console application and usage from within the native C++ DLL?
    Friday, July 7, 2017 1:38 PM
  • From the C++ console app & C++ DLL, I call the C# Class Lib with exactly the same code given below:
     
                    HRESULT hr = CoInitialize(NULL);
                    TestInfo::IGetTestInfoPtr obj(__uuidof(TestInfo::GetTestCode));
                    BSTR strResult;
                    BSTR strInp = L"hello";
                    HRESULT Hr = obj->GetTestDetails(strInp, &strResult);
                    wprintf(L"The result is %s", strResult);
                    CoUninitialize();
     
    The pointer is initialized correctly in both cases.

    The Difference is -

    VC++ console App:
    This calls the C# lib using the above code and I get to see the output.
    VC++ Console App-->C# Class Lib
     
    VC++ DLL:
    This dll is invoked from WCF. For testing purpose, I have created a C# Winform which allows me to call the DLL using the COM Wrapper.
    C# WinForm-->COM Wrapper-->VC++ Native DLL-->C# Class Lib.
    The exception is thrown in the last phase VC++ Native DLL-->C# ClassLib. Once the exception is thrown, control is seen in the C# WinForm app.
     
    Could it be that when I try to access the managed code from the DLL, control is being passed back to the managed code, that made the call to the VC++ DLL in the first place??
    I do not understand how this works. Is it possible to oscillate between managed/Unmanaged code as given here? If so, what am I missing??
    Monday, July 10, 2017 8:22 AM
  • From the C++ console app & C++ DLL, I call the C# Class Lib with exactly the same code given below:
     
                    HRESULT hr = CoInitialize(NULL);
                    TestInfo::IGetTestInfoPtr obj(__uuidof(TestInfo::GetTestCode));
                    BSTR strResult;
                    BSTR strInp = L"hello";
                    HRESULT Hr = obj->GetTestDetails(strInp, &strResult);
                    wprintf(L"The result is %s", strResult);
                    CoUninitialize();
     
    The pointer is initialized correctly in both cases.

    The Difference is -

    VC++ console App:
    This calls the C# lib using the above code and I get to see the output.
    VC++ Console App-->C# Class Lib
     
    VC++ DLL:
    This dll is invoked from WCF. For testing purpose, I have created a C# Winform which allows me to call the DLL using the COM Wrapper.
    C# WinForm-->COM Wrapper-->VC++ Native DLL-->C# Class Lib.
    The exception is thrown in the last phase VC++ Native DLL-->C# ClassLib. Once the exception is thrown, control is seen in the C# WinForm app.
     
    Could it be that when I try to access the managed code from the DLL, control is being passed back to the managed code, that made the call to the VC++ DLL in the first place??
    I do not understand how this works. Is it possible to oscillate between managed/Unmanaged code as given here? If so, what am I missing??

    Can you make COM calls directly from the C# Winform to the C# Library?

    Some observations about the above code snippet -

    Ordinarily C# Winform projects initialize COM in the STA.  It's not clear to my why the code would need to call CoInitialize/CoUninitialize from within the VC++ DLL unless it was using COM  on a different thread.

    The return code  of CoInitialize is not checked.

    Successful creation of the COM object is not checked. If object creation from the DLL fails then the IGetTestInfoPtr is null and calling through it will result in an access violation.  Have you stepped through the DLL code line by line in the debugger?

    Assuming that IGetTestInfoPtr is a smart pointer then it will go out of scope and it's destructor will call release on the encapsulated interface pointer after the call to CoUninitialize.

    BSTRs are initialized with SysAllocString.  Merely assigning a wide char variable to a BSTR is erroneous.

    It is the caller's responsibility to free BSTRs passed back as an out parameter from a COM call.  The code should call SysFreeString on strResult when it no longer needs the BSTR or a memory leak results.

    Monday, July 10, 2017 9:39 AM
  • Calling CoInitialize too often is not a problem, as long as you call CoUninitialize the same amount. But, it's correct, I'd also consider checking the return value. So... try this and tell us what errors you get:

    HRESULT hRes;
    
    if(SUCCEEDED(hRes = CoInitialize(NULL)))
    {
        {
        TestInfo::IGetTestInfoPtr obj(__uuidof(TestInfo::GetTestCode));
    
        if(obj) // or test return value of GetTestCode
        {
            BSTR strResult = SysAllocString(L"hello");
            hRes = obj->GetTestDetails(strInp, &strResult);
            wprintf(L"The result is %s", strResult);
        }
        } // scope for obj -> as alternative you can manually call Release and set to NULL
        CoUninitialize();
    }
    

    Rudolf

    • Marked as answer by Roshni.2013 Tuesday, July 11, 2017 8:04 AM
    Monday, July 10, 2017 3:24 PM
  • Thank you so much Rudolf!! The problem was with me not using SysAllocString to initialize BSTR. This was resulting in the AccessViolation exception.
    Your code worked like a charm!!

    Thanks to RLWA32 too! The points you mentioned were very helpful.
    Tuesday, July 11, 2017 8:04 AM