|
One last remark, if I may:
You might try constructing a test project to call the CAPICOM dll from native code and see if the error still happens.
Good luck.
|
|
|
|
|
Funny that you should mention it. I did have a backup of a native code which simply signed data, and worked as I wanted/expected it to, it would generate the signed hash as expected. But after I ran this (managed) project a few times (in a separate VS 2008), I went over to test my native application, which surprisingly now, also started giving me this same error. I assume it's a bug of having porting my project from VS 2005 to VS2008.
|
|
|
|
|
I've posted on here several times and gotten nothing but great advice, so I once again return with my most recent C++/CLI headache.
First, I have some native code, which I wrapped in a C++/CLI library, and the result was MyLib.dll. I've gotten this working very well with C#, but would like to produce some example code in VC++ and VB, and can't seem to figure out how to get those two working.
I could compile the C# program using:
$ csc /nologo /platform:x86 TestProgram.cs /r:MyLib.dll
I know pretty much nothing about VB and don't really know what's different between VC++ and regular C++. What I'm looking for are instructions on what I need to do to convince a VC++ program and a VB program to talk to MyLib.dll. Much of what I found on the internet either looked dated, or mandated the presence of .lib files.
Long story short, what steps need to be taken to call functions defined in a C++/CLI .dll from VC++ and VB code? Any and all advice is very much appreciated!
|
|
|
|
|
Shadowsoal wrote: looking for are instructions on what I need to do to convince a VC++ program and a VB program to talk to MyLib.dll.
MyLib.dll is a mixed mode DLL (compiled using /clr switch), right?
Communicating with a mixed mode DLL from native code is tough. I guess, you need to use conditional compilation and expose the interfaces for managed and unmanaged clients depending upon the compiler options. _MANAGED is a macro which will be defined when /clr compilation switch is used. Make use of this macro to decide the functions you need to expose to native clients. You need to provide a header file as well for native clients as they can't read from the assembly meta data.
I haven't tried the above, but I believe it should do the trick.
|
|
|
|
|
After doing some more reading, it seems I've erred. So from what I've gathered on Wikipedia, Visual C++ is actually just an IDE which is used to develop C, C++ and C++/CLI. My initial impression was that VC++ was a separate language. From what I understand people really only code in C++/CLI to provide access to unmanaged code for managed programs. Someone coding in C++ or C can access the underlying C SDK directly, so there shouldn't be any issue there.
The purpose of what I'm doing is to allow a user who is programming in a .NET language access to an unmanaged C SDK. At this point I've got all the functionality I want in a C++/CLI wrapper and am just whipping up example code. I don't really know much about the .NET framework, I'm not a .NET programmer and haven't really looked into it extensively. I know we have clients who use C# and VB. What I am trying to do is put together some example code for the clients' sake, and as a sanity check to ensure that my wrapper works with the languages that it will get used with.
C# - Good to go, all my testing was done with C#, and it works.
VB - I've never programmed in VB, don't know much about it... What I do know is my code needs to work with it. I'm sure I can figure out the basics of the language, enough to convert my C# example code to VB code. What I'm more worried about is figuring out the mechanism necessary to access my C++/CLI DLL from VB.
So I guess I have two real questions...
First, given a C++/CLI DLL, MyLib.dll , compiled as follows:
$ cl /nologo /clr /LD /FeMyLib.dll MyLib.cpp UnmanagedLib.lib
$ mt /nologo /manifest MyLib.dll.manifest /outputresource:MyLib.dll;2
And a VB program: TestProgram.vb
What do I need to do to allow TestProgram.vb the ability to construct objects defined in MyLib.dll and use said objects' subroutines.
Second, what other .NET languages are widely used, and consequently should be tested?
|
|
|
|
|
I suppose I should have a little more faith in myself. Convincing a VB application to talk with my C++/CLI DLL was as easy as it was in C#. Just had to add the /r:MyLib.dll flag when compiling and it works.
So I suppose the real question now is what other .NET languages are widely used, such that I should provide some example code.
|
|
|
|
|
Shadowsoal wrote: So I suppose the real question now is what other .NET languages are widely used, such that I should provide some example code.
C# and VB.NET are widely used in .NET world.
|
|
|
|
|
If those are the only two .NET languages which are really heavily used, then it looks like I'm done. Since I now have fully functioning C# and VB.NET examples.
|
|
|
|
|
Great Glad to hear that.
|
|
|
|
|
Hi All,
As the title suggests, I have some C code serving as an API for interacting with a certain device. We're in the process of porting the current console application to a GUI app that uses Windows Forms via C++. Some of the C code takes function pointers as callbacks, and I'm currently struggling with figuring out how to pass managed C++ delegates in as those parameters.
Here's what I have so far - from Form1.h:
public: delegate void FuncCallbackDelegate(String^ str, int status);
public: void funcCallback(String^ str, int status)
{
printf("Passed in string: %s\n", str);
}
private: System::Void btnStartTest_Click(System::Object^ sender, System::EventArgs^ e)
{
FuncCallbackDelegate^ FuncDelegate = gcnew FuncCallbackDelegate(this, &Form1::funcCallback);
int retval = CFunction("Dummy path", Marshal::GetFunctionPointerForDelegate(FuncDelegate).ToPointer());
}
Some more code - this time from the .h file included in my Windows Form app:
#ifdef __cplusplus
extern "C" {
#endif
int CFunction(char *src_path, void (__stdcall *func)(const char *,int ));
#ifdef __cplusplus
}
#endif
And lastly, the C function itself:
int CFunction(char *src_path,void (__stdcall *func)(const char *, int))
{
if (func != NULL)
{
func("Test Output String", 1);
}
return 1;
}
I understand why the failed line fails - Marshal::GetFunctionPointerForDelegate(FuncDelegate).ToPointer() causes this error:
<br />
error C2664: 'CFunction' : cannot convert parameter 2 from 'void *' to 'void (__cdecl *)(const char *,int)'<br />
My question is, what do I need to do to allow a Managed C++ function to be passed in to a C function as a callback? (I tried using #pragma unmanaged and #pragma managed flags to no avail)
Thank You.
|
|
|
|
|
KawiRider wrote: int retval = CFunction("Dummy path", Marshal::GetFunctionPointerForDelegate(FuncDelegate).ToPointer()); // THIS LINE FAILS
I'm assuming your C code is in a separate DLL....
If you use platform invoke to call the C function then you should only need
something like this:
delegate void FuncCallbackDelegate(String^ str, int status);
[DllImport("My_C_Dll.dll", CharSet = CharSet::Ansi, CallingConvention = CallingConvention::StdCall)]
extern "C" int CFunction(String ^src_path, FuncCallbackDelegate ^del);
...
public: void funcCallback(String^ str, int status)
{
printf("Passed in string: %s\n", str);
}
private: System::Void btnStartTest_Click(System::Object^ sender, System::EventArgs^ e)
{
FuncCallbackDelegate^ FuncDelegate = gcnew FuncCallbackDelegate(this, &Form1::funcCallback);
int retval = CFunction("Dummy path", FuncDelegate);
}
...
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hi,
Thanks for your reply. I apologize but I forgot to specify that we are actually using a .lib instead. I did, however, start a new project as a Win32 DLL and "successfully" generated a .dll. I use the term "successfully" loosely because although after making your suggested changes and hopefully configuring the .dll correctly, my program compiles flawlessly but at run-time I get the error
<br />
An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in driver.exe<br />
<br />
Additional information: External component has thrown an exception.<br />
On this line:
int retval = CFunction("Dummy path", FuncDelegate);
I've been scouring the net for resources on creating a C dll (though ideally I'd rather use the lib that was provided to us) and it appears as if I'm doing it correctly.
My_C_Dll.c
#include "My_C_Dll.h"
__declspec(dllexport) int __cdecl CFunction(char *src_path,void (*func)(const char *, int))
{
if (func != NULL)
{
func("Test String", 1);
}
return 1;
}
My_C_Dll.h
<code>
#ifdef __cplusplus
extern "C" {
#endif
</code>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
__declspec(dllexport) int __cdecl CFunction(char *src_path,void (*func)(const char *,int ));
<code>
#ifdef __cplusplus
}
#endif
</code>
Additionally, I placed these lines:
delegate void FuncCallbackDelegate(String^ str, int status);
[DllImport("My_C_Dll.dll", CharSet = CharSet::Ansi, CallingConvention = CallingConvention::StdCall)]
extern "C" int CFunction(String ^src_path, FuncCallbackDelegate ^del);
directly below all of the using namespace ... and right above the Form1 class definition.
Again, thank you for taking the time to provide assistance.
|
|
|
|
|
KawiRider wrote: I forgot to specify that we are actually using a .lib instead
Maybe just a cast was needed in the original code. This should work:
delegate void FuncCallbackDelegate(String^ str, int status);
...
public: void funcCallback(String^ str, int status)
{
printf("Passed in string: %s\n", str);
}
private: System::Void btnStartTest_Click(System::Object^ sender, System::EventArgs^ e)
{
FuncCallbackDelegate^ FuncDelegate = gcnew FuncCallbackDelegate(this, &Form1::funcCallback);
int retval = CFunction("Dummy path", (void (__stdcall *)(const char *, int))Marshal::GetFunctionPointerForDelegate(FuncDelegate).ToPointer());
}
...
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark,
Thank you! Reverting back to the original code and implementing that cast did the trick.
|
|
|
|
|
Looking at the documentation of GetFunctionPointerForDelegate[^]:
The delegate d is converted to a function pointer that can be passed to unmanaged code using the __stdcall calling convention.
You must manually keep the delegate from being collected by the garbage collector from managed code. The garbage collector does not track reference to unmanaged code.
So Mark's code has a race condition: the GC might collect the delegate while it's still used.
Add a call to GC.KeepAlive(FuncDelegate); after the CFunction call to ensure the delegate will live long enough.
|
|
|
|
|
I have asked on the VC++ forum on MSDN for an app that provides somewhat of an illustration of a legacy C++ app migrated to C++/CLI.
I have been unsuccessful so far. I have a C++ console exe app that I need to wrap that in a managed class so I can call it using C#. I can post code if necessary. The program is not that big but there was a pop-up dialog that claimed otherwise.
I don't know if I should create a dll out of it and export functions or something else
Appreciate any help offered. Please re-direct if this is the wrong forum.
Al
Jer 29:11
|
|
|
|
|
|
I too have looked on the forums. It seems from numerous threads in my searches that my requirements are indeed not specific and very much in line with what developers are looking to do. That is, migrate console legacy code to that with a UI front end and wrap that in a managed dll or convert to unmanged dll and call it via IJW or P/Invoke.
One source of help is located here http://cfx.codeplex.com/[^]
I strongly recommend it as I am going through it and find a ton of useful example and resources. It seems it's been created for those asking questions similar to mine and designed as an aid to the solution
Al
Jer 29:11
|
|
|
|
|
Hi All,
I'm a developer with most of my experience in MFC, C#. Recently, I've been assigned to a project that has a Borland C++ 6 (OWL) GUI and a VC6.0 DLL that does most of the work. The VC6 DLL has around 1500 functions declared as extern "C" __stdcall (1500??!! I know... seriously! )
Now I've been delegated with the job of replacing the BOrland GUI with a new console/GUI mode application (in C#).
Hence, I decided to write a Managed C++ wrapper for this native DLL, and then write my application in C#.
The downside is that I don't have access to the source code for the VC6 DLL. I felt that a managed c++ DLL project which statically links to the .lib file for the VC6 native DLL might be the best approach.
I've created a Managed C++ CLR Class library project, which has a reference to the unmanaged VC6 .lib file (from Project Properties -> Linker -> Input -> Additional Dependencies. I've also added the header file for the DLL to this project.
I have created a managed class which wraps all the functions in the unmanaged DLL in a function.
Header file
#pragma once
#pragma comment(lib, "C:\\Sources\\lib\\native.lib")
#include "..\..\Common\include\native.h"
#include "Common.h"
#using <System.dll>
#using <System.Windows.Forms.dll>
using namespace System;
using namespace System::Windows::Forms;
namespace MC_SAMPDLL
{
public ref class MCSAMP
{
MYRESULT MC_Func1(int handle, unsigned int timeout)
{
return ::Func1(handle, timeout);
}
};
}
For example if the unmanaged function is Func1(), I'm creating a wrapper function MC_Func1().
MCSAMP::
However, when I try to call any unmanaged function from within the managed wrapper, I get linker errors as below
Error 1 error LNK2028: unresolved token (0A000012) "extern "C" enum MYRESULT __stdcall Func1(int,unsigned int)" (?Func1@@$$J18YG?AW4MYRESULT@@HI@Z) referenced in function "private: enum MYRESULT __clrcall MC_SAMPDLL::MCSAMP::MC_Func1(int,unsigned int)" (?MC_Func1@MCSAMP@MC_SAMPDLL@@$$FA$AAM?AW4MYRESULT@@HI@Z) MC_SAMPDLL.obj MC_SAMPDLL
Error 2 error LNK2019: unresolved external symbol "extern "C" enum MYRESULT __stdcall Func1(int,unsigned int)" (?Func1@@$$J18YG?AW4MYRESULT@@HI@Z) referenced in function "private: enum MYRESULT __clrcall MC_SAMPDLL::MCSAMP::MC_Func1(int,unsigned int)" (?MC_Func1@MCSAMP@MC_SAMPDLL@@$$FA$AAM?AW4MYRESULT@@HI@Z) MC_SAMPDLL.obj MC_SAMPDLL
Error 3 fatal error LNK1120: 2 unresolved externals C:\Sources\CLI SAMP\MC_SAMPDLL\Debug\MC_SAMPDLL.dll MC_SAMPDLL
The original unmanaged function is defined as extern "C" MYRESULT __stdcall Func1(int, unsigned int);
When I wrote a similar example with my own functions, it seems to work fine. However, in the case of these sources, I'm getting these link errors.
I'm at my wits end here, and the first implementation deadline is looming ahead of me. I'd be really grateful if you could help me out here...
Thanks a lot,
'The time has come,' the Walrus said,
'To talk of many things:
Of shoes -- and ships -- and sealing wax --
Of cabbages -- and kings --
And why the sea is boiling hot --
And whether pigs have wings.'
-- The Walrus and the Carpenter (by Lewis Carroll)
|
|
|
|
|
Hi,
Since I couldn't find any solution to the problem, nor are there any replies here in this forum I finally decided to go in for a C# based P/Invoke method of calling the native DLL. I know it sucks compared to the MC++ wrapper solution, but hey, at least it works!
For those who are stuck in a similar situation, they can try using the [PInvoke Interop Assistant]. This is a wonderful open source tool that makes it really simple to create an automated wrapper for native dlls. There are a few articles in MSDN magazine on how to use this tool too.
It comes with a command-line interface that allows easy porting of entire header files in the easiest manner possible. Just supply your header files to this tool, and it'll write out almost the entire wrapper declarations. Just to make sure though, you should manually examine all the ported declarations, ensuring that no mistakes are present.
Hope this helps someone else,
Bharat
'The time has come,' the Walrus said,
'To talk of many things:
Of shoes -- and ships -- and sealing wax --
Of cabbages -- and kings --
And why the sea is boiling hot --
And whether pigs have wings.'
-- The Walrus and the Carpenter (by Lewis Carroll)
|
|
|
|
|
Hi!
I'm referring on the article Calling Managed Code from Unmanaged Code and vice-versa[^], where callback functions in managed C++ code is called from unmanaged code using delegates.
On that way I have programmed a Windows Forms GUI, whose functions are delegated to unmanaged (because I had an unmanaged Interface to implement). The whole marshalling is done in one VS-project.
Now I want to compile it as DLL and call the unmanaged functions to control the GUI:
PROBLEM: To initialise the callbacks the first thing to do is to call managed code to activate the delegates and so the callbacks.
Now it would be nice to do that in the DLL-main function (entry point). But it is not possible to call managed code in DLL main, what should I do?
I want to initialize the callbacks on DLL loading, so that the functions are directly useable.
Any idea?
Thanks, cherry
|
|
|
|
|
What you can do is have a flag variable that keeps track of whether the delegates are initialized.
Then, in every exported function, the first thing you do is check to see if the delegates have been initialized.
If they have not been initialized (according to the flag variable,) then you call the initialization function from there.
That way, the initialization is performed on the thread that is calling your Dll, instead of the thread that is calling DLLMain.
|
|
|
|
|
Any chance, anyone has code to maintain the format:
(###) ###-####
for a CEdit? There are some masked edit controls, but I
cant get them to blend in with what I have. Im just looking
for something small to let me maintain the above phone
format.
Please, any response any one can give me will be greatly
appreciated.
Sincerely,
Danielle Brina
|
|
|
|
|
i'm not sure about CEdit. That looks like an MFC control. You might have better luck in the C/C++/MFC forum.[^]
if you're looking for a C++/CLI way of doing this you could use a MaskedTextBox.[^] If you must use a CEdit control you could use .net to validate the text entered using a Regular Expression.[^]
Hope this helps,
Don't be overcome by evil, but overcome evil with good
|
|
|
|
|
// IN C++ /clr
// BOXED VALUE TYPE ON GC HEAP
int ^ gc_i = gcnew int;
// WHAT EXACTLY IS THE STORAGE TYPE FOR THIS int ?
int * i = new int;
*i = 5;
// PRESUMABLY ON THE UNMANAGED HEAP, BUT HOW CAN THIS HAPPEN FOR INT?
// DOESN'T INT ALWAYS MAP TO System.Int32?
// OR DOES THE COMPILER GIVE US A NATIVE INT INSTEAD, TO PLACE ON THE UNMANGED HEAP?
|
|
|
|
|