A continued saga of C# interoprability with unmanaged C++ - c++

After a day of banging my head against the wall both literally and metaphorically, I plead for help:
I have an unmanaged C++ project, which is compiled as a DLL. Let's call it CPP Project. It currently works in an unmanaged environment. In addition, I have created a WPF project, that shall be called WPF Project. This project is a simple and currently almost empty project. It contains a single window and I want it to use code from Project 1. For that, I have created a CLR C++ project, which shall be called Interop Project and is also compiled as a DLL.
For simplicity I will attach some basic testing code I have boiled down to the basics.
CPP Project has the following two testing files:
tester.h
#pragma once
extern "C" class __declspec(dllexport) NativeTester
{
public:
void NativeTest();
};
tester.cpp
#include "tester.h"
void NativeTester::NativeTest()
{
int i = 0;
}
Interop Project has the following file:
InteropLib.h
#pragma once
#include <tester.h>
using namespace System;
namespace InteropLib {
public ref class InteropProject
{
public:
static void Test()
{
NativeTester nativeTester;
nativeTester.NativeTest();
}
};
}
Lastly, WPF Project has a single window refrencing Interop Project:
MainWindow.xaml.cs
using System;
using System.Windows;
using InteropLib;
namespace AppGUI
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InteropProject.Test();
}
}
}
And the XAML itself has an empty window (default created).
Once I am trying to run the WPF project, I get the following error:
System.Windows.Markup.XamlParseException: 'The invocation of the constructor on type 'AppGUI.MainWindow' that matches the specified binding constraints threw an exception.' Line number '3' and line position '9'. ---> System.IO.FileNotFoundException: Could not load file or assembly 'InteropLib.dll' or one of its dependencies. The specified module could not be found.
at AppGUI.MainWindow..ctor()
Interestingly enough, if I do not export the class from CPP Project, I do not get this error. Say, if i change tester.h to:
#pragma once
class NativeTester
{
public:
void NativeTest()
{
int i = 0;
}
};
However, in this case I cannot use my more complex classes. If I move my implementation to a cpp file like before, I get unresolved linkage errors due to my not exporting my code. The C++ code I want to actually use is large and has many classes and is object oriented, so I can't just move all my implementation to the h files.
Please help me understand this horrific error I've been trying resolve without success.
Thanks.

This went wrong right from the start, your tester.h file is not correct. The class should only have the __declspec(dllexport) attribute when you are building the tester project. Any other project that uses the DLL must see the class with the __declspec(dllimport) attribute. Start fixing this by using a macro in tester.h:
#undef EXPORTED
#ifdef BUILDING_DLL
# define EXPORTED __declspec(dllexport)
#else
# define EXPORTED __declspec(dllimport)
#endif
class EXPORTED NativeTester {
// etc..
};
And in your tester project, use C/C++, Preprocessor, Preprocessor Definitions and add BUILDING_DLL.
Next thing is to make sure that the DLL is being stored in the right directory. Which is what the exception is complaining about, it can't find the DLL. The build directory for C++ projects is Debug but for WPF projects it is bin\Debug. Fix that by changing the General + Output Directory setting, make it $(SolutionDir)$bin\(ConfigurationName).
Build the C++ project and verify that you can find the DLL back in the Solution's bin\Debug directory. And check that you also have the .lib file, you'll need that when you build the C++/CLI project. As an extra verification step, run Dumpbin.exe /exports foo.dll from the Visual Studio Command Prompt and check that you indeed see the class getting exported.
The C++/CLI project next, you need to change the Output Directory setting the same way. Add the .lib file to the linker's Additional Dependencies properties. You'll get the kind of linker errors you were talking about if you skip that step. Build it and verify that you get the DLL in the correct bin\Debug directory again.
Repeat these changes for the Release configuration.
Set the project dependencies, the WPF project depends on the C++/CLI project. The C++/CLI project depends on the C++ project. This ensures the projects are getting built in the right order.
You should now have a good shot at using these DLLs in your WPF project.

Related

Importing a C++ module from an external shared library (error C2230)

