Reputation: 951
So I am trying to export a function in a DLL that was developed in C++ into a C# project. After digging around online and doing some book research as well I found a means to do so. However my exposure to this is limited and all my knowledge is self taut so I am sure that I messed something up somewhere.
I am exporting the function like so:
STDMETHODIMP __export DataSetpImpl::set_HeaderFile(BSTR Value)
and importing it as such:
public unsafe class test
{
const string _dllLocation = "DllPath.dll";
[DLLImport(_dllLocation, CallingConvention = CallingConvention.stdCall)]
[return: MarshalAs(UnmanagedType.Bstr)]
public static extern string set_HeaderFile([MarshalAs(UnmanagedType.BStr)] String path);
}
then call it in the application as followes:
test.set_HeaderFile(@"C:\temp\SomeHeaderFile.hdz");
everything builds correctly and links up just fine... the issue appears when the application hits the above call. It throws and error saying:
Unable to find an entry point named 'set_HeaderFile' in DLL 'DLLPath.dll'.
any ideas on what I am doing wrong? Also please keep in mind my knowledge on this subject if very limited, I am just going off what I could find online and in notes around the office.
Upvotes: 1
Views: 2352
Reputation: 14467
This way you can only import non-class member functions.
The name "set_HeaderFile" in your case is mangled into something like "DataTableImpl$$set_HeaderFile@4" and even if it is declared as static, the CLR won't find this in your .dll file using the name "set_HeaderFile".
You can make a workaround.
Say you have a
DataSetpImpl* g_Instance;
Then write a function
LONG __stdcall mySetHeaderFile(BSTR Val)
{
return g_Instance->set_HeaderFile(Val);
}
and then in C# you can access it.
[DLLImport(_dllLocation, CallingConvention = CallingConvention.stdCall, EntryPoint="mySetHeaderFile")]
public static extern Int32 set_HeaderFile([MarshalAs(UnmanagedType.BStr)] String path);
Returning BSTRs also require some wrapping using the Marshalling. See this: http://msdn.microsoft.com/en-us/library/7b620dhe.aspx
Upvotes: 2
Reputation: 61331
I think you're confusing two ways of interaction with managed code. You can wrap your code in a COM server and take advantage of .NET's COM interop facility. Or you can make a nonclass (i. e. globally scoped) exported function and use P/Invoke.
The wording of the function suggests COM. But on the C# side you use P/Invoke, wrongly.
I suggest that you use P/Invoke. COM is a big topic; unless you're willing to learn A LOT, don't go there.
For P/Invokable function, make a non-class function. You cannot consume exported C++ classes from DLLs via P/Invoke. The two class systems - managed and C++ - are quite distinct. Also, you don't have to pass BSTR's around, P/Invoke is fine with good old LPCWSTRs.
Upvotes: 0