Linking unmanaged C++ DLL with managed C++ class library DLL

Roger Nelson picture Roger Nelson · Oct 23, 2010 · Viewed 20.4k times · Source

As in the question Creating simple c++.net wrapper. Step-by-step

I am tring to use C++ classes in .NET but I am having problems building in Visual Studio (2008).

I have an unmanaged class A (C++ compiled with /clr). I created a C++/clr class 'Class1' which wraps A and with matching method delegates to A's methods.

If I include class A's unit source file in the class library project for Class1 (managed) I have no problems everything links and works fine, But I have many unmanaged C++ classes like A and I am tring to put them in a DLL and link that DLL to the managed library (of class wrappers). [I actually don't see a need to link these DLL's together at this point, but the compiler appears to be requiring it, giving the same errors shown below.]

I created VisualC++ / CLR / Class library and added my C++ class (A listed below) and build. [I used the default settings but in the project linker settings I've tried both Register output with yes and no.] There were no errors and the .DLL file was created.

I created VisualC++ / CLR / Class library and created the wrapper class 'Class1' I used all default settings. Under project properties I clicked 'References' 'Add New Reference" and selected the DLL created in the first step.

I get linker errors:

test_NET_library.obj : error LNK2028: unresolved token (0A000009) "public: int __thiscall Z::A::m1(int,int)" (?m1@A@Z@@$$FQAEHHH@Z) referenced in function "public: int __clrcall test_NET_library::Class1::m1(int,int)" (?m1@Class1@test_NET_library@@$$FQ$AAMHHH@Z)
test_NET_library.obj : error LNK2028: unresolved token (0A00000A) "public: int __thiscall Z::A::m2(int,int)" (?m2@A@Z@@$$FQAEHHH@Z) referenced in function "public: int __clrcall test_NET_library::Class1::m2(int,int)" (?m2@Class1@test_NET_library@@$$FQ$AAMHHH@Z)
test_NET_library.obj : error LNK2019: unresolved external symbol "public: int __thiscall Z::A::m1(int,int)" (?m1@A@Z@@$$FQAEHHH@Z) referenced in function "public: int __clrcall test_NET_library::Class1::m1(int,int)" (?m1@Class1@test_NET_library@@$$FQ$AAMHHH@Z)
test_NET_library.obj : error LNK2019: unresolved external symbol "public: int __thiscall Z::A::m2(int,int)" (?m2@A@Z@@$$FQAEHHH@Z) referenced in function "public: int __clrcall test_NET_library::Class1::m2(int,int)" (?m2@Class1@test_NET_library@@$$FQ$AAMHHH@Z)
C:\temp\test_Cpp_CLI\test_NET_library\Debug\test_NET_library.dll : fatal error LNK1120: 4 unresolved externals

The same errors as if I remove A.cpp in the wrapper class library project (the option that works). I don't understand why the build is trying to resolve externals in the first place because this is a library, not a program.

Is there something else I need to add to the wrapper class library project properties or register the DLL of unmanaged classes, or compiler options? Do I also need a .lib file to go with the DLL? (no lib file appears in the projects target directory)

Do I still have to use __declspec(dllexport) [it thought that was only for C style functions not class members.] as in the question: Export Unmanaged Classes from a Visual C++ DLL? even though the unmanaged C++ library is compiled with CLR enabled.

(I did also try compiling as a static library, but I can't figure out how to add the .lib file to the CLR class library project).

My test class is

namespace Z 
{
class A
{
public:

   int m1(int p1, int p2);
   int m2(int p3, int p4);
};
};

with the implementation:

#include "A.h"
namespace Z 
{
int A::m1(int p1, int p2) { return p1+p2; };
int A::m2(int p3, int p4) { return p3 * p4; };
};

And the wrapper class is

#pragma once
#include "../A.h"
using namespace System;
namespace test_NET_library {
 public ref class Class1
 {
 private: Z::A *a;
 public: Class1()
  : a(new Z::A)
   {}
 public: inline int m1(int p1, int p2)
  {  return a->m1(p1,p2);
  };
 public: inline int m2(int p3, int p4)
  {return a->m2(p3,p4);
  };
 };
}

As per the question: C++/CLI Mixed Mode DLL Creation I have also tried:

#pragma managed(push, off) 
#include "../A.h"
#pragma managed(pop)

And also this pushing managed around A.cpp.

Update: As per mcdave's response I removed the /clr this produced a DLL, now how do I make this DLL available to my test_NET_library?

I tried References/Add New Reference, and selected the new this new DLL; and got the message "Could not add reference to file 'C:..\unmanaged_lib.dll' because it is neither .NET assembly or registered ActiveX control.". The DLL was added to the project's file list, but the compiler appears to be ignoring it.

I tried Add/Existing item and selected the new DLL. but .DLL files are not a selectable file type.

Answer

mcdave picture mcdave · Nov 7, 2010

With the few hints from your update I will try two guesses...

  1. When unmanaged_lib is a statically linked lib, have you set the unmanaged_lib project to be a dependency of test_NET_library? (In the Project Explorer window, right-click on test_NET_library, select "Project Dependencies..." and select unmanaged_lib.)
  2. When unmanaged_lib is a DLL, you need to export the class from the DLL by following this answer and also make the test_NET_library depend on the unmanaged_lib project.