I've got 2 C++ project in the same Visual Studio solution: Engine, a library; and Test, that uses the Engine library
Engine compiles correctly on Windows and produces a lib and a dll. The lib is correctly given to the linker of Test as well
In Test, I try to import a module from Engine, but the compiler fails with error C2230
Here are code excerpts from the 2 projects:
Engine > hal.ixx
export module hal;
#ifdef TEST_ENGINE_EXPORTS
#define TEST_ENGINE_API __declspec(dllexport)
#else
#define TEST_ENGINE_API __declspec(dllimport)
#endif
import <string>;
export extern TEST_ENGINE_API void prepareMain();
export extern TEST_ENGINE_API int init();
//...
Test > main.cpp
#include <cstddef>
#include <stdio.h>
import hal; //fails here: error C2230 could not find module 'hal'
int main(int argc, char const* argv[])
{
prepareMain();
// some other stuff...
}
I'm using Visual Studio 2022 (v. 17.4.0), and for the 2 projects, I compile with std::c++latest, /permissive- and /experimental:module. I've also added the Engine header's folder as Additional include directory for the Test project.
I've tried to remove the module altogether and including headers files in Test and functions are correctly called
I already read this question (How to import a c++ module from another library?) that has the same problem that me, and the article linked in one comment (VS2019 Modules), but I fail to see how it can solve my problem
EDIT
So, I ran a couple of tests, and basically, it seems to stem from the fact that my library is a dll project
I tried making a new solution with 2 projects
The library one is a WindowsStaticLib project. Compiler options are : /std:c++latest, /std:c17, /permissive-, /experimental:module, and /sdl and /W3 (last 2 where there by default, I let them as they were). I deactivated precompiled headers since it seemed to interfere with modules (compliling amodule unit with /exportHeader as it is recommended here when module import standard header was causing VS to start looking for pch.h in header)
For the actual project using the library; library project is added as a reference, compiler options are the same as the library project, lib headers directory is added to VC++ directories > External include directories, lib folder to Library directories, and .lib file added as an Additional dependancy
Everything works.
Module is correctly found and imported, and functions can be called from the actual project.
As a side note, I should add that I didn't need to specify my module functions as extern for them to be usable in the other project main.cpp. I thought I should have done it but apparently not.
Now I tried to do the same thing but with a DLL project for the library. New solution with 2 project, with the exact same configuration as it was for the previous solution.
Error C2230 when I try to import my module in the actual project main.cpp.
Does anyone know something about this ?
Is it normal behaviour that I just didn't know ?

c++ import functions from dll - my dll doesn't export lib

I want to create a dll that exports a function and a struct. I went through the walkthrough and here is what I have:
Project myDll: the_dll.h
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
typedef struct MyStruct
{
bool b;
} MYSTRUCTTYPE, *PMYSTRUCTTYPE;
typedef const MYSTRUCTTYPE *MYCSTRUCTTYPE;
MYDLL_API bool dllF();
Project myDll: the_dll.cpp
#include the_dll.h
bool dllF() { return true };
In the Preprocessor definitions of the myDll project, I define MYDLL_EXPORTS
In Linker -> Advanced -> Import Library I see $(OutDir)$(TargetName).lib
Yet there is no lib generated, only dll and pdb
Intellisense shows MYDLL_EXPORTS to be __declspec(dllexport) and the dllimport portion is grayed out... So I must be exporting...
I have included the dependent header file, and set the additional library directories and additional include directories, as well as dependent libs, in the caller project. But... in the absence of the lib...
The project that requires the functions from this dll gives unresolved external symbol error.
How can I make my dll create a lib ? What am I missing ? (Or... how can I use its functions without linking to a lib and include a header ?)
Note: I assume the structs and typedefs do not need to be exported... true ?
Update: as I wrote in comment, the project did create a lib when I imported it into a different solution and erased all the debug folders... I have been "Build -> Clean Solution" between tries but I suppose something did not get cleaned ...
So the true reason for not getting a lib created was (my guess) that, while experimenting with the code and before adding the definition for MYDLL_EXPORTS, files where created that did not get cleaned... I will always delete the build folders before trying again, in the future.
I checked with a small test project in VS2013. It produced .lib files for both my DLLs in the Debug directory. This means that if the setup is not screwed up, using default settings you should have implib after building the DLL.
In fact, you need .lib file only if you want to distribute your dll to customers. If you want to use this dll in the same solution by other projects, do the following:
Select project where you want to import functions.
On the top menu click PROJECT->References....
Click button "Add New Reference" at the mid bottom.
Select dlls that you want to import from.
Close all dialogs with OK.
Rebuild your solution.
Structures cannot be exported. They are communicated to other binaries using header files. You can export only function entry points (including class member functions) and static data fields. You should include your header both into your dll code and and all applications that use your DLL. The #ifdef MYDLL_EXPORTS has exactly this purpose.

Can I build executable as dll?

I need to create a dll which contains stuff I have in my executable project in visual studio 2010. I realized instead of creating a dll project, I can just change the project configuration in project properties >> General >> 'configuration type' to 'dll' and it builds fine. It creates the dll. I added an additional .h/.cpp files which contains the export functions I want in the dll.
My first concern is that is this a legit dll? I am trying to load it using LoadLibrary() but I get error code 126 (The specified module could not be found) although the dll is in the project directory (same as executable). I am just wondering if it has to do with the fact it may not be a fully qualified dll for any reason? My exe project is MFC project.
** Update **
Thanks to the comments, I can now load the dll successfully - it was dependencies issue. However GetProcAddress() doesn't return valid pointer for the export function. The dumpbin /exports utility shows the dll has no export functions!
So I have added just .h/cpp files to the original project which has a simple dummy function for export right now.
__declspec(dllexport) int MakeDouble(int value);
I also included the header file in the app class just in case. I am wondering why does this function does't appear as an export? What do I have to do?
First:
__declspec(dllexport) int MakeDouble(int value);
Function declaration should have the same signature than the definition and, of course, the function must have a definition (at simple return 0; should work }
Second:
The exported function name is decorated with beautiful weird characters, you should use extern "C" (or the MS specific stdcall + the .def file).:
//.h
extern "C" __declspec(dllexport) int MakeDouble(int value);
//.cpp
extern "C" __declspec(dllexport) int MakeDouble(int value) {
return 0;
}
You should also check in project properties the option:
Configuration Properties -> C/C++ -> Code Generation -> Runtime Library
Make sure the value contains the word DLL.

