473,240 Members | 1,743 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,240 software developers and data experts.

Create native DLL in c++ and call it from c#

Hi,
This is an answer, not a question. I hope it helps you since i was
messing around for ages trying to get information on this:

For anyone else wanting to create a test c++nativedll/c# project follow
these instructions...

1) Create a new 'Visual C++ - Win32 Console Project' - call it 'test'
1b) When the wizard pops up, click the 'Application Settings' link on
the left
1c) Select 'DLL' under 'Application Type'
1d) Click 'Finish' (don't worry, everything remains in English)

2) In test.cpp you will need to ADD the following code at the bottom of
the auto-generated stuff:

//START

struct MyTestStruct
{
int iSomeNumber;
int iAnotherNumber;
};

extern "C" __declspec(dllexport) void
DoSomethingWithStruct(MyTestStruct* mts);

void DoSomethingWithStruct(MyTestStruct* mts)
{
if (mts != NULL)
{
mts->iSomeNumber = 12345;
mts->iAnotherNumber = mts->iAnotherNumber + 67890;
}
}

//END

That's the dll sorted. As you can see, DoSomethingWithStruct just sets
the value of the referenced structure's members.

3) Now File Add Project New Project 'Visual C# - Windows
Application'
3b) Add a button to your form - leave it named 'button1'
3c) Add the button click event handler
3d) Paste the code below OVER the entire event handler 'private void
button1_Click( ... ) { ... }':

//START

struct MyTestStruct
{
int iSomeNumber;
int iAnotherNumber;
};

[System.Runtime.InteropServices.DllImport(@"REPLACE
_THIS_WITH_THE_PATH_TO_YOUR_TEST.DLL_FILE\test\Deb ug\test.dll")]
private static extern void DoSomethingWithStruct(ref MyTestStruct
theStruct);

private void button1_Click(object sender, System.EventArgs e)
{
MyTestStruct mts = new MyTestStruct();
DoSomethingWithStruct(ref mts);
}

//END

3e) change the path where it says
REPLACE_THIS_WITH_THE_PATH_TO_YOUR_TEST.DLL_FILE to point to your dll.

4) Set the C# Windows Application as the startup project

5) Set a breakpoint so you can see that mts has indeed been changed

6) Run the project.

Shamelessly adapted from
http://blogs.msdn.com/jonathanswift/...02/780637.aspx, but
with some vital information added thanks to b0b - you know who you are.

Regards,
James Randle.

Also check out jonathan's followup article
http://blogs.msdn.com/jonathanswift/...23002900_.aspx
which eliminates the need to specify the location of the dll in the
DllImport attribute. Excellent work :).

Jan 16 '07 #1
14 14029
"pigeonrandle" <pi**********@hotmail.comwrote in message
news:11**********************@a75g2000cwd.googlegr oups.com...
extern "C" __declspec(dllexport) void
DoSomethingWithStruct(MyTestStruct* mts);
Doesn't this cause the name DoSomethingWithStruct to be mangled?

Michael
Jan 16 '07 #2

"Michael C" <no****@nospam.comwrote in message
news:eQ**************@TK2MSFTNGP03.phx.gbl...
"pigeonrandle" <pi**********@hotmail.comwrote in message
news:11**********************@a75g2000cwd.googlegr oups.com...
>extern "C" __declspec(dllexport) void
DoSomethingWithStruct(MyTestStruct* mts);

Doesn't this cause the name DoSomethingWithStruct to be mangled?
With extern "C", the compiler will just add a leading underscore. I think
P/Invoke is smart enough to find the export anyway. Other things it might
do is add "A" or "U" depending on whether you selected CharSet.Unicode or
not.
>
Michael

Jan 16 '07 #3
Michael,

I don't think so (taken from
http://blogs.msdn.com/jonathanswift/...2/780637.aspx)...

