how to pass window handle to c++ win32 dll from C# - c#

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.

Related

To share an exported C++ DLL event, within an external C++ Win32 Application

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!

Problems using methods from DLL - EntryPoints

I need to use a DLL created in C in a C # application. I have followed several ways seen on the internet and I can not use the methods that are supposed to be in the DLL.
When looking for the entrypoints I get 4, which are the following.
DllCanUnloadNow
llGetClassObject
DllRegisterServer
DllUnregisterServer
I'm trying with the following code:
[DllImport("DLL.dll", EntryPoint ="DllCanUnloadNow" ,CharSet = CharSet.Auto)]
public static extern int Open();
static void Main(string[] args)
{
Console.WriteLine(Open());
Console.ReadLine();
}
It doesn't matter what function I use, it returns always 0.
If I use a function called for example, asdf() I got 0.
Does anyone know how to use the DLL correctly? I think it's made as COM and I have a .lib file.
Thanks in advance.

BadImageFormatException error when using C++ .dll function for C#?

I am having trouble with using P/Invoke for C#. Here is the function (written in C++) that I am trying to call from the .dll:
string
BeatTracker::getName() const
{
return "Tempo and Beat Tracker";
}
And here is my code for trying to call this function:
[DllImport("qm-vamp-plugins.dll",EntryPoint="BeatTracker")]
public static extern string getName();
public QMTempo()
{
Console.WriteLine(getName());
}
What seems to be wrong? I am getting a BadImageFormatException. And how can I know what is wrong in future references aside from the vague names the IDE is giving me? I am using Visual Studio 2008 by the way.
Also I am using (but not sure if right) EntryPoint, to let it know that I am using the getName function from the BeatTracker class (because there are also getName functions for other classes, which are included in the single .dll file)
Thanks!
This exception can be caused by a mismath between the .NET runtime proc architecture used and the imported dll one.
More precisely:
Do you use a 64bit Windows? The runtime will, by default, run in 64bit. If your C++ library was compiled targeting 32bit, you will get a BadFormatException upon library loading. The Same goes if your .NET app is running 32bit and your C++ library was compiled targeting x64.
If you can recompile the library, do it. Otherwise you can force the .NET runtime to use a specified architecture at compilation, but it will prevent it from running on the other architecture. It's your choice ;) When coding against .NET or java, we tend to forget what really happen under the hood.
[DllImport("qm-vamp-plugins.dll",EntryPoint="BeatTracker")]
The EntryPoint should be getName(), not BeatTracker which is a class!
But even then you cannot call that, because getName() is member function which cannot be callled without instance.
So I would suggest that define free functions in the DLL, and export them. You can use class internally, in the DLL. You can work with handle of classes.
Example,
DLL code:
typedef BeatTracker* PBeatTracker;
typedef PBeatTracker HBeatTracker;
//exported functions
HBeatTracker CreateBeatTracker()
{
return new BeatTracker();
}
void DeleteBeatTracker(HBeatTracker handle)
{
delete handle;
}
string getName(HBeatTracker handle)
{
return handle->getName();
}
C# Code:
[DllImport("qm-vamp-plugins.dll",EntryPoint="CreateBeatTracker")]
public static extern IntPtr CreateBeatTracker();
[DllImport("qm-vamp-plugins.dll",EntryPoint="DeleteBeatTracker")]
public static extern void DeleteBeatTracker(IntPtr);
[DllImport("qm-vamp-plugins.dll",EntryPoint="getName")]
public static extern string getName(IntPtr);
public QMTempo()
{
IntPtr handle = CreateBeatTracker();
Console.WriteLine(getName(handle));
DeleteBeatTracker(handle);
}

calling C++ "int WINAPI _tWinMain" from C#

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.

Defining extern "C" function in C#

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.

Categories