C# DLL for C++ Application

M

Martin

Hi. I have a C++ application that can communicate with C++ DLL with
specific interface. I would like to know, if it is possible to create a
C# DLL with the same interface. The functions which the C++ DLL exposes
are these:

extern "C" _declspec(dllexport) int _stdcall f1(int a,char *b,int c,int
d);
extern "C" _declspec(dllexport) void _stdcall f2(void)
extern "C" _declspec(dllexport) int _stdcall f3(char *a,char *b,int c)
extern "C" _declspec(dllexport) int _stdcall f4(char *a,_T **b)

where the _T type is a structure:

typedef struct
{
char x;
char y[128];
void *z;
}_T;

In function f1 is the "b" parameter an application preallocated array
of chars (128 chars). So are the "a" and "b" parameters in function f3
and "a" parameter in function f4. The "b" parameter in function f4 is
dynamically allocated in DLL. Is it possible to rewrite this DLL
interface to C#? How?
 
T

tsahiasher

i think not. the internall structure of a .net dll (and it is
completely irrelevant what language was used in writing it) is very
different from a c/c++ dll, so i doubt if a c++ program will be able to
link to it.
 
?

=?ISO-8859-2?Q?=A3ukasz?=

Martin said:
Hi. I have a C++ application that can communicate with C++ DLL with
specific interface. I would like to know, if it is possible to create a
C# DLL with the same interface. The functions which the C++ DLL exposes
are these:

extern "C" _declspec(dllexport) int _stdcall f1(int a,char *b,int c,int
d);
extern "C" _declspec(dllexport) void _stdcall f2(void)
extern "C" _declspec(dllexport) int _stdcall f3(char *a,char *b,int c)
extern "C" _declspec(dllexport) int _stdcall f4(char *a,_T **b)

where the _T type is a structure:

typedef struct
{
char x;
char y[128];
void *z;
}_T;

In function f1 is the "b" parameter an application preallocated array
of chars (128 chars). So are the "a" and "b" parameters in function f3
and "a" parameter in function f4. The "b" parameter in function f4 is
dynamically allocated in DLL. Is it possible to rewrite this DLL
interface to C#? How?

It is possible, but difficult and you cannot do that without MC++ (you
can write "wrapper" dll in MC++).

£ukasz
 
W

Willy Denoyette [MVP]

Martin said:
Hi. I have a C++ application that can communicate with C++ DLL with
specific interface. I would like to know, if it is possible to create a
C# DLL with the same interface. The functions which the C++ DLL exposes
are these:

extern "C" _declspec(dllexport) int _stdcall f1(int a,char *b,int c,int
d);
extern "C" _declspec(dllexport) void _stdcall f2(void)
extern "C" _declspec(dllexport) int _stdcall f3(char *a,char *b,int c)
extern "C" _declspec(dllexport) int _stdcall f4(char *a,_T **b)

where the _T type is a structure:

typedef struct
{
char x;
char y[128];
void *z;
}_T;

In function f1 is the "b" parameter an application preallocated array
of chars (128 chars). So are the "a" and "b" parameters in function f3
and "a" parameter in function f4. The "b" parameter in function f4 is
dynamically allocated in DLL. Is it possible to rewrite this DLL
interface to C#? How?

The functions are exported as C functions, as such they can be called
through PInvoke interop.
You need declare your function imports in C# using DllImport like this
simple declaration for f2:

[DllImport("yourlibrary.dll")]
public static extern void f2();

The f4 function is a bit more tricky and requires you to answer a few
questions before you can declare the import signature:
1 the first arg. is a pointer to a 'char' but might point to 'something'
else in reality like an array of char's or bytes.
2. what are the args. semantics (in, out, in-out), who's allocating the
memory the pointers are pointing to, the caller or the callee?
3. char's are 16 bit in C#, in C they are 8 bits for ANSI builds or 16 bits
for UNICODE builds or when they are declared as wchar_t.
4 you have to consider struct alignment and packing...
5. void * can point to anything, so you need to pass an IntPtr and do the
marhaling yourself depending on whta's exeactly pointed to.

Following gives you an idea how it could be done, however, you should
consult MSDN for more detailed info on marshaling and PInvoke.
struct _T
{
internal char x;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
internal char[] y;
IntPtr z;
}


[DllImport("yourlibrary.dll")]
public static extern int f4(IntPtr a, ref _T b);


_T t = new _T();
IntPtr a = ....????; what is expected as type for a?
int ret = f4(a, ref t);
...

Willy.
 
M

Martin

Well, that's not what I need - you are writing about importing of C++
DLL into a C# app. I wanted the exact opposite - create a C# DLL that
is callable from C++ application using the interface described in my
first post.

1. the pointers to char are C++ strings of max length of 127 bytes
(plus ending zero, so the arrays are 128 bytes long). These strings are
allocated by calling application, the DLL should only copy a string
into it. The only allocation that is done by the DLL is allocation of
"b" parameter in "f4" function.

2. all the non-pointer parameters are in, all the pointer parameters
are out. none of them are in-out.

3. all chars are 8bit

4. alignment is 4 bytes

5. that void* points to array of bytes, the allocated size of that
array is stored in member variable "x" of the struct "_T"
 
W

Willy Denoyette [MVP]

Martin said:
Well, that's not what I need - you are writing about importing of C++
DLL into a C# app. I wanted the exact opposite - create a C# DLL that
is callable from C++ application using the interface described in my
first post.