Using extern "C" forces the compiler to use the actual function name
(as it would in C). This prevents us from overloading this function but
we're not bothered about that in this example.
On a related note, if you want to examine a dll to find out, amongst
other things, exported function names, you can use the dumpbin command
from the Visual Studio command prompt. Typing dumpin /exports filename
will list the exported function names from the dll. Try it on our
simple dll with and without the extern "C" keywords to see the
decoration in action.

....unless you have something you'd like to add?!

Cheers,
James.

Again, maximum respect to Jonathan Swift, whoever you are ;)

Michael C wrote:
"pigeonrandle" <pi**********@hotmail.comwrote in message
news:11**********************@a75g2000cwd.googlegr oups.com...
extern "C" __declspec(dllexport) void
DoSomethingWithStruct(MyTestStruct* mts);

Doesn't this cause the name DoSomethingWithStruct to be mangled?

Michael
Jan 16 '07 #4
>Using extern "C" forces the compiler to use the actual function name
(as it would in C).
Because you're using the cdecl calling convention. If you want to keep
it that way and not switch to stdcall (which is more common for Win32
APIs), you should specify that in your DllImport attribute.
Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Jan 16 '07 #5
"Mattias Sjögren" <ma********************@mvps.orgwrote in message
news:uD*************@TK2MSFTNGP02.phx.gbl...
>
>>Using extern "C" forces the compiler to use the actual function name
(as it would in C).

Because you're using the cdecl calling convention. If you want to keep
it that way and not switch to stdcall (which is more common for Win32
APIs), you should specify that in your DllImport attribute.
So to use stdcall you need a DEF file?

Michael
Jan 17 '07 #6
"Mattias Sjögren" <ma********************@mvps.orgwrote in message
news:uD*************@TK2MSFTNGP02.phx.gbl...
>
>>Using extern "C" forces the compiler to use the actual function name
(as it would in C).

Because you're using the cdecl calling convention. If you want to keep
it that way and not switch to stdcall (which is more common for Win32
APIs), you should specify that in your DllImport attribute.
It's interesting that this example worked at all. C is using cdecl while c#
is using stdcall.

Michael
Jan 17 '07 #7
>So to use stdcall you need a DEF file?

To get it exported with an unmangled name, yes.

To be able to call it from .NET, no. The stdcall naming scheme is

_<function name>@<parameter byte count>

and like Ben mentioned, .NET can and will try that if the function
isn't found by its unmangled name.
Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Jan 17 '07 #8
All,
Perhaps one of you would like to modify the example I posted to reflect
what you have said? The reason i posted this in the first place was to
give people a starting point that was free from confusion!

Cheers,
James.
Mattias Sjögren wrote:
So to use stdcall you need a DEF file?

To get it exported with an unmangled name, yes.

To be able to call it from .NET, no. The stdcall naming scheme is

_<function name>@<parameter byte count>

and like Ben mentioned, .NET can and will try that if the function
isn't found by its unmangled name.
Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Jan 17 '07 #9
"Michael C" <no****@nospam.comwrote in message
news:%2***************@TK2MSFTNGP06.phx.gbl...
"Mattias Sjögren" <ma********************@mvps.orgwrote in message
news:uD*************@TK2MSFTNGP02.phx.gbl...
>>
>>>Using extern "C" forces the compiler to use the actual function name
(as it would in C).

Because you're using the cdecl calling convention. If you want to keep
it that way and not switch to stdcall (which is more common for Win32
APIs), you should specify that in your DllImport attribute.

It's interesting that this example worked at all. C is using cdecl while c# is using
stdcall.

Michael
Yep, this results in a corrupted stack, but you don't call C directly from C#, the PInvoke
interop layer fixes the calling convention mismatch.
Anyway, this is a bug that should be corrected by the author of the code, you should not
rely on the CLR to do the right thing.

Willy.
Jan 17 '07 #10
Willy,
I'm happy to make the correction :), what is it?

James.

Willy Denoyette [MVP] wrote:
"Michael C" <no****@nospam.comwrote in message
news:%2***************@TK2MSFTNGP06.phx.gbl...
"Mattias Sjögren" <ma********************@mvps.orgwrote in message
news:uD*************@TK2MSFTNGP02.phx.gbl...
>
Using extern "C" forces the compiler to use the actual function name
(as it would in C).

