This question already has answers here:
Call a C++ function from C#
(4 answers)
Closed 9 years ago.
I am making a program to control a laser but to do that I need to import a dll into c# and call functions with it. The original program is written in C++ and I just cant figure it out how to do it.
So my questions are:
How to import a dll in c#
how to call the functions from C++ in c#
To make it a bit more clear to you I've added the code from the C++ program.
#include "MarkEzdDll.h"
class CDemoEzdDlg : public CDialog
{
// Construction
public:
CDemoEzdDlg(CWnd* pParent = NULL); // standard constructor
HINSTANCE m_hEzdDLL;//DLLµ÷Óþä±ú
LMC1_INITIAL lmc1_Initial;
LMC1_CLOSE lmc1_Close;
LMC1_LOADEZDFILE lmc1_LoadEzdFile;
LMC1_MARK lmc1_Mark;
LMC1_MARKENTITY lmc1_MarkEntity;
LMC1_GETPREVBITMAP lmc1_GetPrevBitmap;
LMC1_READPORT lmc1_ReadPort;
LMC1_WRITEPORT lmc1_WritePort;
LMC1_SETDEVCFG lmc1_SetDevCfg;
LMC1_SETHATCHPARAM lmc1_SetHatchParam;
LMC1_SETFONTPARAM lmc1_SetFontParam;
LMC1_GETPENPARAM lmc1_GetPenParam;
LMC1_SETPENPARAM lmc1_SetPenParam;
LMC1_CLEARENTLIB lmc1_ClearEntLib;
LMC1_ADDTEXTTOLIB lmc1_AddTextToLib;
LMC1_ADDFILETOLIB lmc1_AddFileToLib;
LMC1_ADDBARCODETOLIB lmc1_AddBarCodeToLib;
LMC1_CHANGETEXTBYNAME lmc1_ChangeTextByName;
LMC1_AXISMOVETO lmc1_AxisMoveTo;
LMC1_AXISCORRECTORIGIN lmc1_AxisCorrectOrigin;
LMC1_GETAXISCOOR lmc1_GetAxisCoor;
LMC1_SAVEENTLIBTOFILE lmc1_SaveEntLibToFile;
in the dialog, there is a button which has this code attached to it:
void CDemoEzdDlg::OnButtonRun()
{
// TODO: Add your control notification handler code here
UpdateData();
if(lmc1_Mark==NULL)
{
return;
}
lmc1_Mark(FALSE);
UpdatePrevBmp();
AfxMessageBox(_T("Mark file finish!"));
}
This is when the laser should start.
How to get this in c#?
(It was not very clear from your post, but I am guessing you want to call C++ functions from your C# code.)
PInvoke is perfect for this. Here is a nice tutorial: click.
You don't import the DLL in your project settings; instead you call it from your source code. You do have to make sure that the DLL is in the same folder as your project's output (.exe) file, of course.
In a nutshell, if you define a C method like this in foo.dll:
extern "C" __declspec(dllexport) bool __stdcall GetTrue()
{
return true;
}
Then your C# program can declare it like this:
[DllImport("foo.dll")]
static public extern bool GetTrue();
and simply use GetTrue() to call it. (You also need to add using System.Runtime.InteropServices; in the same file)
Of course it gets more complicated when you use data types that differ between C# and C++ (like strings, objects, etc) but the tutorial covers that pretty nicely.
Related
I have a C lib and want to call function in this library from C# application. I tried creating a C++/CLI wrapper on the C lib by adding the C lib file as linker input and adding the source files as additional dependencies.
Is there any better way to achieve this as am not sure how to add C output to c# application.
My C Code -
__declspec(dllexport) unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen);
My CPP Wrapper -
long MyClass::ConnectSessionWrapper(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen)
{
return ConnectSession(handle, publicKey, publicKeyLen);
}
The example will be, for Linux:
1) Create a C file, libtest.c with this content:
#include <stdio.h>
void print(const char *message)
{
printf("%s\\n", message);
}
That’s a simple pseudo-wrapper for printf. But represents any C function in the library you want to call. If you have a C++ function don’t forget to put extern C to avoid mangling the name.
2) create the C# file
using System;
using System.Runtime.InteropServices;
public class Tester
{
[DllImport("libtest.so", EntryPoint="print")]
static extern void print(string message);
public static void Main(string[] args)
{
print("Hello World C# => C++");
}
}
3) Unless you have the library libtest.so in a standard library path like “/usr/lib”, you are likely to see a System.DllNotFoundException, to fix this you can move your libtest.so to /usr/lib, or better yet, just add your CWD to the library path: export LD_LIBRARY_PATH=pwd
credits from here
EDIT
For Windows, it's not much different.
Taking an example from here, you only have yo enclose in your *.cpp file your method with extern "C"
Something like
extern "C"
{
//Note: must use __declspec(dllexport) to make (export) methods as 'public'
__declspec(dllexport) void DoSomethingInC(unsigned short int ExampleParam, unsigned char AnotherExampleParam)
{
printf("You called method DoSomethingInC(), You passed in %d and %c\n\r", ExampleParam, AnotherExampleParam);
}
}//End 'extern "C"' to prevent name mangling
then, compile, and in your C# file do
[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]
public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);
and then just use it:
using System;
using System.Runtime.InteropServices;
public class Tester
{
[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]
public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);
public static void Main(string[] args)
{
ushort var1 = 2;
char var2 = '';
DoSomethingInC(var1, var2);
}
}
UPDATE - Feb 22 2019: Since this answer has been getting quite a few upvotes, I decided to update it with a better way of calling the C method. Previously I had suggested using unsafe code, but the safe and correct way is to use MarshalAs attribute for converting a .NET string to a char*. Also, in VS2017 there is no Win32 project anymore, you'll probably have to create a Visual C++ dll or empty project and modify that. Thank you!
You can directly call C functions from C# by using P/Invoke.
Here's a short how-to on creating a C# lbrary that wraps around a C dll.
Create a new C# Library project (I'll call it "Wrapper")
Add a Win32 project to the solution, set application type to: DLL (I'll call it "CLibrary")
You can remove all the other cpp/h files since we won't need them
Rename the CLibrary.cpp file to CLibrary.c
Add a CLibrary.h header file
Now we need to configure the CLibrary project, right-click it and go to properties, and select Configuration: "All Configurations"
In Configuration Properties > C/C++ > Precompiled headers, set Precompiled Headers to: "Not using Precompiled Headers"
In the same C/C++ branch, go to Advanced, change Compile As to: "Compile as C code (/TC)"
Now in the Linker branch, go to General, and change Output File to: "$(SolutionDir)Wrapper\$(ProjectName).dll", this will copy the built C DLL to the C# project root.
CLibrary.h
__declspec(dllexport) unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen);
CLibrary.c
#include "CLibrary.h"
unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen)
{
return 42;
}
Right-click CLibrary project, build it, so we get the DLL in the C# project directory
Right-click C# Wrapper project, add existing item, add CLibrary.dll
Click on CLibrary.dll, go to the properties pane, set "Copy to output Directory" to "Copy Always"
It's a good idea to make the Wrapper project dependent on CLibrary so CLibrary gets built first, you can do that by right-clicking the Wrapper project, going to "Project Dependencies" and checking "CLibrary".
Now for the actual wrapper code:
ConnectSessionWrapper.cs
using System.Runtime.InteropServices;
namespace Wrapper
{
public class ConnectSessionWrapper
{
[DllImport("CLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern uint ConnectSession(uint handle,
[MarshalAs(UnmanagedType.LPStr)] string publicKey,
char publicKeyLen);
public uint GetConnectSession(uint handle,
string publicKey,
char publicKeyLen)
{
return ConnectSession(handle, publicKey, publicKeyLen);
}
}
}
Now just call GetConnectSession, and it should return 42.
Result:
Okay well, Open VS 2010, Goto File -> New -> Project -> Visual C++ -> Win32 -> Win32 Project and give it a name (HelloWorldDll in my case), Then in the window that follows under Application Type choose 'DLL' and under Additonal Options choose 'Empty Project'.
Now goto your Solution Explorer tab usually right hand side of VS window, right click Source Files -> Add Item -> C++ file (.cpp) and give it a name (HelloWorld in my case)
Then in the new class paste this code:
#include <stdio.h>
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL()
{
printf ("Hello from DLL !\n");
}
}
Now Build the project, after navigate to your projects DEBUG folder and there you should find: HelloWorldDll.dll.
Now, lets create our C# app which will access the dll, Goto File -> New -> Project -> Visual C# -> Console Application and give it a name (CallDllCSharp), now copy and paste this code to your main:
using System;
using System.Runtime.InteropServices;
...
static void Main(string[] args)
{
Console.WriteLine("This is C# program");
DisplayHelloFromDLL();
Console.ReadKey();
}
and build the program, now that we have both our apps built lets use them, get your *.dll and your .exe (bin/debug/.exe) in the same directory, and execute the application output should be
This is C# program
Hello from DLL !
Hope that clears some of your issues up.
References:
How to create a DLL library in C and then use it with C#
NOTE : BELOW CODE IS FOR MULTIPLE METHODS FROM DLL.
[DllImport("MyLibc.so")] public static extern bool MyLib_GetName();
[DllImport("MyLibc.so")] public static extern bool MyLib_SetName(string name);
[DllImport("MyLibc.so")] public static extern bool MyLib_DisplayName(string name);
public static void Main(string[] args)
{
string name = MyLib_GetName();
MyLib_SetName(name);
MyLib_DisplayName(name);
}
The P/Invoke method has been described extensively and repeatedly, ok so far.
What I'm missing here is, that the C++/CLI method has a big advantage: Calling safety.
In contrast to P/Invoke, where the call of the C funtion is like shooting blind into the sky (if this comparison is allowed), nobody will check the function arguments when calling the C function.
Using C++/CLI in this case means normally, you include a headerfile with the functions prototypes you want to use. If you are calling the C function with wrong/to much /to few arguments, the compiler will tell you.
I don't think you can say in general which is the better method, honestly I don't like either of them.
Here are the steps what I have done.
I have created a .dll file using C# with the content as
public static int MyFunction(int dummy)
{
MessageBox.Show("I am in dll");
return 0;
}
I have also created an MFC application (exe) with content as
int main()
{
int a = MyFunction(0);
return 0;
}
Is this right way to do the call ?
Note:
i. I have changed my MFC application to /cl (common language run time support)
ii. I have also added C# file in the MFC's Reference.
Problems I faced:
Error 1 error C3861: 'MyFunction': identifier not found
Warning 2 warning C4793: 'MyDialog::`vcall'{132}'' : function compiled as native :
I have used the following command in the MyDialog.cpp file as a last line, the warning is solved.
#pragma unmanaged
Now how to solve the Error?
The C# code is placed inside a class, say MyClass. If you want to call a static member of this class in C++/CLI, you need to use MyClass::MyFunction(0).
Finally, you would need to add the namespace: MyNamespace::MyClass::MyFunction(0).
You can compile your C++ program with the /clr flag and use C++/CLI to simply call any .NET code (as long as you include a reference to it).
You could also use a COM callable wrapper for your C# code (compiled in a DLL) -> check this article
I tried to call the function from .dll file using java native interface ,its successfully working, But I don't know how to call function from .dll using C# ,please advice me on this.
Look at DLLImport attribute in MSDN
http://msdn.microsoft.com/en-us/library/aa664436(v=vs.71).aspx
using System;
using System.Runtime.InteropServices;
class Example
{
[DllImport("your_dll_here.dll")]
static extern int SomeFuncion1(int parm);
static void Main()
{
int result = SomeFunction1(10);
}
}
If it's a native DLL, you need to add a DLLImport statement, importing the function you want.
The documentation is here.
The attribute looks like this, typically:
[DllImport("YourDllNameHere.dll")]
public static extern int YourFunction(int input);
This will import a function called YourFunction (which takes an int input, and returns an int) from YourDllNameHere.dll.
Let's say your DLL name is MyLibrary and MyFunction is the function contain in your DLL .
First right click on your Reference , browse and add your DLL .
Declare your DLL as a namespace using MyLibrary;
And you can call MyFunction !
Or
Another way ,
you can use this msdn reference !
Add that dll into your project as a referenced dll into reference folder(right click on references ,add reference then "Browse" to you DLL).then it should be available for to use as you want and just use that dll as follows in the code level.
using System;
using YourDllName;
class ExampleClass
{
//you can use your dll functions
}
I like the link provided by Baldrick for DllImport attribute.
This is what I recommend.
Download Dependency Walker (small application exe, no need to install).
Open your DLL in the Dependecy Walker to view the exposed entry points of DLL.
Declare external call to native function in C# like this.
C#:
[DllImport("Your_DLL.DLL", EntryPoint="Function_Entry_Point",CallingConvention=CallingConvention.StdCall)]
static extern IntPtr Function1();
Note:
If entry point is not specified the function name is considered as the entry point.
When you run the application make sure the native DLL is in the
same folder.
I'm new to unity3D and C# (and IOS :), but need to get things working with a legacy C library (.h & .a files) on iPhone. I've read some about Plugins from unity documentation, but still feel overwhelmed by the complicated procedures. Could any guru show me the correct way out of the mess? Thanks!
Go through this link. This gives the idea for making plugins for iOS. If any doubt, ask.
A practical example for plugin
1) Make a C# file called AppControllerBinding.cs in the plugins folder in Unity and add the code as followed:
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
// All Objective-C exposed methods should be bound here
public class AppControllerBinding
{
[DllImport("__Internal")]
private static extern void _MyFunction(string myName);
public static void MyFunction(string MyNameIN)
{
// Call plugin only when running on real device
if( Application.platform == RuntimePlatform.IPhonePlayer )
_MyFunction(MyNameIN);
}
}
2) Add the MyFunction() function to the bottom on the AppController.mm file inside Xcode as follows (after the #end statement):
extern "C"
{
void _MyFunction(const char* MyName)
{
NSString* s = [NSString stringWithUTF8String: MyName];
[Self logName:s]; //<-----logName is method which takes string parameter
printf_console("_MyFunction() called in Appcontroller.mm in Xcode.\n");
}
}
3) When you want to use the logName function of AppController.mm inside Unity just make a call like this:
AppControllerBinding.MyFunction("Nick");
I have a particular function in an Excel addin(xll).
The addin is proprietary and we do not have access to the source code. However we need to call some functions contained within the addin and we would like to call it from a C# program.
Currently, I was thinking of writing a C++ interface calling the Excel function with xlopers, then calling this C++ interface from C#.
Does anybody who has prior experience of this kind of issues know what would be the best solution for that ?
Anthony
You need to create a fake xlcall32.dll, put it in the same directory as your XLL (do not put excel's own xlcall32.dll in the PATH). Here is some code:
# include <windows.h>
typedef void* LPXLOPER;
extern "C" void __declspec(dllexport) XLCallVer ( ) {}
extern "C" int __declspec(dllexport) Excel4 (int xlfn, LPXLOPER operRes, int count,... ) { return 0; }
extern "C" int __declspec(dllexport) Excel4v(int xlfn, LPXLOPER operRes, int count, LPXLOPER far opers[]) {return 0;}
Now suppose I have an XLL called xll-dll.xll with a function called (use "depends.exe" to find out the names of the exported functions) xlAdd that well adds two doubles:
extern "C" __declspec(dllexport) XLOPER * __cdecl xlAdd(XLOPER* pA, XLOPER* pB);
The following code calls it:
# include <windows.h>
# include <iostream>
// your own header that defines XLOPERs
# include <parser/xll/xloper.hpp>
// pointer to function taking 2 XLOPERS
typedef XLOPER * (__cdecl *xl2args) (XLOPER* , XLOPER* ) ;
void test(){
/// get the XLL address
HINSTANCE h = LoadLibrary("xll-dll.xll");
if (h != NULL){
xl2args myfunc;
/// get my xll-dll.xll function address
myfunc = (xl2args) GetProcAddress(h, "xlAdd");
if (!myfunc) { // handle the error
FreeLibrary(h); }
else { /// build some XLOPERS, call the remote function
XLOPER a,b, *c;
a.xltype = 1; a.val.num = 1. ;
b.xltype = 1; b.val.num = 2. ;
c = (*myfunc)(&a,&b);
std::cout << " call of xll " << c->val.num << std::endl; }
FreeLibrary(h); }
}
int main()
{test();}
My exe actually works (to my own surprise), and output 3 as expected. You must have some knowledge of what your XLL actually expects for parameters. If it allocates some memory, you must check if the #define xlbitDLLFree 0x4000
is set on your XLOPER c->type, and call back "xlAutoFree".
You might like to try XLL Plus http://www.planatechsolutions.com/xllplus/default.htm. It's a bit pricey, but the
XLL Wrapper Libraries feature is exactly what you are looking for:
"Sometimes it is useful to be able to call your Excel add-in functions from other environments, such as command-line programs or interactive applications, written in C++, Java, C# or Visual Basic. The Xll Wrapper toolkit contains tools, a runtime library, samples and documentation to help with the development of COM modules and .NET assemblies that wrap Excel XLL add-ins"
An Excell add-in DLL might be written in C#. If so, then you can probably bypass Excel altogether. Might need a wrapper though.
check whether assembly is available in program files where you install the plguin,
reference that assembly directly to your c# project - check the object browser for your class, method or object
You should be able to use reflection to get access to your addin. try using The Reflector to see what's available.