1. the pointers to char are C++ strings of max length of 127 bytes
(plus ending zero, so the arrays are 128 bytes long). These strings are
allocated by calling application, the DLL should only copy a string
into it. The only allocation that is done by the DLL is allocation of
"b" parameter in "f4" function.

2. all the non-pointer parameters are in, all the pointer parameters
are out. none of them are in-out.

3. all chars are 8bit

4. alignment is 4 bytes

5. that void* points to array of bytes, the allocated size of that
array is stored in member variable "x" of the struct "_T"

I see what you mean, question is why. You have a DLL that's callable from
C++ and from C#, and now you wan't to build a C# dll that won't be callable
from C++, unless you are willing to change all your C++ users to call it
through COM interop or, as the other posters suggested, you are also writing
a managed wrapper in managed C++ (ME C++) or C++/CLI (upcoming VS2005).

Willy.
 
M

Martin

No, I do not have any DLL.

The C++ application wasn't made by me. The application has an interface
for additional external modules - on its startup it checks all DLLs
that are in its program directory. If they have the right functions
(that 4 that I've written above) the application loads them. I only
want to create a module for that application and I would like to write
this module in C#.
 
W

Willy Denoyette [MVP]

Martin said:
No, I do not have any DLL.

The C++ application wasn't made by me. The application has an interface
for additional external modules - on its startup it checks all DLLs
that are in its program directory. If they have the right functions
(that 4 that I've written above) the application loads them. I only
want to create a module for that application and I would like to write
this module in C#.

Well, you can't call C# from C/C++ directly, you need to write a C++ DLL
that exports these functions.
Another option is to write a C# DLL plus a wrapper in ME C++, but this makes
no sense if the purpose is to call it only from C++.

Willy.
 
?

=?ISO-8859-2?Q?=A3ukasz?=

Martin said:
Can you post a source code how this could be done?

OK. I hope it will be helpful.


##########################

So, this is example code of application:

#include <iostream>
#include <tchar.h>
using namespace std;

#pragma comment(lib, "{path to MC++ DLL wrapper lib file}.lib")
#undef _T // undefining some _T macro

typedef struct
{
char x;
char y[128];
void *z;
}_T;

extern "C" _declspec(dllimport) int _stdcall f1(int a, char *b, int c,
int d);
extern "C" _declspec(dllimport) void _stdcall f2(void);
extern "C" _declspec(dllimport) int _stdcall f3(char *a, char *b, int c);
extern "C" _declspec(dllimport) int _stdcall f4(char *a, _T **b);

int _tmain(int argc, _TCHAR* argv[])
{
char* str1 = "some text";
cout << f1(1, str1, 2, 3) << endl;

f2();

char* str2 = "other text";
cout << f3(str1, str2, 4) << endl;

_T * t = new _T();
t->x = 'c';
for (int i = 0; i < 20; i++)
{
t->y = 'a' + i;
}
t->z = (void*)12345;

cout << f4(str1, &t) << endl;
cout << t->x << " " << t->y << " " << t->z << endl;

return 0;
}


##########################

This is wrapper code (managed c++):

#using <mscorlib.dll>
#using <System.dll>
#using <{ your c# dll }.dll>

extern "C" _declspec(dllexport) int _stdcall f1(int a, char *b, int c,
int d)
{
return F::f1(a, b, c, d);
}

extern "C" _declspec(dllexport) void _stdcall f2(void)
{
F::f2();
}

extern "C" _declspec(dllexport) int _stdcall f3(char *a, char *b, int c)
{
return F::f3(a, b, c);
}

extern "C" _declspec(dllexport) int _stdcall f4(char *a, _T **b)
{
return F::f4(a, b);
}


##########################

This is your C# dll example code:

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public class _T
{
public char x;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string y;
public IntPtr z;
}

public class F
{
public static int f1(int a, [MarshalAs(UnmanagedType.LPStr)]string b,
int c, int d)
{
MessageBox.Show(a + " " + b + " " + c + " " + d, "f1");
return a + c + d;
}

public static void f2()
{
MessageBox.Show("f2", "f2");
}

public static int f3([MarshalAs(UnmanagedType.LPStr)]string a,
[MarshalAs(UnmanagedType.LPStr)]string b, int c)
{
MessageBox.Show(a + " " + b + " " + c, "f3");
return c * 2;
}

public static int f4([MarshalAs(UnmanagedType.LPStr)]string a, ref _T b)
{
MessageBox.Show(a + " " + b.x + " " + b.y + " " + b.z, "f4");
b.x = '@';
b.y = "C#";
b.z = IntPtr.Zero;
return 555;
}
}
 
M

Martin

Why should I write a C++ DLL? I'll be in the same situation as now only
with one DLL more. The problem with exporting C# methods to C++
application will remain. Maybe I'm missing something...
 
W

Willy Denoyette [MVP]

Martin said:
Why should I write a C++ DLL? I'll be in the same situation as now only
with one DLL more. The problem with exporting C# methods to C++
application will remain. Maybe I'm missing something...

No, you should write a C++ DLL using VS2003 ME C++ (or the upcoming C++/CLI
in VS2005). This DLL must be compiled as a mixed mode DLL (managed/unmanaged
code) using the /clr compiler option.
See the sample posted by Lukasz.
But again it makes little sense if the only consumer of the C# DLL is C++,
it creates an extra level of indirection without any other advantage.

Willy.
 
M

Martin

Great! Now I see, its simple. Thanks!

I only have to allocate the "b" parameter inside the F::f4 method, not
outside as you did.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top