Because you're using the cdecl calling convention. If you want to keep
it that way and not switch to stdcall (which is more common for Win32
APIs), you should specify that in your DllImport attribute.
It's interesting that this example worked at all. C is using cdecl while c# is using
stdcall.

Michael

Yep, this results in a corrupted stack, but you don't call C directly from C#, the PInvoke
interop layer fixes the calling convention mismatch.
Anyway, this is a bug that should be corrected by the author of the code,you should not
rely on the CLR to do the right thing.

Willy.
Jan 18 '07 #11
"pigeonrandle" <pi**********@hotmail.comwrote in message
news:11*********************@a75g2000cwd.googlegro ups.com...
Willy,
I'm happy to make the correction :), what is it?

James.

The default calling convention as expected by PInvoke is __stdcall, when calling a __cdecl
function, you'll have to tell PInvoke by applying the CallingConvention parameter like this:
[DllImport("yourdll", CallingConvention=CallingConvention.Cdecl) static extern .....
Note that the majority of the Win32 API's are __stdcall, and all Win32 callbacks must be
__stdcall. This is probably the reason why it has been taken as the default.
Most of the CRT API's however, are __cdecl and the VC compiler defaults to _cdecl, so, if
you want to decalre your C function as __stdcall you have to declare your function like so:

extern "C" void __declspec(dllexport) __stdcall function(...);
In this case you can go with the default in your PInvoke declaration by leaving out the
CallingConvention , but I would prefer to be explicit and always include the
CallingConvention.

Willy.
Jan 18 '07 #12
"pigeonrandle" <pi**********@hotmail.comwrote in message
news:11*********************@a75g2000cwd.googlegro ups.com...
Willy,
I'm happy to make the correction :), what is it?

Willy's method modifies the C# definition to use cdecl but IMO it is better
to modify C++ so it uses stdcall. Just about every API I've ever used on
windows from MS or other vendors has been stdcall so it is better to go with
the standard. I'm no expert on C++ but here's my example of a dll with a
single function called AddOne. It takes an integer and returns an integer
which has had 1 added to it. I just created a new Win32 dynamic link library
project and replace the default code with the code below. You will need to
create a DEF file also so C++ doesn't mangle the function names. The DEF
file is only 2 lines and is below also. There is no option to add a DEF file
but just add a text file and rename it to something.def. The .h file isn't
strictly needed but is good to have. In the .cpp file where is says #include
"TestDll.h" you should rename this to whatever you've called your .h file.
That's it, besides what C++ adds by default there's only 5 lines of code.
Compile the dll and view it with dependency walker or quick view and have a
look at the exports to make sure it all worked, you should see AddOne
unmangled. You can call this from C# in the way you originally called it. If
anyone sees any issues with my C++ code please let me know. :-)

--------------------------------------------
..h file:

extern int __stdcall AddOne(int Value);
----------------------------------
..cpp file:

#include "stdafx.h"
#include "TestDll.h"

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

int __stdcall AddOne(int Value)
{
return Value + 1;
}

------------------------------------
..def file

EXPORTS
AddOne
Jan 21 '07 #13
"Michael C" <no****@nospam.comwrote in message
news:eO**************@TK2MSFTNGP04.phx.gbl...
"pigeonrandle" <pi**********@hotmail.comwrote in message
news:11*********************@a75g2000cwd.googlegro ups.com...
Willy,
I'm happy to make the correction :), what is it?

Willy's method modifies the C# definition to use cdecl but IMO it is better to modify C++
so it uses stdcall. Just about every API I've ever used on windows from MS or other
vendors has been stdcall so it is better to go with the standard. I'm no expert on C++ but
here's my example of a dll with a single function called AddOne. It takes an integer and
returns an integer which has had 1 added to it. I just created a new Win32 dynamic link
library project and replace the default code with the code below. You will need to create
a DEF file also so C++ doesn't mangle the function names. The DEF file is only 2 lines and
is below also. There is no option to add a DEF file but just add a text file and rename it
to something.def. The .h file isn't strictly needed but is good to have. In the .cpp file
where is says #include "TestDll.h" you should rename this to whatever you've called your
.h file. That's it, besides what C++ adds by default there's only 5 lines of code. Compile
the dll and view it with dependency walker or quick view and have a look at the exports to
make sure it all worked, you should see AddOne unmangled. You can call this from C# in the
way you originally called it. If anyone sees any issues with my C++ code please let me
know. :-)

--------------------------------------------
.h file:

extern int __stdcall AddOne(int Value);
----------------------------------
.cpp file:

#include "stdafx.h"
#include "TestDll.h"

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

int __stdcall AddOne(int Value)
{
return Value + 1;
}

------------------------------------
.def file

EXPORTS
AddOne

Be careful, all C runtime and C++ Standard Library exports are __cdecl. The default export
for VC++ is __cdecl.
So when using PInvoke, the message should be, read the docs of the API you need to call,
don't assume any default.

Willy.
Jan 22 '07 #14
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:uk**************@TK2MSFTNGP02.phx.gbl...
Be careful, all C runtime and C++ Standard Library exports are __cdecl.
The default export for VC++ is __cdecl.
So when using PInvoke, the message should be, read the docs of the API you
need to call, don't assume any default.
Good advice, especially seeing dot net apparently fixes the stack corruption
without error so you might never know. Although I've only ever encountered 1
cdecl api.

Michael
Jan 22 '07 #15

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Mike Kamzyuk | last post by:
Hello all. Basically, I need to call a mixed-mode dll's function (which uses managed code) from a native or mixed-mode dll function (which does not use managed code). I'm wondering if this could...
1
by: dln | last post by:
Hey all. I'm a bit new to the language and I'm trying to figure out how to have my c# application interact with native code that is exported via a dll. I've run into a problem interfacing with a...
1
by: Tim Rogers | last post by:
We've currently got a C++ client/server app that uses DCOM in order to make remote calls. We want to replace DCOM with a .NET Web Service. The server piece seems clear to me. I can write it...
8
by: Ted Miller | last post by:
Hi folks, I'm looking at moving a large base of C++ code to .Net under tight time constraints. The code runs in mission-critical environments, and I am extremely concerned about the loader lock...
5
by: Elton Rabello | last post by:
Hi I don't know if it is possible, but I need to create a DLL in C# or VB.Net, that can be invoke by function Loadlibrary from Delphi. Is this possible? How? Thanks a lot Elton
13
by: bonk | last post by:
Hello, I am trying to create a dll that internally uses managed types but exposes a plain unmanaged interface. All the managed stuff shall be "wrapped out of sight". So that I would be able to...
3
by: -DG- | last post by:
I'm still trying to figure out some of the nuances of access to legacy Win32 DLLs. I need to alloc buffers to be used by the Win32 DLLs. I know that pinning a managed pointer can lead to...
3
by: Lonewolf | last post by:
Hi all, I'm having difficulties passing data back to managed class from my native class when the data is generated from within a native thread in the native class itself. I will give the following...
9
by: S Wheeler | last post by:
Hi all - I am trying to create an instance of a vb .net class containing a form from unmanaged vc++. The vb.net is a dll. How to do this ? I am trying #import by can't seem to get it quite...
14
by: Ben Voigt | last post by:
Under certain circumstances I get: First-chance exception at 0x7c812a5b (kernel32.dll) in LTMGUI.exe: 0xC0020001: The string binding is invalid. First-chance exception at 0x7c812a5b (kernel32.dll)...
0
by: jianzs | last post by:
Introduction Cloud-native applications are conventionally identified as those designed and nurtured on cloud infrastructure. Such applications, rooted in cloud technologies, skillfully benefit from...
0
by: abbasky | last post by:
### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.