Export dll method from C ++ to C #. Why I need: "extern" C ""

There is a method in my dll that I want to export.

// Transactions:

extern "C" __declspec(dllexport) 

//Does not work

 __declspec(dllexport) 

C ++ Export:

  extern "C" __declspec(dllexport) int Test(); 

C # import:

 [DllImport("CircleGPU2_32.DLL", EntryPoint = "Test", CallingConvention = CallingConvention.StdCall)] public static extern int Test(); 

Why do I need extern "C" ?

+8
c ++ c # dllexport
source share
4 answers

The main reason is to prevent the use of the man key of the C ++ name of the function name.

Try to export it without extern "C" and check the resulting DLL in Dependency Walker, and you will see a completely different name for the exported function.

+11
source share

This is due to a name change being made by C ++.

extern "C" vs no extern "C"

As an example, here is shown what CFF Explorer shows for the dll export table. The first was built with the borland C ++ compiler. The second was built using msvc.

 Ordinal FunctionRVA Name RVA Name 00000001 0020E140 0032C2B6 createDevice 00000002 0020E244 0032C2C3 createDeviceEx 0000000D 00328DA4 0032C0C1 @irr@core@IdentityMatrix 0000000E 00328DE4 0032C28A @irr@video@IdentityMaterial 

 0000000C 000F9C80 001EE1B6 createDevice 0000000D 000F9CE0 001EE1C3 createDeviceEx 00000001 00207458 001EDDC7 ?IdentityMaterial@video@irr@@3VSMaterial@12@A 00000002 001F55A0 001EDDF5 ?IdentityMatrix@core@irr@@3V?$CMatrix4@M@12@B 

The first 2 functions createDevice and createDeviceEx contain the extern "C" signature in their prototype, while the others do not. Note the coding difference when using C ++ mangling. The difference really goes deeper than that.

ABI and standardization

As explained in other answers, the C ++ standard does not specify I unstructured A bstract B. This means that vendors who develop their tools can pretty much do everything they need when it comes to how function calls are handled and how overloading works under the hood - while it demonstrates the expected behavior dictated by the standard.

With all of these different coding schemes, there is no other way that another language may have the hope of working with modules compiled with C ++. Heck modules compiled with one C ++ compiler are unlikely to work with another! Compiler providers are free to change their encoding between versions at their discretion.

In addition, no common ABI means that there is no common expected way to call these functions / methods. For example, one compiler can pass its arguments to the stack, and another compiler can pass it to the register. One could pass arguments from left to right, and the other could be undone. If only one of these aspects does not exactly match between the caller and the callee, then your application will crash ... that is, if you're lucky. Instead of dealing with this, vendors simply say no, causing a build error with different encodings.

OTOH, while C does not have a standardized ABI, C is a much simpler language to compare. Most C compiler providers handle the decoration function and call mechanism in a similar way. As a result, there is a kind of β€œde facto” standard, even if the ABI is not explicitly specified in the standard. With this community, it simplifies the interaction of other languages ​​with modules compiled with C.

For example, the decoration __stdcall in a function signature is understood as a specific calling convention. The arguments are pushed from right to left, and the caller is responsible for clearing the stack afterwards. __cdecl similar, but it understands that the caller is responsible for clearing the stack.

Bottom line

If the module in question should interact with languages ​​outside of C ++, it should be properly decorated and exposed as an API C, this is the best choice. Note that you are giving up some flexibility by doing this. In particular, you will not be able to overload these functions, since the compiler can no longer generate unique characters for each overload using mangling.

If interoperability is not important for the module in question - it will be used only with the same tool with which it was built, and then omit the extern "C" decor from your prototypes.

+20
source share

Typically, the compiler decorates your exported names to include class information and signatures. extern "C" tells the compiler to not do this.

+1
source share

I tried this with a function with parameter 1 and you should use

[DllImportAttribute ("whatever.Dll", CallingConvention = CallingConvention. Cdecl )]

for import in C #. The Stdcall operator only works (in the presented situation, and not at all) for functions without parameters and returns void. Tested in vs2012 express edition.

As a side note, the walker can be downloaded from http://www.dependencywalker.com/

0
source share

All Articles