简体   繁体   中英

Calling a C dll from C# windows application causes the svchost.exe to crash

I created a C DLL so that I can use it in my C# application.
I tested the DLL on a C++ test application and it worked fine, but it won't work in the C# application.
For some reason, I can't build a debug version of the DLL , and therefore I haven't been able to run the C# app in debug mode either.
The DLL debug configuration won't find the include directories , where as in the release mode, it works just fine!
I need to say that, there is a specific method which I give below, that causes the crash, calling the other methods from the DLL is fine and works as expected. This is the main implementation :
header definition:

//use this function to classify an image
CDLL_API const char* Classify(const char* img_path, int N = 2);

.cpp implementation

CDLL_API const char* Classify(const char * img_path, int N)
    {
        auto classifier = reinterpret_cast<Classifier*>(GetHandle());
        std::vector<PredictionResults> result = classifier->Classify(std::string(img_path), N);
        std::string str_info = "";
        std::stringstream ss;
        for (size_t i = 0; i <result.size(); ++i)
        {
            auto label = result[i].label;
            auto acc = result[i].accuracy;
            ss << "label=" << label << ",acc=" << acc << "|";
        }
        return ss.str().c_str();
    }

C# code :

[DllImport(@"CDll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern string Classify([MarshalAs(UnmanagedType.LPStr)]string img_path,int N = 2);

//...
        var s = Classify(txtFilePath.Text, 2);
        MessageBox.Show(s);

So I'm completely out of thoughts about what could be the real cause.

The string type in C# is not compatible with const char * in C. You have to use StringBuilder :

 [DllImport("aCDLL.dll")]
 public extern static void getabuilder(StringBuilder abuilder);

and in C dll:

 extern "C" void __declspec(dllexport) __stdcall getabuilder(char *abuilder);

If you do not like the StringBuilder, you can store the string characters in an array of byte initialised in C# and passed to the C function:

 [DllImport("aCDLL.dll")]
 public extern static void getastring(byte[] data, ref int datalength);

and in C:

 extern "C" void __declspec(dllexport) __stdcall getastring(const char *data, int *datalength);

I see that you specified the calling convention to Cdecl ( CallingConvention = CallingConvention.Cdecl ) in your C# PInvoke declaration; since this is the default calling convention in C++ code as well, you shouldn't have any calling convention mismatch in this case. Although, please note that the common calling convention for C-interface DLLs is __stdcall .

The problem I see is the way you return the string from the C-interface API

 CDLL_API const char* Classify(const char * img_path, int N) { ... return ss.str().c_str(); } 

(BTW I assume ss is something like a std::ostringstream object.)

You build a string using an output string stream (calling its str method), then you get a raw C-style string pointer calling c_str . But when the function exits, the string object is destroyed, so the C-style raw string pointer is not valid anymore.

To return a string from C-interface DLL APIs to C#, you can consider one of these options:

  1. Return a BSTR string from the C-interface DLL. Use SysAllocString to create the BSTR object from a raw C-style string pointer. Note that BSTR s "naturally" store Unicode UTF-16 encoded strings, so please make sure to convert your string to this encoding. The CLR is able to manage BSTR strings just fine, so you don't have to pay attention to release the string memory: this will be the CLR's job.

  2. Add to the C-interface DLL function a couple of parameters: a pointer to a buffer , and a buffer size . This will be an output string buffer , that is allocated by the caller (eg C#), and the C-interface API exported from the DLL will write the result string to that caller-provided buffer. This is what eg the GetWindowText Win32 API does (on the C# side, the output string buffer can be represented by a StringBuilder object).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM