I have an ActiveX control written in C# and working when run in an ActiveX compatible program (CoDeSys). The problem I've come across is that in order to allow CoDeSys to interact with the ActiveX control, CoDeSys requires the dll to export the function prototype:
void ExecuteActiveXCall(IUnknown* pUnk, char* pszId, char* pszParam, char* pszReturnBuffer, int nReturnBufferSize, DWORD* pdwReturnFlag);
I've looked without success on how to export this like you can in C++, as shown in this example:
extern "C" __declspec (dllexport) void ExecuteActiveXCall(IUnknown* pUnk, char* pszId, char* pszParam, char* pszReturnBuffer, int nReturnBufferSize, DWORD* pdwReturnFlag)
{
if (strcmp(pszId, "IWebBrowser|GoBack") == 0)
{
IUnknown* pNewUnk;
IWebBrowser* pwb;
pUnk->QueryInterface(IID_IWebBrowser, (void**) &pNewUnk);
pwb = (IWebBrowser*) pNewUnk;
if (pwb)
{
pwb->GoBack();
pwb->Release();
}
}
else if (strcmp(pszId, "IWebBrowser|GoForward") == 0)
{
IUnknown* pNewUnk;
IWebBrowser* pwb;
pUnk->QueryInterface(IID_IWebBrowser, (void**) &pNewUnk);
pwb = (IWebBrowser*) pNewUnk;
if (pwb)
{
pwb->GoForward();
pwb->Release();
}
}
}
C# does have an extern keyword, but it doesn't allow you to provide the function definition (at least I haven't found a way). After attempting this:
extern unsafe void ExecuteActiveXCall(
[MarshalAs(UnmanagedType.IUnknown)] object pUnk,
char* pszId,
char* pszParam,
char* pszReturnBuffer,
int nReturnBufferSize,
UInt32* pdwReturnFlag)
{
}
The following error occurs:
'AlarmsCSharp.AlarmsControl.ExecuteActiveXCall(object, char*, char*, char*, int, uint*)' cannot be extern and declare a body
Has anyone attempted exporting a function in a C# dll?
Are there any workarounds? (I had the thought of [DllImport("AlarmsCSharp.dll")] and calling C# in the C++ dll, but figured I'd see if anyone had a solution before)
Perhaps I'm over thinking this and don't need to export this function since the ActiveX control is able to interact already with the C# code.
EDIT: I have a feeling my translation from the C++ function prototype to the C# interface declaration. If someone with more experience with C++/C# programming could verify that I did that translation correct or incorrect, it may be of some help.
You say that CoDeSys is ActiveX-compatible; have you tried using COM interop?
There seems to be 3 main options; the first is to set up COM interop where you can instantiate your C# control / class using COM. I'm sure if you do some searching you can find some more info on that.
The second option is to make your c++ module mixed managed/unmanaged, as described here:
http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/5345a27a-a614-4a74-9f6d-ea7a999ddf83/
The third option is to use "reverse PInvoke" as described here: http://tigerang.blogspot.com/2008/09/reverse-pinvoke.html
There may be other options; those are the ones I know of.
Related
Have a good day!
For portability reasons, i have created a C++ DLL with almost novice C++ knowledge just by searching thousands of pages, hundreds of compiling error corrections and couple of stackoverflow questions.
It is far beyond being stable but it is working most of the time :)
Just for curiosity and modularity reasons without importing the header and the cpp file to my application, i would like to ask your advice and help:
C++ Win32 Console Application
int main()
{
HMODULE lib = LoadLibrary(L"Serial.dll");
typedef void(*void_Connect)(UINT Port, UINT Baud);
void_Connect Connect = (void_Connect)GetProcAddress(lib, "Connect");
Connect(1, 9600);
}
I want to add an event into above C++ Win32 Console application, which will be triggered or hosted by the DLL
For example, a Received_Event(const char* data) or Connected_Event(BOOL status) with parameters.
Part from the DLL
typedef void(*fpCALLBACK) (const char* aParam);
static fpCALLBACK s_pCallback = NULL;
extern "C"
{
#define DLL __declspec(dllexport)
DLL void ReceivedEventRegister(fpCALLBACK p_pCallback)
{
s_pCallback = p_pCallback;
}
DLL void evntReceived(const char *receivedData);
}
DLL void evntReceived(const char *received)
{
s_pCallback(received);
}
I want to achive something similar to this C# version, with Standard C++
private static ManagedCallbackDelegate MessageCallbackDelegate;
public delegate void ManagedCallbackDelegate(string aParam);
[DllImport("Serial.dll", EntryPoint = "ReceivedEventRegister", CallingConvention = CallingConvention.Cdecl)]
private static extern void ReceivedEventRegister(ManagedCallbackDelegate callback);
static private void serialRecieved(string data)
{
Console.WriteLine(data);
}
static void Main(string[] args)
{
MessageCallbackDelegate = new ManagedCallbackDelegate(serialRecieved);
ReceivedEventRegister(MessageCallbackDelegate);
}
With C# code above, any data received by the DLL, the serialRecieved function is called in realtime. I want to achive this with Standard C++
I want to be informed or be aware of with the DLL process in realtime, in my Win32 C++ Console Application. ( Without blocking the Win32 Console application )
No MFC. if it is possible, no Component Object Model (It is possible with C# without need to convert the DLL into a COM). if it is possible, I want to do it with Standard C++.
I am compiling things with Visual Studio 2017 Community
Please go easy with me. It is a hobby for me and i just do it in my spare time.
Questions
Can you reference me some code examples written for this purpose, you are aware of?
Is there any specific name for this kind of communication that i can Google?
Is there any approach, you can suggest?
Thank you!
Once again, thanks to #dxiv's comment; helped me a lot, to sort things out! Even, when someone tells you that it should work, you resolve 90% of the problem.
At the DLL side
DLL void evntReceived(const char *received)
{
s_pCallback(received);
}
The DLL is calling the above function all the time as soon as it receives any data. To get that data realtime in your Win32 C++ Application, you need to import the DLL function which is calling the above callback function. Which is this
DLL void ReceivedEventRegister(fpCALLBACK p_pCallback)
part of the DLL.
As the DLL function's parameter type name fpCALLBACK suggests, our function parameter has to be as it is defind in the DLL:
typedef void(*fpCALLBACK) (const char* aParam);
At the Application side
//Callback Function: A function that is passed to another function as an argument
void Event_Received(const char *recvd)
{
std::cout << recvd << std::endl;
}
int main()
{
HMODULE lib = LoadLibrary(L"Serial.dll");
typedef void(*void_Connect)(UINT Port, UINT Baud);
void_Connect Connect = (void_Connect)GetProcAddress(lib, "Connect");
// Type definition of the function pointer.
// In our case: a Void type, which takes in a
// void type function pointer with a parameter (const char *aParam)
// dllCALLBACK is just a type name; you can name it whatever you want.
typedef void(*dllCALLBACK) (void(*fpCALLBACK) (const char* aParam));
// Now we will import the function from our DLL which takes
// the same parameters as we defined above, to call
// our callback function
dllCALLBACK ReceivedEventRegister = (dllCALLBACK)GetProcAddress(lib, "ReceivedEventRegister");
// Call the callback function with the imported function above.
// And that is all there is to it. As soon as any data received
// by our DLL - our Event_Received callback function
// fires in our C++ Win32 Console Application
ReceivedEventRegister(Event_Received);
Connect(1, 9600);
}
If you are a novice like me this video may help you to understand about Callback functions.
Thank you #dxiv again, taking time to read and answer my question!
I have one project which capture images from multiple cameras which is in C++ .I want to use that project in my new project which is in C#.I had made dll of that project.My question is ,how can i use that dll in my project.I know by passing window handle to C++ dll we can use it but i dont know how to do it and what changes should i make in dll.
Please forgive ,if it is foolish question.
I had the exact problem as you and this article helped me.
http://blogs.msdn.com/b/jonathanswift/archive/2006/10/03/dynamically-calling-an-unmanaged-dll-from-.net-_2800_c_23002900_.aspx
To pass the handle, you can add another function in C++ end. Something like,
(in the header)
extern "C" __declspec(dllexport) void SetParent(HWND hWnd);
To use the SetParent in C#
class Program
{
...
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SetParent(IntPtr hWnd);
public void testMethod()
{
...
IntPtr getAddress = NativeMethods.GetProcAddress(pDll, "SetParent");
...
SetParent setParent = (SetParent)Marshal.GetDelegateForFunctionPointer(getAddress, typeof(SetParent));
setParent(this.Handle);
...
}
}
If your C++ project is already in a DLL you can call any functions that it exports using P/Invoke. You will have to declare the method in your C# assembly as shown below, but then you can call it like a standard static method.
[DllImport("YourDllsName.dll")]
public static extern bool FunctionThatAWindowHandleAndReturnsBool(IntPtr hWnd);
Depending on the types of parameters that your C++ DLL's functions take the marshaling of the .Net datatypes to C data types can get complicated.
I am trying to call a function from a DLL generated in LabVIEW. I thought this was going to be far more straightforward than it is turning out to be. The function is described below:
void __cdecl Device_Init(char DevName[]);
So in my C# code I am trying the following:
[DllImport(#"Device.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void Device_Init(StringBuilder name);
I call this in my application by simply using the following:
StringBuilder devName = new StringBuilder(DeviceName);
Device_Init(devName);
Rather than getting any initialization on my device, I see a LabVIEW vi window pop up that has a title akin to a different method within the dll (i.e. AF1_GetPressure.vi). The application then hangs with this LabVIEW window popped up and I have to exit the debugging session.
I guess my question is how my function signature might be erroneous... I used StringBuilder as I found an example on the NI website that seemed to indicate that LabVIEW requires this variable type to better ascertain the number of characters in the array. http://www.ni.com/example/31050/en/
I have tried all kinds of different combinations of parameter types but I simply can't seem to get this to work. If I try calling the dll from C++ then I can get things to work. Although, oddly, I had to dynamically load the dll in C++ because I was getting a dll initialization failure when I tried to load it with the application.
Any help would be greatly appreciated!
I was able to build a DLL with LabView 2012, and import it into a .NET 4.0 console application, call the function, and receive a result. Here is a screenshot of the VI:
And here is the import statement in C#:
[DllImport(#"SharedLib.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int StringLength(string str);
I would recommend trying something very simple like this and see if you can get it working.
I should note that I tried passing my parameter as a StringBuilder object and that worked as well - and I didn't expect it to!
Also, I recommend posting this question on the LabView forums. I was always able to get a very quick response there, and I think with LabView, you're likely to get a better response there than StackOverflow.
As requested, here are the contents of the .h file generated by LabView:
#include "extcode.h"
#pragma pack(push)
#pragma pack(1)
#ifdef __cplusplus
extern "C" {
#endif
/*!
* StringLength
*/
int32_t __cdecl StringLength(char String[]);
long __cdecl LVDLLStatus(char *errStr, int errStrLen, void *module);
#ifdef __cplusplus
} // extern "C"
#endif
#pragma pack(pop)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
A call to PInvoke function '[…]' has unbalanced the stack
I'm trying to wrap a few functions written in c++, in order to use them in a c# program (WPF, or as an example a console app), but get run-time exceptions.
I guess this is a compilation issue (of either the c++ project of the C# one). When I change the platform target for the C# projects, I get different exceptions. when the platform target is x64 I get
An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
When I try to compile it as x86, I get:
A call to PInvoke function 'Wrapper!Wrapper.IWrapper::create' 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.
I'm running VS2010 on windows 7 64.
Would be happy for any ideas on how to solve this.
This is what I do:
c++ code. cpp:
int create(int Handle)
{
return 1;
}
and h:
#define EXPORT_DLL __declspec(dllexport)
extern "C"
{
EXPORT_DLL int create(int Handle);
}
Then in a second C# project, I call this dll, where the c++ project's name is wrapAttemptC
namespace Wrapper
{
internal class IWrapper
{
const string SHADOW_DLL_NAME = "wrapAttemptC.dll";
[DllImport(SHADOW_DLL_NAME)]
public static extern int create(int Handle);
}
public class CWW
{
public CWW(){}
public int Connect(int cam)
{
return IWrapper.create(cam);
}
}
}
Then, I put the DLL file created in the c++ project in the bin/Debug of this c# project and of the app c# project (WPF), and try to call
CWW cww = new CWW();
cww.Connect(5);
The default calling convention for C++ exported functions is cdecl, but the default calling convention for the DllImport attribute is WinApi (which defaults to stdcall). So you have a mismatch there that could indeed mess up your stack. Try stating the calling convention explicitly in the DllImport Attribute, your C++ function declaration, or better, both (so that they match). Like this:
EXPORT_DLL __stdcall int create(int Handle);
And in your C# project:
[DllImport(SHADOW_DLL_NAME, CallingConvention = CallingConvention.StdCall)]
I can access a method from a C++ Dll using C# using this method in the C++:
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL()
{
printf ("Hello from DLL !\n");
}
}
this works great...but the solution I am working with uses this as the entry point:
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE /*hPrevInstance*/,
LPTSTR lpCmdLine,
int /*nShowCmd*/)
Is there a way I can access this like I have done with the __declspec method?
Cheers
That is not a DLL entry point, that is a primary application entry point. You will need to create it as a new process via CreateProcess.
_tWinMain is actually a #define to either WinMain or wWinMain. You also need to make sure it's actually exported.
That being said, why would a DLL have a WinMain function at all? You should just export a normal function like DisplayHelloFromDLL.
[edit]
The project you are trying to reference -- the one with _tWinMain -- is an EXE (as #DeadMG says). You should not try to import its functions from C# like you do with DLLs; instead you should launch it with Process.Start.
The answer was to call a function created in the C++ using:
extern "C"
{
__declspec(dllexport) void StartAgent()
{
printf ("Starting Agent... \n");
StartServer(true);
RunMainLoop();
}
}
This is then called in the C# using:
[DllImport("myDll.dll")]
public static extern string StartAgent();
StartAgent();
Calling this from the C# and into the C++ gets the application running.