|
Hi,
I'm doing a simple managed C++ class to grab data from a USB device and pass it to the C# side.
This is my class:
public __gc class Communication<br />
{<br />
private:<br />
LPVOID dataInBuffer; <br />
HANDLE _hFileHandle;<br />
int nBytesToRead; <br />
int maxPacketSize;<br />
<br />
public:<br />
<br />
Communication()<br />
{<br />
_hFileHandle = INVALID_HANDLE_VALUE;<br />
<br />
maxPacketSize = 256;<br />
dataInBuffer = malloc(sizeof(char) * maxPacketSize);<br />
nBytesToRead = maxPacketSize;<br />
}<br />
<br />
~Communication()<br />
{<br />
if( _hFileHandle != INVALID_HANDLE_VALUE )<br />
{<br />
CloseHandle( _hFileHandle );<br />
}<br />
}<br />
<br />
bool OpenDevice( String* driverName )<br />
{<br />
char* lpFileName = new char[driverName->Length + 10];<br />
<br />
sprintf( lpFileName, "\\\\?\\%s", driverName );<br />
<br />
_hFileHandle = CreateFile((LPCSTR) lpFileName,GENERIC_READ,0,0,OPEN_EXISTING,0,0);<br />
<br />
if( _hFileHandle == INVALID_HANDLE_VALUE )<br />
{<br />
puts("Couldn't not open device");<br />
}<br />
<br />
delete lpFileName;<br />
<br />
return( _hFileHandle != INVALID_HANDLE_VALUE );<br />
}<br />
<br />
BOOL CloseDevice()<br />
{<br />
return CloseHandle( _hFileHandle );<br />
}<br />
<br />
int GetPacket()<br />
{<br />
char outBuffer[256];<br />
<br />
int nBytesRead = -1;<br />
<br />
if (_hFileHandle!=INVALID_HANDLE_VALUE)<br />
{<br />
ReadFile(_hFileHandle, dataInBuffer, nBytesToRead, (PULONG) &nBytesRead,0);<br />
}<br />
<br />
memset(outBuffer,0,maxPacketSize*sizeof(char));<br />
memcpy(outBuffer,dataInBuffer,maxPacketSize*sizeof(char));<br />
<br />
return nBytesRead;<br />
}<br />
};
My problem right now it how to pass the outBuffer variable in the GetPacket method outside the class.
If I let the variable being declared inside the function, it gets erase when the function ends and my data goes with it.
If I declare that variable in the class itself, the compiler says the following:
'outBuffer' : must explicitly specify __gc or __nogc for an array declared in a managed type
And if I put the __gc attribute on the variable, then the compiler tells the following:
'identifier' : '__gc' can only be applied to a class, struct, interface, array or pointer
So... what do I have to do in order to make this variable available in the C# side?
I'm using char, because I need a signed 8-bit value on each position of the array.
Can anyone give me some lights here?
Thanks,
Nuno
|
|
|
|
|
You are using the obsolete Managed C++ syntax. Are you using a compiler that don't support C++/CLI? If not, I would suggest you to rewrite this in C++/CLI.
|
|
|
|
|
Hi,
You could try something like this:
#pragma once
#include <memory.h>;
#include <string.h>;
using namespace System;
namespace CnvBuffLib
{
public __gc class ConvertBuffer
{
const char __nogc * const _buffer;
static const int bsize = 256;
public:
ConvertBuffer()
: _buffer(new char __nogc [bsize])
{
}
~ConvertBuffer()
{
delete [] _buffer;
}
int GetPacket()
{
char tmp[] = {'t', 'e', 's', 't'};
int tmplen = sizeof(tmp);
char __nogc * _bp = const_cast<char*>(_buffer);
_bp = static_cast<char*>(memset(_bp, 0, bsize));
memcpy(_bp, tmp, tmplen);
return tmplen;
}
SByte GetData() __gc []
{
int rlen = strlen(_buffer);
if(rlen == 0)
return 0;
SByte result[] = new SByte[rlen];
char __pin * presult = &result[0];
memcpy(presult, _buffer, rlen);
return result;
}
};
}
|
|
|
|
|
CComPtr<iwshruntimelibrary::ifilesystem>fileSystem;
fileSystem->DeleteFolder((wchar_t*)ServerPath, VARIANT_TRUE);
fileSystem->DeleteFolder() is failing . Can I know when this happens and what could be the solution.
Thanks.
|
|
|
|
|
Read return code into a HRESULT and identify the return code.
|
|
|
|
|
It is most unlikely that the poster of this question is still waiting for an answer nearly eleven years later.
|
|
|
|
|
hey, i'm new to managed c++, and i need to use managed c++ to perform some tasks. I am using capicom.dll to create an application which will be able to sign, verify, encrypt,etc. only encrypt function requires the use of managed functions (to get file as bytes, convert to base-64 string and then encrypt), whereas the sign function does not require any managed code. even so, I am getting a System.Runtime.InteropServices.SEHException error on the signing function. here is the code which deals with the signing part:
if(cert->HasPrivateKey())
{
signedData->Content = "This is a string";
signer->PutCertificate(cert);
_bstr_t text = signedData->Sign(signer,true,CAPICOM_ENCODE_BASE64);
return text;
}
I have traced the code to fail at the Sign(signer,....) part. signer is the certificate being used to sign the data with, signedData and signer variables have been initialized with the __uuidof method, which is also how i've initialized encrypt and verify functions in their code sections.
the debugger takes me inside the capicom.tli file and fails. here is the tli code block which fails:
inline _bstr_t ISignedData::Sign ( struct ISigner * pSigner, VARIANT_BOOL bDetached, enum CAPICOM_ENCODING_TYPE EncodingType ) {
BSTR _result = 0;
HRESULT _hr = raw_Sign(pSigner, bDetached, EncodingType, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _bstr_t(_result, false);
pSigner, bDetached, and EncodingType get their proper values, but the _result variable keeps getting set to <undefined value>
any suggestions would be most welcomed on what i might do or what might be going wrong here.
the error on debugger output is (at line: raw_Sign(pSigner, bDetached, EncodingType, &_result); )
First-chance exception at 0x7c81eb33 in CAPICOMGUI.exe: Microsoft C++ exception: _com_error at memory location 0x0012d708..
A first chance exception of type 'System.Runtime.InteropServices.SEHException' occurred in CAPICOMGUI.exe
An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in CAPICOMGUI.exe
Additional information: External component has thrown an exception.
hope i was clear enough
|
|
|
|
|
My best guess is that there's something about the pSigner pointer that it's choking on.
You say that the sign function does not call any managed code, but that the other functions do.
Is it possible that the pSigner object contains pointers to managed objects that the "raw_Sign" function doesn't understand?
|
|
|
|
|
thanks for the reply Richard. I assumed it was pSigner as well at first. pSigner is a pointer to a certificate (stored on the computer), certificate variable being initialized as ICertificate2Ptr cert (this initialization also exists in functions such as verify,encrypt, decrypt that are also calling managed variables)
I checked what all it was passing on signing and encryption and this is what I noticed:
on this line:
_bstr_t text = signedData->Sign(signer,true,CAPICOM_ENCODE_BASE64);
signer had the values (on hovering mouse over the variable):
-signer: 0xhexvalue
-m_pInterface: 0xhexvalue
-IDispatch: {...}
-IUnknown: {...}
-__vfptr: 0xhexvalue
[0]: values
[1]: values
[2]: values
and once it was passed onto the inline raw_Sign function the values were:
- pSigner: 0xhexvalue
-IDispatch: {...}
-IUnknown: {...}
-Children could not be evaluated
this was also the case on the encrypt function (when running encryption function only, and no other function), yet it worked. all the variables otherwise (in the raw_Sign) were holding thier proper values. Do you think its failing because of the "Children could not be evaluated" part? If so, is there anything I can do to pass values successfully?
|
|
|
|
|
UserNameless wrote: Do you think its failing because of the "Children could not be evaluated" part?
That's where my suspicions would fall. Unfortunately, COM is not my strength.
I'm interested to know why the "children" CAN be evaluated when the debugger is stopped on the outside of the function call, but once we go inside the function, then the children can no longer be evaluated.
|
|
|
|
|
Richard Andrew x64 wrote:
That's where my suspicions would fall. Unfortunately, COM is not my strength.
No worries, appreciated your thoughts on the problem.
Richard Andrew x64 wrote: I'm interested to know why the "children" CAN be evaluated when the debugger is stopped on the outside of the function call, but once we go inside the function, then the children can no longer be evaluated.
Yes this was as interesting point to me as well. Thanks for the thoughts. I guess it can't be helped as the pointers are defined in the capicom.dll already
|
|
|
|
|
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.
|
|
|
|
|