c++ one solution two projects (exe & dll) linking error

I have one Visual Studio solution which consists of two win32 projects: 1) application (.exe) 2) functions wrapper (.dll).
The solution is in prototyping stage so all classes/functionality are implemented under (.exe) project - dirty but quick and easy for debugging/testing.
I've started to write a DLL wrapper to "play" with functionality in MSExcel/VBA and faced linking error
error LNK2019: unresolved external symbol "public: __thiscall Date::Date(int,int,int)" (??0Date##QAE#HHH#Z) referenced in function addNumbers
DLL header file:
#ifdef LIBRARYWRAP_EXPORTS
#define LIBRARYWRAP_API __declspec(dllexport)
#else
#define LIBRARYWRAP_API __declspec(dllimport)
#endif
LIBRARYWRAP_API int _stdcall addNumbers(int a, int b);
DLL source file:
#include "..\applicationProject\Date.h"
class Date;
LIBRARYWRAP_API int _stdcall addNumbers(int a, int b){
Date dummyDate(12,1,2014); // <- Linker error LNK2019.
return (a+b);
}
Class Date and constructor Date::Date(int,int,int) are defined in application project(.exe) within Date.h, Date.cpp.
What I've tried to do already:
for librarywrap project added new reference. Project -> Properties -> Common -> Add New Reference. Selected "applicationProject".
added additional include directories: $(SolutionDir)\applicationProject
Two questions:
First, Is that legal/achievable what I'm trying to do? DLL links to application project, whereas usually it should be other way round - application links to DLL. Hypothetically if i have two application projects (.exe) & (.exe) will it be possible to link one to another?
Second, If answer for first question is positive what should I add/change to make it work?
Thanks very much!
Nicholas
Technically, it is possible to make a DLL to call all needed functions from another modules (even from .exe ones - LoadLibrary can do this), but it would be a great pain: you will have to export all needed methods explicitly in the .EXE (just like you export DLL functions) and import them into your DLL. So the answer to the first question is yes, but if the DLL wants to use a lot of entry points from the EXE then probably it is not the best option.
I'd suggest a different approach: having a common code base for both .exe (application) and .dll projects. Then you will be able to test your code by running the application, and to use the functionality from other apps through the DLL (the DLL will contain all the necessary code itself).

Is there an easy way to setup a link seam with Visual Studio 2010's build system?

I used to have a static library which was imported by both my main program and my tests. However, I needed global variables inside of my static library to be constructed, and there's no way to force Visual Studio to do that.
What I'd like to do then is to have a project which compiles all the common C++ files, a project which compiles and links the unit tests (with the common C++ files), and a project which links the actual application.
How can I do this in Visual Studio 2010?
EDIT: Because clarification has been asked, here's what I mean:
InterfaceIUse.hpp
#include <memory>
struct IInterface
{
virtual ~IInterface() {}
virtual void SomethingIDependOn() = 0;
};
std::auto_ptr<IInterface> FactoryMethod();
CodeUnderTest.cpp
#include "InterfaceIUse.hpp"
void FunctionUnderTest()
{
//Blah blah blah
}
IExistOnlyInTheMainProgram.cpp
#include "InterfaceIUse.hpp"
std::auto_ptr<IInterface> FactoryMethod()
{
//I return the real implementation of the interface.
}
IExistOnlyInTheTest.cpp
#include "InterfaceIUse.hpp"
std::auto_ptr<IInterface> FactoryMethod()
{
//I return the mock implementation of the interface.
}
The idea is to compile the right .cpp implementation of the given factory, which will allow the dependencies of the code to be tested to be dependency injected.
Doing this kind of link seam is easy with makefiles -- but makefiles are undesirable because I'm forced to manually maintain header dependencies in the makefile.
I have done similar setup in VS2008, which I think still applicable for you in VS2010.
To start, I setup my project hierarchy as Build, ProductionCodeBase and TestCodeBase.
Common interface/headers are extracted into folder accessible by all projects.
Then in my "Build" project, I manually add object file(s) from ProductionCodeBase into "Release" configuration, and object file(s) from TestCodeBase into "Debug" configuration.
Don't forget to set project dependencies so that object file are valid when linking in "Build".
Do note that you can create project that only compile source code into object files without attempt to link them. Just go to "Tool Build Order" for that particular project and disable corresponding linker.