I created a DLL inside of MV C++ 2012 and when I used
Dumpbin /Exports filename
The name of the function inside of the DLL file has an equal sign inside of it. I had to use Common Language Runtime Support (/crl) because I used a DLL from C#. Is this why the name of the function would show up with an equals sign? My header file:
#ifdef ColorDLL_EXPORTS
#define ColorDLL_API __declspec(dllexport)
#else
#define ColorDLL_API __declspec(dllexport)
#endif
extern "C"{
ColorDLL_API int ColorSelect(int i);
}
ColorDLL.cpp
#include "stdafx.h"
#include "ColorDLL.h"
#using <ColorDiologeClass.dll>
extern "C"{
ColorDLL_API int ColorSelect(){
ColorDiologeClass::Class1::ColorReturn(1);
return 1;
}
}
When I used Dumpbin the name showed up as this:
Name
ColorSelect = _ColorSelect
Why is this? I am expecting it to show up as ColorSelect, not ColorSelect = _ColorSelect. And if I were to leave it this way, how would I call this function from a program like JMP where it needs the exact function name? Would it be ColorSelect? Or would it be ColorSelect = _ColorSelect?
The name is "mangled" - the return type and the parameters are enchoded into the name of the function. Should you wish to NOT have that, you would use extern "C" before the function name (or around a block of functions).
That would be name mangling, which is the under-the-covers feature of c++ that allows it to support function overloading (since it incorporates the argument types of the function into its name).
Here's another question that goes into greater detail.
Microsoft calls this "decorating" instead of mangling. They include a command line tool named "undname" that will produce the original name from the decorated name:
C:\>undname ?ColorSelect##YAHXZ
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.
Undecoration of :- "?ColorSelect##YAHXZ"
is :- "int __cdecl ColorSelect(void)"
If you want to do the same in your own code, you can do that too, using UnDecorateSymbolName.
For what it's worth, decorating/mangling supports not only overloading, but typesafe linking. Typesafe linking stems from function overloading though it isn't really function overloading in itself.
Specifically, typesafe linking deals with (for example) how to deal with C++ code that has overloads of, say, sqrt for float, double, long double, and probably complex as well, but links to a C library that provides a double sqrt(double), but not the other overloads. In this case, we typically want that to be used when the right arguments were/are used, but not otherwise.
This can (or could) arise even without function overloading being involved. For example, in pure C you could do something like this:
#include <stdio.h>
extern int sqrt(int);
// ...
printf("%d", sqrt(100));
Now, we've told the compiler we're using a version of sqrt that takes (and returns) an int. Unfortunately, the linker doesn't realize that, so it still links with the sqrt in the standard library that takes and returns double. As a result, the code above will print some thoroughly useless result (typically 0, not that it matters a lot).
Typesafe linkage prevents that -- even though it isn't exactly function overloading, we still have two functions with the same name, but different types by the time we're linking. By encoding the parameter type(s) into the name, the linker can keep this sorted out just as well as the compiler can.
The same can (and frequently does) arise in C when we have name collisions between different libraries. With a traditional C compiler, straightening out this sort of mess can be extremely difficult (at best). With a C++ compiler, unless the two libraries use not only the same names, but identical number and types of parameters, it's never a problem at all.
Related
Background: As part of a larger assignment I need to make a C# library accessible to unmanaged C++ and C code. In an attempt to answer this question myself I have been learning C++/CLI the past few days/ weeks.
There seems to be a number of different ways to achieve using a C# dll from unmanaged C++ and C. Some of the answers in brief appear to be: using Interlope services, Using .com. and regasm, Using PInvoke (which appears to go from C# to C++ only), and using IJW in the C++/CLR (which appears to be Interlope services). I am thinking it would be best to set up a library that is perhaps a CLR wrapper that uses IJW to call my C# dll on the behalf of native C++ and C code.
Specifics: I need to pass values of string as well as int to a C# dll from c++ code, and return void.
Relevance: Many companies have many excuses to mix and match C++, C and C#. Performance: unmanaged code is usually faster, interfaces: Managed interfaces are generally easier to maintain, deploy, and are often easier on the eyes, Managers tell us too. Legacy code forces us too. It was there (Like the mountain that we climbed). While examples of how to call a C++ library from C# are abundant. Examples of how to call C# libraries from C++ code are difficult to find via Googling especially if you want to see updated 4.0+ code.
Software: C#, C++/CLR, C++, C, Visual Studio 2010, and .NET 4.0
Question details: OK multi-part question:
Is there an advantage to using com objects? Or the PInvoke? Or some other method? (I feel like the learning curve here will be just as steep, even though I do find more information on the topic in Google Land. IJW seems to promise what I want it to do. Should I give up on looking for an IJW solution and focus on this instead?) (Advantage/ disadvantage?)
Am I correct in imagining that there is a solution where I write a wrapper that that utilizes IJW in the C++/CLR? Where can I find more information on this topic, and don’t say I didn’t Google enough/ or look at MSDN without telling me where you saw it there. (I think I prefer this option, in the effort to write clear and simple code.)
A narrowing of question scope: I feel that my true issue and need is answering the smaller question that follows: How do I set up a C++/CLR library that an unmanaged C++ file can use within visual studio. I think that if I could simply instantiate a managed C++ class in unmanaged C++ code, then I might be able work out the rest (interfacing and wrapping etc.). I expect that my main folly is in trying to set up references/#includes etc. within Visual Studio, thought clearly I could have other misconceptions. Perhaps the answer to this whole thing could be just a link to a tutorial or instructions that help me with this.
Research: I have Googled and Binged over and over with some success. I have found many links that show you how to use an unmanaged library from C# code. And I will admit that there have been some links that show how to do it using com objects. Not many results were targeted at VS 2010.
References:
I have read over and over many posts. I have tried to work through the most relevant ones. Some seem tantalizingly close to the answer, but I just can’t seem to get them to work. I suspect that the thing that I am missing is tantalizingly small, such as misusing the keyword ref, or missing a #include or using statement, or a misuse of namespace, or not actually using the IJW feature properly, or missing a setting that VS needs to handle the compilation correctly, etc. So you wonder, why not include the code? Well I feel like I am not at a place where I understand and expect the code I have to work. I want to be in a place where I understand it, when I get there maybe then I'll need help fixing it. I'll randomly include two of the links but I am not permitted to show them all at my current Hitpoint level.
http://www.codeproject.com/Articles/35437/Moving-Data-between-Managed-Code-and-Unmanaged-Cod
This calls code from managed and unmanaged code in both directions going from C++ to Visual Basic and back via C++CLR, and of course I am interested in C#.: http://www.codeproject.com/Articles/9903/Calling-Managed-Code-from-Unmanaged-Code-and-vice
You can do this fairly easily.
Create an .h/.cpp combo
Enable /clr on the newly create .cpp file. (CPP -> Right click -> Properties)
Set the search path for "additional #using directories" to point towards your C# dll.
Native.h
void NativeWrapMethod();
Native.cpp
#using <mscorlib.dll>
#using <MyNet.dll>
using namespace MyNetNameSpace;
void NativeWrapMethod()
{
MyNetNameSpace::MyManagedClass::Method(); // static method
}
That's the basics of using a C# lib from C++\CLI with native code. (Just reference Native.h where needed, and call the function.)
Using C# code with managed C++\CLI code is roughly the same.
There is a lot of misinformation on this subject, so, hopefully this saves someone a lot of hassle. :)
I've done this in: VS2010 - VS2012 (It probably works in VS2008 too.)
UPDATE 2018
It seems like as if the solution does not work for Visual Studio 2017 and onwards. Unfortunately I am currently not working with Visual Studio and therefore cannot update this answer by myself. But kaylee posted an updated version of my answer, thank you!
UPDATE END
If you want to use COM, here's my solution for this problem:
C# library
First of all you need a COM compatible library.
You already got one? Perfect, you can skip this part.
You have access to the library? Make sure it's COM compatible by following the steps.
Make sure that you checked the "Register for COM interop" option in the properties of your project. Properties -> Build -> Scroll down -> Register for COM interop
The following screenshots shows where you find this option.
All the interfaces and classes that should be available need to have a GUID
namespace NamespaceOfYourProject
{
[Guid("add a GUID here")]
public interface IInterface
{
void Connect();
void Disconnect();
}
}
namespace NamespaceOfYourProject
{
[Guid("add a GUID here")]
public class ClassYouWantToUse: IInterface
{
private bool connected;
public void Connect()
{
//add code here
}
public void Disconnect()
{
//add code here
}
}
}
So that's pretty much what you have to do with your C# code. Let's continue with the C++ code.
C++
First of all we need to import the C# library.
After compiling your C# library there should be a .tlb file.
#import "path\to\the\file.tlb"
If you import this new created file to your file.cpp you can use your object as a local variable.
#import "path\to\the\file.tlb"
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
NamespaceOfYourProject::IInterfacePtr yourClass(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));
yourClass->Connect();
CoUninitialize();
}
Using your class as an attribute.
You will noticed that the first step only works with a local variable. The following code shows how to use it as a attribute. Related to this question.
You will need the CComPtr, which is located in atlcomcli.h. Include this file in your header file.
CPlusPlusClass.h
#include <atlcomcli.h>
#import "path\to\the\file.tlb"
class CPlusPlusClass
{
public:
CPlusPlusClass(void);
~CPlusPlusClass(void);
void Connect(void);
private:
CComPtr<NamespaceOfYourProject::IInterface> yourClass;
}
CPlusPlusClass.cpp
CPlusPlusClass::CPlusPlusClass(void)
{
CoInitialize(NULL);
yourClass.CoCreateInstance(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));
}
CPlusPlusClass::~CPlusPlusClass(void)
{
CoUninitialize();
}
void CPlusPlusClass::Connect(void)
{
yourClass->Connect();
}
That's it! Have fun with your C# classes in C++ with COM.
The answer from 0lli.rocks is unfortunately either outdated or incomplete. My co-worker helped me get this working, and to be frank one or two of the implementation details were not remotely obvious. This answer rectifies the gaps and should be directly copyable into Visual Studio 2017 for your own use.
Caveats: I haven't been able to get this working for C++/WinRT, just an FYI. All sorts of compile errors due to ambiguity of the IUnknown interface. I was also having problems getting this to work for just a library implementation instead of using it in the main of the app. I tried following the instructions from 0lli.rocks for that specifically, but was never able to get it compiling.
Step 01: Create your C# Library
Here's the one we'll be using for the demo:
using System;
using System.Runtime.InteropServices;
namespace MyCSharpClass
{
[ComVisible(true)] // Don't forget
[ClassInterface(ClassInterfaceType.AutoDual)] // these two lines
[Guid("485B98AF-53D4-4148-B2BD-CC3920BF0ADF")] // or this GUID
public class TheClass
{
public String GetTheThing(String arg) // Make sure this is public
{
return arg + "the thing";
}
}
}
Step 02 - Configure your C# library for COM-visibility
Sub-Step A - Register for COM interoperability
Sub-Step B - Make the assembly COM-visible
Step 3 - Build your Library for the .tlb file
You probably want to just do this as Release for AnyCPU unless you really need something more specific.
Step 4 - Copy the .tlb file into the source location for your C++ project
Step 5 - Import the .tlb file into your C++ project
#include "pch.h"
#include <iostream>
#include <Windows.h>
#import "MyCSharpClass.tlb" raw_interfaces_only
int wmain() {
return 0;
}
Step 6 - Don't panic when Intellisense fails
It will still build. You're going to see even more red-lined code once we implement the actual class into the C++ project.
Step 7 - Build your C++ project to generate the .tlh file
This file will go into your intermediate object build directory once you build the first time
Step 8 - Assess the .tlh file for implementation instructions
This is the .tlh file that is generated in the intermediate object folder. Don't edit it.
// Created by Microsoft (R) C/C++ Compiler Version 14.15.26730.0 (333f2c26).
//
// c:\users\user name\source\repos\consoleapplication6\consoleapplication6\debug\mycsharpclass.tlh
//
// C++ source equivalent of Win32 type library MyCSharpClass.tlb
// compiler-generated file created 10/26/18 at 14:04:14 - DO NOT EDIT!
//
// Cross-referenced type libraries:
//
// #import "C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb"
//
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
namespace MyCSharpClass {
//
// Forward references and typedefs
//
struct __declspec(uuid("48b51671-5200-4e47-8914-eb1bd0200267"))
/* LIBID */ __MyCSharpClass;
struct /* coclass */ TheClass;
struct __declspec(uuid("1ed1036e-c4ae-31c1-8846-5ac75029cb93"))
/* dual interface */ _TheClass;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(_TheClass, __uuidof(_TheClass));
//
// Type library items
//
struct __declspec(uuid("485b98af-53d4-4148-b2bd-cc3920bf0adf"))
TheClass;
// [ default ] interface _TheClass
// interface _Object
struct __declspec(uuid("1ed1036e-c4ae-31c1-8846-5ac75029cb93"))
_TheClass : IDispatch
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall get_ToString (
/*[out,retval]*/ BSTR * pRetVal ) = 0;
virtual HRESULT __stdcall Equals (
/*[in]*/ VARIANT obj,
/*[out,retval]*/ VARIANT_BOOL * pRetVal ) = 0;
virtual HRESULT __stdcall GetHashCode (
/*[out,retval]*/ long * pRetVal ) = 0;
virtual HRESULT __stdcall GetType (
/*[out,retval]*/ struct _Type * * pRetVal ) = 0;
virtual HRESULT __stdcall GetTheThing (
/*[in]*/ BSTR arg,
/*[out,retval]*/ BSTR * pRetVal ) = 0;
};
} // namespace MyCSharpClass
#pragma pack(pop)
In that file, we see these lines for the public method we want to use:
virtual HRESULT __stdcall GetTheThing (
/*[in]*/ BSTR arg,
/*[out,retval]*/ BSTR * pRetVal ) = 0;
That means that the imported method will expect an input-string of type BSTR, and a pointer to a BSTR for the output string that the imported method will return on success. You can set them up like this, for example:
BSTR thing_to_send = ::SysAllocString(L"My thing, or ... ");
BSTR returned_thing;
Before we can use the imported method, we will have to construct it. From the .tlh file, we see these lines:
namespace MyCSharpClass {
//
// Forward references and typedefs
//
struct __declspec(uuid("48b51671-5200-4e47-8914-eb1bd0200267"))
/* LIBID */ __MyCSharpClass;
struct /* coclass */ TheClass;
struct __declspec(uuid("1ed1036e-c4ae-31c1-8846-5ac75029cb93"))
/* dual interface */ _TheClass;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(_TheClass, __uuidof(_TheClass));
//
// Type library items
//
struct __declspec(uuid("485b98af-53d4-4148-b2bd-cc3920bf0adf"))
TheClass;
// [ default ] interface _TheClass
// interface _Object
First, we need to use the namespace of the class, which is MyCSharpClass
Next, we need to determine the the smart pointer from the namespace, which is _TheClass + Ptr ; this step is not remotely obvious, as it's nowhere in the .tlh file.
Last, we need to provide the correct construction parameter for the class, which is __uuidof(MyCSharpClass::TheClass)
Ending up with,
MyCSharpClass::_TheClassPtr obj(__uuidof(MyCSharpClass::TheClass));
Step 9 - Initialize COM and test the imported library
You can do that with CoInitialize(0) or whatever your specific COM initializer happens to be.
#include "pch.h"
#include <iostream>
#include <Windows.h>
#import "MyCSharpClass.tlb" raw_interfaces_only
int wmain() {
CoInitialize(0); // Init COM
BSTR thing_to_send = ::SysAllocString(L"My thing, or ... ");
BSTR returned_thing;
MyCSharpClass::_TheClassPtr obj(__uuidof(MyCSharpClass::TheClass));
HRESULT hResult = obj->GetTheThing(thing_to_send, &returned_thing);
if (hResult == S_OK) {
std::wcout << returned_thing << std::endl;
return 0;
}
return 1;
}
Once again, don't panic when Intellisense freaks out. You're in Black Magic, Voodoo, & Thar Be Dragons territory, so press onward!
The absolute best way I have found to do this is create a c++/cli bridge that connects the c# code to your native C++. You can do this with 3 different projects.
First Project: C# library
Second Project: C++/CLI bridge (this wraps the C# library)
Third Project: Native C++ application that uses the second project
I recently created a simple GitHub Tutorial for how to do this here. Reading through that code with a little grit and you should be able to hammer out creating a C++/CLI bridge that allows you to use C# code in your native C++.
As a bonus I added how to wrap a C# event down to a function pointer in C++ that you can subscribe to.
I found something that at least begins to answer my own question. The following two links have wmv files from Microsoft that demonstrate using a C# class in unmanaged C++.
This first one uses a COM object and regasm: http://msdn.microsoft.com/en-us/vstudio/bb892741.
This second one uses the features of C++/CLI to wrap the C# class: http://msdn.microsoft.com/en-us/vstudio/bb892742. I have been able to instantiate a c# class from managed code and retrieve a string as in the video. It has been very helpful but it only answers 2/3rds of my question as I want to instantiate a class with a string perimeter into a c# class. As a proof of concept I altered the code presented in the example for the following method, and achieved this goal. Of course I also added a altered the {public string PickDate(string Name)} method to do something with the name string to prove to myself that it worked.
wchar_t * DatePickerClient::pick(std::wstring nme)
{
IntPtr temp(ref);// system int pointer from a native int
String ^date;// tracking handle to a string (managed)
String ^name;// tracking handle to a string (managed)
name = gcnew String(nme.c_str());
wchar_t *ret;// pointer to a c++ string
GCHandle gch;// garbage collector handle
DatePicker::DatePicker ^obj;// reference the c# object with tracking handle(^)
gch = static_cast<GCHandle>(temp);// converted from the int pointer
obj = static_cast<DatePicker::DatePicker ^>(gch.Target);
date = obj->PickDate(name);
ret = new wchar_t[date->Length +1];
interior_ptr<const wchar_t> p1 = PtrToStringChars(date);// clr pointer that acts like pointer
pin_ptr<const wchar_t> p2 = p1;// pin the pointer to a location as clr pointers move around in memory but c++ does not know about that.
wcscpy_s(ret, date->Length +1, p2);
return ret;
}
Part of my question was: What is better? From what I have read in many many efforts to research the answer is that COM objects are considered easier to use, and using a wrapper instead allows for greater control. In some cases using a wrapper can (but not always) reduce the size of the thunk, as COM objects automatically have a standard size footprint and wrappers are only as big as they need to be.
The thunk (as I have used above) refers to the space time and resources used in between C# and C++ in the case of the COM object, and in between C++/CLI and native C++ in the case of coding-using a C++/CLI Wrapper. So another part of my answer should include a warning that crossing the thunk boundary more than absolutely necessary is bad practice, accessing the thunk boundary inside a loop is not recommended, and that it is possible to set up a wrapper incorrectly so that it double thunks (crosses the boundary twice where only one thunk is called for) without the code seeming to be incorrect to a novice like me.
Two notes about the wmv's. First: some footage is reused in both, don't be fooled. At first they seem the same but they do cover different topics. Second, there are some bonus features such as marshalling that are now a part of the CLI that are not covered in the wmv's.
Edit:
Note there is a consequence for your installs, your c++ wrapper will not be found by the CLR. You will have to either confirm that the c++ application installs in any/every directory that uses it, or add the library (which will then need to be strongly named) to the GAC at install time. This also means that with either case in development environments you will likely have to copy the library to each directory where applications call it.
I did a bunch of looking around and found a relatively recent article by Microsoft detailing how it can be done (there is a lot of old infomration floating around). From the article itself:
The code sample uses the CLR 4 hosting APIs to host CLR in a native C++ project, load and invoke .NET assemblies
https://code.msdn.microsoft.com/CppHostCLR-e6581ee0
Basically it describes it in two steps:
Load the CLR into a process
Load your assembly.
I wrote a native C++ library that does some math and simulations using Visual Studio 2013. I'd like to have this library easily usable from VBA and .NET (C#). Being able to easily call it from pure C would be also desired, but not necessary.
The internals of the library are quite complex and I want to expose a facade library for the clients. The API will have just a couple of functions (about 5). Each of the functions will only take 2 pointers as parameters - input and output structures.
My first idea was to create a COM DLL in C++. It seems to be easy to integrate with a COM DLL from VBA and C#. Calling COM from pure C is also possible. But I read the creating COM DLLs in C++ is painful, so I dropped that idea.
My next idea is to create a pure C DLL. I'll define the functions and all input and output nested structs in a C header file, so it's reusable both from C and C++. Here's an excerpt:
#pragma pack(push)
#define MF_MAX_PERIODS 240
#define MF_MAX_REGIONS 60
typedef enum mf_agency_model_type { FNMA, FHLMC } mf_agency_model_type;
/* BEGIN OF INPUT DATA STRUCTURES */
/* VBA structs are packed to 4 byte boundaries. */
#pragma pack(4)
typedef struct mf_boarding_loans {
int regions_count;
double timeline[MF_MAX_REGIONS];
} mf_boarding_loans;
#pragma pack(4)
typedef struct mf_agency_model_input {
mf_agency_model_type model_type;
int periods_count;
mf_boarding_loans boarding_loans;
} mf_agency_model_input;
/* BEGIN OF OUTPUT DATA STRUCTURES */
#pragma pack(4)
typedef struct mf_curves {
double dd_90_rate[MF_MAX_PERIODS];
double dd_60_rate[MF_MAX_PERIODS];
} mf_curves;
#pragma pack(4)
typedef struct mf_agency_model_output{
double wal_years;
mf_curves curves;
} mf_agency_model_output;
#pragma pack(pop)
/* BEGIN OF EXTERN FUNCTIONS */
#ifdef __cplusplus
extern "C" {
#endif
/* VBA requires _stdcall calling convention. */
MFLIB_API void _stdcall mf_run_agency_model(mf_agency_model_input *model_input, mf_agency_model_output *model_output);
#ifdef __cplusplus
}
#endif
It should be possible to call such a DLL from C/C++, VBA (via DECLARE) and C# (via PInvoke). The problem is the amount of input and output data. Ultimately, my input data structures will contain about 70 parameters (numbers and arrays of numbers), and the outputs will contain about 100 variables (also numbers and arrays of numbers). I presume that I'd have to declare the same structures both in VBA and C# again and I'd really like to avoid that. (I think I could avoid the declaration in VBA if I expose the C# code as COM to VBA. It seems to be very easy to impelement COM in C#.) My goal is to define the structures only once. Here are my questions:
1) I quickly read about C++/CLI. Could C++/CLI compile my C header to .NET MSIL so it's usable from other .NET languages without any wrappers? I think there will still be a problem with exposing the object to VBA via COM, since it requires some attributes to be added to classes/interfaces, but macros should help here.
2) Is there a tool that will generate for me the structures declarations in VBA and C# from the C code? I'm also OK with having to declare the structures in some meta language and generate C, VBA and C# structures from that.
3) Is it better to define my arrays as fixed size in C or just raw pointers? I read somewhere that it's easier for interop if the arrays have fixed size.
4) Is it better to include the child structures in the parent directly or via pointers from the interop perspective?
Is there any other way that will free me from redefining the huge data structures in multiple languages?
Thanks for your help,
Michal
Keep getting the following error when trying to call a subroutine stored in a Fortran DLL from a C# console application: "An unhandled exception of type 'System.EntryPointNotFoundException' occurred in name.exe Additional information: Unable to find an entry point named 'Fortran_Subroutine' in DLL 'Fortran.dll'" Nearly all of the posts related to this error message pertain to C#/C++. The Fortran project has a post-build event that copies the DLL over to the C# project (CSharp_proj\bin\debug).
The Fortran code uses two calls to !DEC$, do they look OK?:
C
MODULE MF_DLL
C
CONTAINS
C
SUBROUTINE MFNWT_INIT()
C
!DEC$ ATTRIBUTES DLLEXPORT :: MFNWT_INIT
!DEC$ ATTRIBUTES DECORATE, ALIAS: "MFNWT_INIT"
C
USE GLOBAL
...(do stuff)
RETURN
END SUBROUTINE MFNWT_INIT
The C# code that calls the fortran, does the DLLImport call look OK?:
using System.Runtime.InteropServices;
public static class CustomMODSIM
{
public static Model myModel = new Model();
private static SortedList myStreamNodes;
public static void Main(string[] CmdArgs)
{
string FileName = CmdArgs[0];
myModel.Init += OnInitialize;
...(do more stuff)...
//Function call that will invoke "OnInitialize" below
myProgram.RunSolver(myModel);
}
private static void OnInitialize()
{
//call Fortran function
MFNWT_INIT();
//Initialize list of stream nodes
myStreamNodes = new SortedList();
Node m_Node = myModel.FindNode("NonStorage1");
...(do more stuff)
}
//Fortran DLL interface
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern void MFNWT_INIT();
}
Your second compiler directive (the second !DEC$ line) is incorrect - it is missing the :: MFNWT_INIT part that designates which Fortran thing has the nominated attributes (DECORATE and ALIAS). I would expect the compiler to issue a warning about the syntax problem.
For what its worth (assuming you are using a version of ifort >= 11 or so and not one of its ancestors): given you want to use the C calling convention, you are better off getting rid of that second directive completely, and just using the suffix BIND(C,NAME="MFNWT_INIT") on the SUBROUTINE statement.
Most likely the DLL is exporting the function with a decorated name. Find out what that name is and use it on the C# side.
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.Cdecl,
EntryPoint="DecoratedNameGoesHere")]
public static extern void MFNWT_INIT();
To find the exported name use a tool like dumpbin or Dependency Walker.
Are you quite sure that your DLL uses the cdecl calling convention?
In the IVF Help, have a look at Building Applications/Programming with Mixed Languages/Adjusting calling conventions in Mixed Languages/Attributes properties and calling conventions. That is where it is on Version 11. It may have moved in the version you are using. The confusing bit in the help is whether the exported symbol is upper or lowercase. It is only slightly different from the one written for the old MS Fortran 77 compiler (circa 1986). If you are unsure the exported symbols, use depends to find out what they are.
1) If you are not using an alias, then it should look like this on the Fortran side
MODULE MF_DLL
CONTAINS
SUBROUTINE MFNWT_INIT()
!DEC$ ATTRIBUTES STDCALL, DLLEXPORT :: MFNWT_INIT
If STDCALL is used, there will be two exported symbols: MF_DLL_mp_MFNWT_INIT and _MF_DLL_mp_MFNWT_INIT#0. If STDCALL is not specified, it defaults to C. In that case you will only MF_DLL_mp_MFNWT_INIT. The number after the # sign is the number of bytes on the stack that the routine needs to remove before returning to the caller. You will not get this in C decl because it is the responsibility of the caller.
2) On the C# side using stdcall
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.StdCall,
EntryPoint="_MF_DLL_mp_MFNWT_INIT#0")]
public static extern void MFNWT_INIT();
3) On the C# side using Cdecl
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.Cdecl,
EntryPoint="MF_DLL_mp_MFNWT_INIT")]
public static extern void MFNWT_INIT();
The difference is that in C, it does not need to know the number of parameters whereas in stdcall it does. This affects the stacking/unstacking of parameters. If this goes wrong, it will make the call, run the Fortran routine and then crash on exit. In your case, it doesn't really matter because there are no parameters but it is nice to get it right.
4) If an alias is used, the name changes but not the calling convention. In your case, you should have specified
! ,-- This is the name in DLL export
!DEC$ ATTRIBUTES DECORATE, ALIAS: "MFNWT_INIT"::MFNWT_INIT
With C decl, you will get MFNWT_INIT.
With STDCALL, you will get MFNWT_INIT and _MFNWT_INIT#0
On the C# side the entry point is not needed when C Decl is used. It is only needed when STDCALL is used.
5) If the routine is used in both Fortran and C# then it would be better to stick to stdcall.
Background: As part of a larger assignment I need to make a C# library accessible to unmanaged C++ and C code. In an attempt to answer this question myself I have been learning C++/CLI the past few days/ weeks.
There seems to be a number of different ways to achieve using a C# dll from unmanaged C++ and C. Some of the answers in brief appear to be: using Interlope services, Using .com. and regasm, Using PInvoke (which appears to go from C# to C++ only), and using IJW in the C++/CLR (which appears to be Interlope services). I am thinking it would be best to set up a library that is perhaps a CLR wrapper that uses IJW to call my C# dll on the behalf of native C++ and C code.
Specifics: I need to pass values of string as well as int to a C# dll from c++ code, and return void.
Relevance: Many companies have many excuses to mix and match C++, C and C#. Performance: unmanaged code is usually faster, interfaces: Managed interfaces are generally easier to maintain, deploy, and are often easier on the eyes, Managers tell us too. Legacy code forces us too. It was there (Like the mountain that we climbed). While examples of how to call a C++ library from C# are abundant. Examples of how to call C# libraries from C++ code are difficult to find via Googling especially if you want to see updated 4.0+ code.
Software: C#, C++/CLR, C++, C, Visual Studio 2010, and .NET 4.0
Question details: OK multi-part question:
Is there an advantage to using com objects? Or the PInvoke? Or some other method? (I feel like the learning curve here will be just as steep, even though I do find more information on the topic in Google Land. IJW seems to promise what I want it to do. Should I give up on looking for an IJW solution and focus on this instead?) (Advantage/ disadvantage?)
Am I correct in imagining that there is a solution where I write a wrapper that that utilizes IJW in the C++/CLR? Where can I find more information on this topic, and don’t say I didn’t Google enough/ or look at MSDN without telling me where you saw it there. (I think I prefer this option, in the effort to write clear and simple code.)
A narrowing of question scope: I feel that my true issue and need is answering the smaller question that follows: How do I set up a C++/CLR library that an unmanaged C++ file can use within visual studio. I think that if I could simply instantiate a managed C++ class in unmanaged C++ code, then I might be able work out the rest (interfacing and wrapping etc.). I expect that my main folly is in trying to set up references/#includes etc. within Visual Studio, thought clearly I could have other misconceptions. Perhaps the answer to this whole thing could be just a link to a tutorial or instructions that help me with this.
Research: I have Googled and Binged over and over with some success. I have found many links that show you how to use an unmanaged library from C# code. And I will admit that there have been some links that show how to do it using com objects. Not many results were targeted at VS 2010.
References:
I have read over and over many posts. I have tried to work through the most relevant ones. Some seem tantalizingly close to the answer, but I just can’t seem to get them to work. I suspect that the thing that I am missing is tantalizingly small, such as misusing the keyword ref, or missing a #include or using statement, or a misuse of namespace, or not actually using the IJW feature properly, or missing a setting that VS needs to handle the compilation correctly, etc. So you wonder, why not include the code? Well I feel like I am not at a place where I understand and expect the code I have to work. I want to be in a place where I understand it, when I get there maybe then I'll need help fixing it. I'll randomly include two of the links but I am not permitted to show them all at my current Hitpoint level.
http://www.codeproject.com/Articles/35437/Moving-Data-between-Managed-Code-and-Unmanaged-Cod
This calls code from managed and unmanaged code in both directions going from C++ to Visual Basic and back via C++CLR, and of course I am interested in C#.: http://www.codeproject.com/Articles/9903/Calling-Managed-Code-from-Unmanaged-Code-and-vice
You can do this fairly easily.
Create an .h/.cpp combo
Enable /clr on the newly create .cpp file. (CPP -> Right click -> Properties)
Set the search path for "additional #using directories" to point towards your C# dll.
Native.h
void NativeWrapMethod();
Native.cpp
#using <mscorlib.dll>
#using <MyNet.dll>
using namespace MyNetNameSpace;
void NativeWrapMethod()
{
MyNetNameSpace::MyManagedClass::Method(); // static method
}
That's the basics of using a C# lib from C++\CLI with native code. (Just reference Native.h where needed, and call the function.)
Using C# code with managed C++\CLI code is roughly the same.
There is a lot of misinformation on this subject, so, hopefully this saves someone a lot of hassle. :)
I've done this in: VS2010 - VS2012 (It probably works in VS2008 too.)
UPDATE 2018
It seems like as if the solution does not work for Visual Studio 2017 and onwards. Unfortunately I am currently not working with Visual Studio and therefore cannot update this answer by myself. But kaylee posted an updated version of my answer, thank you!
UPDATE END
If you want to use COM, here's my solution for this problem:
C# library
First of all you need a COM compatible library.
You already got one? Perfect, you can skip this part.
You have access to the library? Make sure it's COM compatible by following the steps.
Make sure that you checked the "Register for COM interop" option in the properties of your project. Properties -> Build -> Scroll down -> Register for COM interop
The following screenshots shows where you find this option.
All the interfaces and classes that should be available need to have a GUID
namespace NamespaceOfYourProject
{
[Guid("add a GUID here")]
public interface IInterface
{
void Connect();
void Disconnect();
}
}
namespace NamespaceOfYourProject
{
[Guid("add a GUID here")]
public class ClassYouWantToUse: IInterface
{
private bool connected;
public void Connect()
{
//add code here
}
public void Disconnect()
{
//add code here
}
}
}
So that's pretty much what you have to do with your C# code. Let's continue with the C++ code.
C++
First of all we need to import the C# library.
After compiling your C# library there should be a .tlb file.
#import "path\to\the\file.tlb"
If you import this new created file to your file.cpp you can use your object as a local variable.
#import "path\to\the\file.tlb"
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
NamespaceOfYourProject::IInterfacePtr yourClass(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));
yourClass->Connect();
CoUninitialize();
}
Using your class as an attribute.
You will noticed that the first step only works with a local variable. The following code shows how to use it as a attribute. Related to this question.
You will need the CComPtr, which is located in atlcomcli.h. Include this file in your header file.
CPlusPlusClass.h
#include <atlcomcli.h>
#import "path\to\the\file.tlb"
class CPlusPlusClass
{
public:
CPlusPlusClass(void);
~CPlusPlusClass(void);
void Connect(void);
private:
CComPtr<NamespaceOfYourProject::IInterface> yourClass;
}
CPlusPlusClass.cpp
CPlusPlusClass::CPlusPlusClass(void)
{
CoInitialize(NULL);
yourClass.CoCreateInstance(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));
}
CPlusPlusClass::~CPlusPlusClass(void)
{
CoUninitialize();
}
void CPlusPlusClass::Connect(void)
{
yourClass->Connect();
}
That's it! Have fun with your C# classes in C++ with COM.
The answer from 0lli.rocks is unfortunately either outdated or incomplete. My co-worker helped me get this working, and to be frank one or two of the implementation details were not remotely obvious. This answer rectifies the gaps and should be directly copyable into Visual Studio 2017 for your own use.
Caveats: I haven't been able to get this working for C++/WinRT, just an FYI. All sorts of compile errors due to ambiguity of the IUnknown interface. I was also having problems getting this to work for just a library implementation instead of using it in the main of the app. I tried following the instructions from 0lli.rocks for that specifically, but was never able to get it compiling.
Step 01: Create your C# Library
Here's the one we'll be using for the demo:
using System;
using System.Runtime.InteropServices;
namespace MyCSharpClass
{
[ComVisible(true)] // Don't forget
[ClassInterface(ClassInterfaceType.AutoDual)] // these two lines
[Guid("485B98AF-53D4-4148-B2BD-CC3920BF0ADF")] // or this GUID
public class TheClass
{
public String GetTheThing(String arg) // Make sure this is public
{
return arg + "the thing";
}
}
}
Step 02 - Configure your C# library for COM-visibility
Sub-Step A - Register for COM interoperability
Sub-Step B - Make the assembly COM-visible
Step 3 - Build your Library for the .tlb file
You probably want to just do this as Release for AnyCPU unless you really need something more specific.
Step 4 - Copy the .tlb file into the source location for your C++ project
Step 5 - Import the .tlb file into your C++ project
#include "pch.h"
#include <iostream>
#include <Windows.h>
#import "MyCSharpClass.tlb" raw_interfaces_only
int wmain() {
return 0;
}
Step 6 - Don't panic when Intellisense fails
It will still build. You're going to see even more red-lined code once we implement the actual class into the C++ project.
Step 7 - Build your C++ project to generate the .tlh file
This file will go into your intermediate object build directory once you build the first time
Step 8 - Assess the .tlh file for implementation instructions
This is the .tlh file that is generated in the intermediate object folder. Don't edit it.
// Created by Microsoft (R) C/C++ Compiler Version 14.15.26730.0 (333f2c26).
//
// c:\users\user name\source\repos\consoleapplication6\consoleapplication6\debug\mycsharpclass.tlh
//
// C++ source equivalent of Win32 type library MyCSharpClass.tlb
// compiler-generated file created 10/26/18 at 14:04:14 - DO NOT EDIT!
//
// Cross-referenced type libraries:
//
// #import "C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb"
//
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
namespace MyCSharpClass {
//
// Forward references and typedefs
//
struct __declspec(uuid("48b51671-5200-4e47-8914-eb1bd0200267"))
/* LIBID */ __MyCSharpClass;
struct /* coclass */ TheClass;
struct __declspec(uuid("1ed1036e-c4ae-31c1-8846-5ac75029cb93"))
/* dual interface */ _TheClass;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(_TheClass, __uuidof(_TheClass));
//
// Type library items
//
struct __declspec(uuid("485b98af-53d4-4148-b2bd-cc3920bf0adf"))
TheClass;
// [ default ] interface _TheClass
// interface _Object
struct __declspec(uuid("1ed1036e-c4ae-31c1-8846-5ac75029cb93"))
_TheClass : IDispatch
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall get_ToString (
/*[out,retval]*/ BSTR * pRetVal ) = 0;
virtual HRESULT __stdcall Equals (
/*[in]*/ VARIANT obj,
/*[out,retval]*/ VARIANT_BOOL * pRetVal ) = 0;
virtual HRESULT __stdcall GetHashCode (
/*[out,retval]*/ long * pRetVal ) = 0;
virtual HRESULT __stdcall GetType (
/*[out,retval]*/ struct _Type * * pRetVal ) = 0;
virtual HRESULT __stdcall GetTheThing (
/*[in]*/ BSTR arg,
/*[out,retval]*/ BSTR * pRetVal ) = 0;
};
} // namespace MyCSharpClass
#pragma pack(pop)
In that file, we see these lines for the public method we want to use:
virtual HRESULT __stdcall GetTheThing (
/*[in]*/ BSTR arg,
/*[out,retval]*/ BSTR * pRetVal ) = 0;
That means that the imported method will expect an input-string of type BSTR, and a pointer to a BSTR for the output string that the imported method will return on success. You can set them up like this, for example:
BSTR thing_to_send = ::SysAllocString(L"My thing, or ... ");
BSTR returned_thing;
Before we can use the imported method, we will have to construct it. From the .tlh file, we see these lines:
namespace MyCSharpClass {
//
// Forward references and typedefs
//
struct __declspec(uuid("48b51671-5200-4e47-8914-eb1bd0200267"))
/* LIBID */ __MyCSharpClass;
struct /* coclass */ TheClass;
struct __declspec(uuid("1ed1036e-c4ae-31c1-8846-5ac75029cb93"))
/* dual interface */ _TheClass;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(_TheClass, __uuidof(_TheClass));
//
// Type library items
//
struct __declspec(uuid("485b98af-53d4-4148-b2bd-cc3920bf0adf"))
TheClass;
// [ default ] interface _TheClass
// interface _Object
First, we need to use the namespace of the class, which is MyCSharpClass
Next, we need to determine the the smart pointer from the namespace, which is _TheClass + Ptr ; this step is not remotely obvious, as it's nowhere in the .tlh file.
Last, we need to provide the correct construction parameter for the class, which is __uuidof(MyCSharpClass::TheClass)
Ending up with,
MyCSharpClass::_TheClassPtr obj(__uuidof(MyCSharpClass::TheClass));
Step 9 - Initialize COM and test the imported library
You can do that with CoInitialize(0) or whatever your specific COM initializer happens to be.
#include "pch.h"
#include <iostream>
#include <Windows.h>
#import "MyCSharpClass.tlb" raw_interfaces_only
int wmain() {
CoInitialize(0); // Init COM
BSTR thing_to_send = ::SysAllocString(L"My thing, or ... ");
BSTR returned_thing;
MyCSharpClass::_TheClassPtr obj(__uuidof(MyCSharpClass::TheClass));
HRESULT hResult = obj->GetTheThing(thing_to_send, &returned_thing);
if (hResult == S_OK) {
std::wcout << returned_thing << std::endl;
return 0;
}
return 1;
}
Once again, don't panic when Intellisense freaks out. You're in Black Magic, Voodoo, & Thar Be Dragons territory, so press onward!
The absolute best way I have found to do this is create a c++/cli bridge that connects the c# code to your native C++. You can do this with 3 different projects.
First Project: C# library
Second Project: C++/CLI bridge (this wraps the C# library)
Third Project: Native C++ application that uses the second project
I recently created a simple GitHub Tutorial for how to do this here. Reading through that code with a little grit and you should be able to hammer out creating a C++/CLI bridge that allows you to use C# code in your native C++.
As a bonus I added how to wrap a C# event down to a function pointer in C++ that you can subscribe to.
I found something that at least begins to answer my own question. The following two links have wmv files from Microsoft that demonstrate using a C# class in unmanaged C++.
This first one uses a COM object and regasm: http://msdn.microsoft.com/en-us/vstudio/bb892741.
This second one uses the features of C++/CLI to wrap the C# class: http://msdn.microsoft.com/en-us/vstudio/bb892742. I have been able to instantiate a c# class from managed code and retrieve a string as in the video. It has been very helpful but it only answers 2/3rds of my question as I want to instantiate a class with a string perimeter into a c# class. As a proof of concept I altered the code presented in the example for the following method, and achieved this goal. Of course I also added a altered the {public string PickDate(string Name)} method to do something with the name string to prove to myself that it worked.
wchar_t * DatePickerClient::pick(std::wstring nme)
{
IntPtr temp(ref);// system int pointer from a native int
String ^date;// tracking handle to a string (managed)
String ^name;// tracking handle to a string (managed)
name = gcnew String(nme.c_str());
wchar_t *ret;// pointer to a c++ string
GCHandle gch;// garbage collector handle
DatePicker::DatePicker ^obj;// reference the c# object with tracking handle(^)
gch = static_cast<GCHandle>(temp);// converted from the int pointer
obj = static_cast<DatePicker::DatePicker ^>(gch.Target);
date = obj->PickDate(name);
ret = new wchar_t[date->Length +1];
interior_ptr<const wchar_t> p1 = PtrToStringChars(date);// clr pointer that acts like pointer
pin_ptr<const wchar_t> p2 = p1;// pin the pointer to a location as clr pointers move around in memory but c++ does not know about that.
wcscpy_s(ret, date->Length +1, p2);
return ret;
}
Part of my question was: What is better? From what I have read in many many efforts to research the answer is that COM objects are considered easier to use, and using a wrapper instead allows for greater control. In some cases using a wrapper can (but not always) reduce the size of the thunk, as COM objects automatically have a standard size footprint and wrappers are only as big as they need to be.
The thunk (as I have used above) refers to the space time and resources used in between C# and C++ in the case of the COM object, and in between C++/CLI and native C++ in the case of coding-using a C++/CLI Wrapper. So another part of my answer should include a warning that crossing the thunk boundary more than absolutely necessary is bad practice, accessing the thunk boundary inside a loop is not recommended, and that it is possible to set up a wrapper incorrectly so that it double thunks (crosses the boundary twice where only one thunk is called for) without the code seeming to be incorrect to a novice like me.
Two notes about the wmv's. First: some footage is reused in both, don't be fooled. At first they seem the same but they do cover different topics. Second, there are some bonus features such as marshalling that are now a part of the CLI that are not covered in the wmv's.
Edit:
Note there is a consequence for your installs, your c++ wrapper will not be found by the CLR. You will have to either confirm that the c++ application installs in any/every directory that uses it, or add the library (which will then need to be strongly named) to the GAC at install time. This also means that with either case in development environments you will likely have to copy the library to each directory where applications call it.
I did a bunch of looking around and found a relatively recent article by Microsoft detailing how it can be done (there is a lot of old infomration floating around). From the article itself:
The code sample uses the CLR 4 hosting APIs to host CLR in a native C++ project, load and invoke .NET assemblies
https://code.msdn.microsoft.com/CppHostCLR-e6581ee0
Basically it describes it in two steps:
Load the CLR into a process
Load your assembly.
My problem is , i have some functions in a DLL some of these functions are for example :
#include <string>
using namespace std;
extern "C" __declspec(dllexport) string __cdecl encryption(string s)
{
return s;
}
Whenever i try to call this function from C# , here is the code im using :
[DllImport("Packer.dll", EntryPoint = "encryption")]
static extern string encryption(string s);
i get an error :
A call to PInvoke function 'Packer' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
im guessing i get this error because i dont have the right declarations for the function
can anyone guide me how to fix that , thanks in advance
std::string can not be used with PInvoke, because C++ does not have an ABI for its objects which is required to properly clean stack, copy objects, etc. This is one of the greatest pains of C++.
You have to use char* pointers and plain C APIs. Simply put, PInvoke does not work with C++.
As I'm sure you already know, the C++ std::string is actually a template. Only when the template is instantiated (as std::basic_string<char> in this case), the exact layout of the objects of that type and signatures of the methods are determined by the C++ compiler.
Unfortunately, only the C++ compiler in question has the access to all the relevant information (such as template source code) to make these kinds of decisions. That's why non-C features such as templates are generally not "transferable" even between different C++ compilers, let alone C++ and C#.
Also, C++ names are typically "mangled" in a C++ compiler-specific manner.
You'll have to change the signature of your native method, so it is becomes a "pure" C function:
Ensure there is no C++ name mangling by declaring the function as extern "C" (you are already doing that).
Use char* parameter instead of std::string.
Return char* result instead of std::string, but be very careful how you do it.
Ensure your DllImportAttribute.CallingConvention matches the __cdecl, __stdcall or __fastcall in your C.
The problem here is, you're using the STL string class which C# doesn't know how to marshal. You have two options here:
refactor your C++ code to work with char * buffers. Or write a wrapper or an overload or something that uses char * instead of string.
Write a C++/CLI wrapper around your C++ functions that uses System::String and calls the STL string versions internally.
If memory serves, if you don't specify otherwise P/Invoke assumes the calling convention is __stdcall. If so, changing your __cdecl to __stdcall should fix the first problem.
As #Adam Rosenfield points out, you probably also need to pass and return a char const *, not a string. C# and C++ almost certainly have somewhat different ideas of what constitutes a string.