Writing a DLL in C/C++ for .Net interoperability - c#

In my C# application, I would like to write a part of the code in C.
I plan to write a DLL witch would be interoperable with .Net.
How can I do that?

There are essentially three right ways to do it:
Use C++/CLI. This is the optimal way if this DLL is going to be used only by .NET.
Use an "extern "C"" compatible API, like the Windows API itself. This is the most portable, but isn't as convenient for your callers as using a class model to represent your objects.
This is the best option if you really intend to write in ANSI C (not C++).
For this path, you write your functions as extern "C" returntype __stdcall __declspec(dllexport) func(params) { ... }
You should also use a "caller-provides-the-buffer" memory model, rather than returning a buffer allocated inside your library. In the cases where you do need to allocate memory for internal state, the caller should see it as an opaque handle and you should provide accessor functions for the caller to extract data. Under no circumstances should the caller be expected to deallocate memory allocated inside your library, however it is ok for the caller to ask the library to do the deallocation.
Use COM, or a COM-like API. Here you return (often via out parameter) a pointer to an interface, which is a class with pure virtual functions, no non-virtual functions and no data.
The implementation is in concrete classes derived from this abstract interface, they can have data and helper functions galore, since that doesn't affect the binary interface.
This is a lot more work in the library but extremely portable and easy for the consumer to use.
And there is one thing absolutely NOT to do:
use __declspec(dllexport) on C++ classes.
EDIT: I want to also explain some good practices for option #2 which will maximize portability and make the native C/C++ parts usable from unmanaged applications as well.
You can make that easier with a macro, the usual way of doing it is:
In your header file, all the function declarations look like
MYPROJECTAPI(returntype) PublicFunc(params);
In your project, the definition is
#define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllexport)
In consumer projects
#define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllimport)
and then you can define the macro differently for other compilers like gcc which don't use __declspec.
The complete solution would look like (in public header file myproject.h):
#if _WIN32
# if BUILDMYPROJECT
# define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllexport)
# else
# define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllimport)
# endif
#else
# define MYPROJECTAPI(returntype) extern "C" returntype
#endif
and then your Visual C++ project would cause BUILDMYPROJECT to be defined when building myproject.dll

In a nutshell:
(1) Create a new C++/CLI library project.
(2) Write your code. For classes that need to be accessible from your C# project, make sure to create them as CLR classes:
public ref class R {/*...*/}; // CLR class
public value class V {/*...*/}; // CLR struct
public interface class I {/*...*/}; // CLR interface
(3) Compile the project and add a reference to it in your C# project.

Through P/Invoke layer.
http://en.wikipedia.org/wiki/Platform_Invocation_Services

Below is an example for an application where I had to do just that. In my case, I needed a DLL to wrap calls to functions that were only available in a .lib. The key part is the extern "C" __declspec (dllexport) in the declaration. That's basically all you need. The rest was merely using dllimport in the C# app and getting the marshalling right.
extern "C" __declspec (dllexport) LONG EstablishContext(DWORD dwScope,
LPCVOID pvReserved1,
LPCVOID pvReserved2,
LPSCARDCONTEXT phContext)
{
return SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext);
}

Related

The best way to use C++ code in .NET and VBA

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

P/Invoke Calls Failing

