Jimmy
Jimmy

Reputation: 951

Export a C++ DLL function and import into C#

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

Answers (2)

Viktor Latypov
Viktor Latypov

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

Seva Alekseyev
Seva Alekseyev

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

Related Questions