I have the following struct defined in C++:
struct GraphicsAdapterDesc {
// ... Just some constructors / operators / destructor here
DEFINE_DEFAULT_CONSTRUCTOR(GraphicsAdapterDesc);
DEFINE_DEFAULT_DESTRUCTOR(GraphicsAdapterDesc);
ALLOW_COPY_ASSIGN_MOVE(GraphicsAdapterDesc);
std::wstring AdapterName;
int32_t AdapterNum;
std::wstring HardwareHash;
int64_t DedicatedVMEM;
int64_t DedicatedSMEM;
int64_t SharedSMEM;
int32_t NumOutputs;
};
In C#, I have a 'mirror' struct declared thusly:
[StructLayout(LayoutKind.Sequential)]
public struct GraphicsAdapterDesc {
string AdapterName;
int AdapterNum;
string HardwareHash;
long DedicatedVMEM;
long DedicatedSMEM;
long SharedSMEM;
int NumOutputs;
};
I've tried to be really careful about matching up the widths of the variables (although I'm a bit unsure on what to do with the strings exactly).
Anyway, I have the following exported C method:
extern "C" __declspec(dllexport) bool GetGraphicsAdapter(int32_t adapterIndex, GraphicsAdapterDesc& outAdapterDesc) {
outAdapterDesc = RENDER_COMPONENT.GetGraphicsAdapter(adapterIndex);
return true;
}
And, the following extern method in my C# app:
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetGraphicsAdapter", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetGraphicsAdapter(int adapterIndex, out GraphicsAdapterDesc adapterDesc);
However, this doesn't work right when I call it. I get a different result depending on whether or not I'm compiling in x64 or x86 mode (both the C++ DLL and the C# app are compiled as x86 or x64):
In x86 mode, the call returns, but the struct has 'nonsense' values in, and the strings are all null,
In x64 mode, the call throws a NullPointerException.
My expectation is that I'm doing something wrong marshalling the strings, and that I need to specify 'wide-mode' for the characters, but I don't know how (or if that's even the right option).
Thank you in advance.
C++ types are not compatible with C# unless they're wrapped in managed C++. and you're using std::wstring which cannot be marshaled into .NET.
To interop successfully you'll either need to use a wchar_t[] or a whar_t* and tell C# now to marshal it.
I don't know what your macros are doing but this will only work if your c++ type is POD. c++11 Has an expanded sense of POD but I don't think you meet the expanded criteria anyway. Otherwise you can't guarantee layout. If you want to export your c++ classes to C# I would suggest you use c++\cli. Also you have wstring defined in your stuct which are definitely not POD. When you use DLLImport think C constructs only or you are going to have a bad time.

Strings in c++?

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.

What are the different ways of combining C++ and C#? [duplicate]

In my C# application, I would like to write a part of the code in C.
I plan to write a DLL witch would be interoperable with .Net.
How can I do that?
There are essentially three right ways to do it:
Use C++/CLI. This is the optimal way if this DLL is going to be used only by .NET.
Use an "extern "C"" compatible API, like the Windows API itself. This is the most portable, but isn't as convenient for your callers as using a class model to represent your objects.
This is the best option if you really intend to write in ANSI C (not C++).
For this path, you write your functions as extern "C" returntype __stdcall __declspec(dllexport) func(params) { ... }
You should also use a "caller-provides-the-buffer" memory model, rather than returning a buffer allocated inside your library. In the cases where you do need to allocate memory for internal state, the caller should see it as an opaque handle and you should provide accessor functions for the caller to extract data. Under no circumstances should the caller be expected to deallocate memory allocated inside your library, however it is ok for the caller to ask the library to do the deallocation.
Use COM, or a COM-like API. Here you return (often via out parameter) a pointer to an interface, which is a class with pure virtual functions, no non-virtual functions and no data.
The implementation is in concrete classes derived from this abstract interface, they can have data and helper functions galore, since that doesn't affect the binary interface.
This is a lot more work in the library but extremely portable and easy for the consumer to use.
And there is one thing absolutely NOT to do:
use __declspec(dllexport) on C++ classes.
EDIT: I want to also explain some good practices for option #2 which will maximize portability and make the native C/C++ parts usable from unmanaged applications as well.
You can make that easier with a macro, the usual way of doing it is:
In your header file, all the function declarations look like
MYPROJECTAPI(returntype) PublicFunc(params);
In your project, the definition is
#define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllexport)
In consumer projects
#define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllimport)
and then you can define the macro differently for other compilers like gcc which don't use __declspec.
The complete solution would look like (in public header file myproject.h):
#if _WIN32
# if BUILDMYPROJECT
# define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllexport)
# else
# define MYPROJECTAPI(returntype) \
extern "C" returntype __stdcall __declspec(dllimport)
# endif
#else
# define MYPROJECTAPI(returntype) extern "C" returntype
#endif
and then your Visual C++ project would cause BUILDMYPROJECT to be defined when building myproject.dll
In a nutshell:
(1) Create a new C++/CLI library project.
(2) Write your code. For classes that need to be accessible from your C# project, make sure to create them as CLR classes:
public ref class R {/*...*/}; // CLR class
public value class V {/*...*/}; // CLR struct
public interface class I {/*...*/}; // CLR interface
(3) Compile the project and add a reference to it in your C# project.
Through P/Invoke layer.
http://en.wikipedia.org/wiki/Platform_Invocation_Services
Below is an example for an application where I had to do just that. In my case, I needed a DLL to wrap calls to functions that were only available in a .lib. The key part is the extern "C" __declspec (dllexport) in the declaration. That's basically all you need. The rest was merely using dllimport in the C# app and getting the marshalling right.
extern "C" __declspec (dllexport) LONG EstablishContext(DWORD dwScope,
LPCVOID pvReserved1,
LPCVOID pvReserved2,
LPSCARDCONTEXT phContext)
{
return SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext);
}

How to export a struct definition from a native C .dll for use in C#

I know how to extern methods in the .dll, how do I extern structs?
I want to create a C method such as
extern __declspec(dllexport) myStructure getStruct();
where myStructure is something like
typedef struct
{
int A;
int B;
char C;
} myStructure;
How can I call getStruct() from a piece of C# code without first defining the same exact struct in C#? I want to keep a centralized declaration of myStructure so that I only have to make code changes in one place.
Thanks a bunch!
What about doing it another way? Define the struct in C# in T4 and then cross gen to the new format in each of the projects:
ie. base.tt
// C# definition of struct
in gencsharp.tt in the C# project
include "base.tt"
... output the C#
in gencplusplus.tt in the CPP project
include "base.tt"
... use C# to gen a cpp .h file
I've done a bit of P/Invoke with C# and I've always had to define structs in C# that correspond to the Win32 struct by definition. The runtime uses the struct definition to marshal the data from unmanaged to managed. Preet's answer is probably the best.

Categories