|
Hi luc,
thantks for advice.
Reading your article, I had an idea:
- I haven't used gcroot but directly GCHandle.
- I must casting because parameter library function is void*.
This is what I've done:
1) I 've used GCHandle to build an handle to object (for my example FORM1) and I've used GCHandle.Alloc() to reserve memory when i send object refer from managed code to unmanaged library. I' ve done this in the constructor. So it is:
Form1(void)
{
InitializeComponent();
evento=gcnew eventRegistered(Form1::cdeclEventCallback);
gch =GCHandle::Alloc(evento);
ip=Marshal::GetFunctionPointerForDelegate(evento);
cb=static_cast<eventCallback_t>(ip.ToPointer());
GC::Collect();
gch3=GCHandle::Alloc(this);
this->registerEvent();
}
2) I've used GCHandle::ToIntPtr to obtain pointer of handle to send like parameter.I've done this in my registerEvent() function when i call library funciton. registerEvent() now is:
void Form1::registerEvent()
{
error_status er_return=TED_PixRad_RegisterEventCallback(cb,(void*)(GCHandle::ToIntPtr(gch3)));
if (this->TestError(er_return)){
this->button2->Visible=true;
}
}
3) Since library function receives void* customData parameter and it returns this in callback function, I must cast my pointer Form1 refer from IntPtr to void*. After, in the callback function I must casting from void* to IntPtr and in second time I must casting from intPtr to Form1^.
The implementation of the callback funciton now is:
static void Form1::cdeclEventCallback(const event_id eventID, const Event *eventData, void* customData )
{
GCHandle gch4 = GCHandle::FromIntPtr((IntPtr)(customData));
Form1^ frm = (Form1^)gch4.Target;
frm->label3->Text="GESTIONE EVENTO";
frm->label3->Refresh();
frm->processEvent(eventID,"");
}
Now I must call processEvent like an object function and not like Form1 external function.
---------------------------------------------------------------
I compiled without problems and doing some tests I've seen that behavior is correct, that the occurrence of an event correctly calls the callback function and that this uses the correctly reference at Form1.
Less than denials I think the problem is solved, thank you all for your help.

|
|
|
|
|
I'm not sure I understand everything you're doing here, however I'm glad you got it working.
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|
Hello,
I'm a long time lurker on CodeProject, and finally have a problem that I'm getting nowhere on.
We have a C++ application we're building in VS2008 that uses "it just works" interop to create reports using Crystal Reports. So there is a C# ReportHandler (which contains a reference to the Report itself), and a C++/CLI ReportWrapper. If the ReportWrapper is built as a static lib, it works under both WinXP x32 and Win7 x64. However, when the ReportWrapper is built as a DLL, it works under WinXP x32 but crashes under Win7 x64 (it's built as a x86 application either way).
It crashes not when the app starts, but when you try to bring up the File:Open dialog using CFileDialog::DoModal(). The call stack is not obvious:
ntdll.dll!77158eb9() <br />
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] <br />
AcXtrnal.dll!60af9480() <br />
KernelBase.dll!76b54958() <br />
comdlg32.dll!769ee4ab() <br />
comdlg32.dll!769eea8b() <br />
comdlg32.dll!769cfa0e() <br />
comdlg32.dll!769b8a57() <br />
comdlg32.dll!769b876c() <br />
shell32.dll!750861ee() <br />
shell32.dll!75086159() <br />
ole32.dll!74dd09bf() <br />
shlwapi.dll!75d4b6cf() <br />
ntdll.dll!7718808e() <br />
ntdll.dll!77159fc5()
Here are the last few lines of the debug output window.
088c:0e48 @ 159626312 - LdrpRunInitializeRoutines - INFO: Calling init routine 64E71291 for DLL "C:\Windows\system32\NetworkExplorer.dll"<br />
088c:0e48 @ 159626312 - LdrpLoadDll - RETURN: Status: 0x00000000<br />
088c:0e48 @ 159626312 - LdrLoadDll - RETURN: Status: 0x00000000<br />
088c:0e48 @ 159626312 - LdrGetProcedureAddressEx - INFO: Locating procedure "DllGetClassObject" by name<br />
088c:0e48 @ 159626312 - LdrGetProcedureAddressEx - INFO: Locating procedure "DllCanUnloadNow" by name<br />
088c:0e48 @ 159626328 - LdrGetProcedureAddressEx - INFO: Locating procedure "PropVariantToUInt64" by name<br />
088c:0e48 @ 159626328 - LdrGetProcedureAddressEx - INFO: Locating procedure "PropVariantToInt32" by name<br />
088c:0e48 @ 159626328 - LdrGetProcedureAddressEx - INFO: Locating procedure "PropVariantToInt32WithDefault" by name<br />
088c:0e90 @ 159626328 - LdrGetProcedureAddressEx - INFO: Locating procedure "OpenThreadToken" by name<br />
First-chance exception at 0x77158eb9 in theapp.exe: 0xC0000005: Access violation writing location 0x00000014.<br />
088c:0e90 @ 159626328 - LdrGetProcedureAddressEx - INFO: Locating procedure "OpenProcessToken" by name<br />
Unhandled exception at 0x77158eb9 in theapp.exe: 0xC0000005: Access violation writing location 0x00000014.
If I force the "bVistaStyle" flag in CFileDialog to false, the dialog does work without crashing the app; however, it then causes strange out of memory errors later on when we try to actually load a file (using dynazip). That tells me that something nefarious is going on, other than just with the CFileDialog (I suspect some strange DLL corruption).
Other oddities:
- we have a similar Report/ReportHandler/ReportWrapper in a different application, and there are no problems with that app.
- if the app is built in release configuration under WinXP x86, it runs fine when installed on Win7 x64.
- if the app is built in release configuration under Win7 x64 (as an x86 project), it runs fine.
So it only crashes when running the debug build (whether debugging or not).
Here's what I've tried so far:
- I compared project settings between the app that works and the one that doesn't. As far as I can tell they're the same.
- I compared project settings between the Release and Debug configurations.
- I created a dummy test MFC app and started pulling in libraries/assemblies/dlls from the app that doesn't work; in the test app, however, the same Report/ReportHandler/ReportWrapper works properly. However, I have not pulled in all of the libraries that are linked into the app.
- I've reread about implementing IJW interop (someone else implemented it) to confirm we've set it up properly.
- I've tried depends (x86), but depends crashes when I try to profile the app.
- I've enabled loader snaps to try and see if anything odd is going on, but have limited experience looking at DLL loading.
- various and sundry other things that I can't think of right now, all to no avail (I've been struggling with this for a while).
Any suggestions on how to approach this problem would be most welcome. Given what's going on, I think there's actually a deeper problem underlying this that's only exposed in this particular configuration (when built as a DLL) -- I don't think it's just a matter of the DLL configuration being the problem.
|
|
|
|
|
Gosh, on the surface I can only hazard a guess. You seem to have covered things pretty thoroughly though.
Some wild-assed guesses:
1. When you statically link and run the app, the .NET framework is automatically loaded. When you dynamically link and run, perhaps a different version of the framework is started outside of your control. For example, if there's a shell extension pulled in by the Open dialog, perhaps it's loading .NET 2 and you need 3.5 or 4? This could throw an exception when your DLL finally gets loaded.
2. Does the DLL form reference a C# assembly and fail b/c you need to handle the AppDomain.AssemblyResolve event? Just having the assembly in the same dir as the C++/CLI DLL does NOT mean that C# assembly will be found automatically as I've learned the hard way.
3. Any clues in the Fusion Log views after the failed load? (use fuslogvw.exe) or in the System Event viewer logs?
I'll ponder more but it's hard to help w/o playing around w/ things as I'm sure you're aware...
John
|
|
|
|
|
Thanks, John, I appreciate the effort. I don't mind guesses at this point, wild-assed or not.
1. I'll look further into that to make sure we're binding to the correct version. We've typically deployed our app binding to .NET 2, to keep the installer footprint small. Unfortunately I can't use depends to find out exactly what's being loaded.
2. I have "resolve #using References" set to the output folder where the assembly DLL is built, and I've made the assembly a dependency of the wrapper library in the VS solution. I've set references for it in no other way.
3. No clues. I ran fuslogvw and enabled all logging; when I run the app to point of failure, nothing appears in the log so I presume that means no binding is triggered. In my test app that does work, nothing shows up in the Fusion log until I actually launch the report. The app that's failing never even gets that far (I just run it and do File:Open).
Trevor
|
|
|
|
|
How about running the app under Application Verifier. This has helped me find some pretty subtle issues with our hybrid C++, C++/CLI, C# app.
It will hang for me if I setup App Verifier and debug as a Mixed mode app. It does work if you change the project debug settings to debug as Native Only.
If it is a pointer bug as jschell mentions this could help nail it early.
John
|
|
|
|
|
Thanks for all the input, everyone. I'm currently trying out AppVerifier, something I wasn't previously aware of. It helped me figure out that there's a buried call to LoadLibrary() within a DllMain() and I'm just testing now to see if that's our issue.
|
|
|
|
|
Pointer bug.
A system exception is caused with the OS detects the app trying to do something that it shouldn't.
The execution environment impacts how a pointer bug impacts an application.
Thus in one place it might work without problem. In another it fails.
The crash can occur long after the actual place where the bug exists.
Presuming the only unmanaged code is via interop the most likely explanation is that it the API is being used incorrectly. Parameter sizing would seem to be likely possibility.
Could also be a bug in one of the libraries you are using.
|
|
|
|
|
That was it! We had a DLL unrelated to C++/CLI that was triggering a buried LoadLibrary() within its DllMain. Once removed, it's running fine. Talk about a red herring: it had nothing to do with C++/CLI, it just happened that by linking in that project, it pushed the app over the edge (but only in Debug and only in Win7). Nasty. It's a problem that's been plaguing us for months (but we were able to avoid it up until recently).
Thanks John for suggesting Application Verifier. Of course it didn't say "hey, this is wrong", but it did raise a flag in the DLL that was causing all the trouble and got me to focus on what was going on there. And that's exactly what I was looking for: not necessarily "tell me what's wrong with my code" but "how do I figure out what's wrong" and your suggestion helped nail it. And jschell, you were right about it being a bug in a different library whereas I had focused mainly on the C++/CLI project itself.
So thanks both to John Schroedl and to jschell for taking the time to respond, and to CodeProject for the great site. Much appreciated!
Trevor
|
|
|
|
|
Hi guys, I'm having a small problem, and I'd like to know what you guys think.
User.h:
void User::getJobs(ArrayList^ jobs)
{
jobs = this->jobs;
}
UserForm.h:
UserForm(User^ currentUser)
{
InitializeComponent();
this->user = gcnew User();
this->allJobs = gcnew ArrayList();
Job^ currentJob = gcnew Job();
ListViewItem^ item = gcnew ListViewItem();
this->user = *currentUser;
this->user->getJobs(this->allJobs);
for(int i = 0; i < allJobs->Count; i++)
{
currentJob = (Job^)allJobs[i];
String^ temp = "";
currentJob->getCustomerName(temp);
item->SubItems->Add(temp);
temp = "";
currentJob->getProjectName(temp);
item->SubItems->Add(temp);
Job::EN_PRIORITY^ priority = Job::EN_PRIORITY::EN_PRIORITY_0;
currentJob->getPriority(priority);
switch(*priority)
{
case Job::EN_PRIORITY::EN_PRIORITY_0:
item->SubItems->Add("NONE");
break;
case Job::EN_PRIORITY::EN_PRIORITY_1:
item->SubItems->Add("1");
break;
case Job::EN_PRIORITY::EN_PRIORITY_2:
item->SubItems->Add("2");
break;
case Job::EN_PRIORITY::EN_PRIORITY_3:
item->SubItems->Add("3");
break;
case Job::EN_PRIORITY::EN_PRIORITY_4:
item->SubItems->Add("4");
break;
case Job::EN_PRIORITY::EN_PRIORITY_5:
item->SubItems->Add("5");
break;
default:
item->SubItems->Add("NONE");
break;
}
listViewAllJobs->Items->Add(item);
}
}
I can see that when getJobs() completes job in Job.h equals the values I'm trying to retrieve, but once the function returns, this->allJobs is blank. Any ideas?
[Insert Witty Sig Here]
modified on Friday, May 13, 2011 8:54 AM
|
|
|
|
|
If you are expecting getJobs() to change the incoming 'jobs' parameter to reference a different ArrayList even after the function returns, you'll need to use a "tracking reference".
To do that use the % decoration and declare the function like this:
void User::getJobs(ArrayList^% jobs)
{
jobs = this->jobs;
}
An alternative would be to loop and copy all the items from this->jobs into jobs.
John
|
|
|
|
|
That did the trick! I'm new to managed code and c++/CLI. All of these new operators are throwing me for a loop. Darn Windows forms projects!
[Insert Witty Sig Here]
|
|
|
|
|
I am animating a ball and I need something faster then what I'm getting with the form Timer() control.
Is there anything faster that I can use to speed up the animation?
Thanks.
|
|
|
|
|
You want less than a millisecond? Our eyes cannot even see such speed. I do not know of anything that is faster than a timer in .NET... If your animation is not running to subtle, maybe you should look for smaller pixels or move the image by more than a dot instead of faster images.
No idea how to do that though. Just saying speed might not be the problem.
It's an OO world.
|
|
|
|
|
I'm testing the collisions with a brick with pixel accuracy. It's the only way I could get the collision working properly.
|
|
|
|
|
Cyclone_S wrote: It's the only way I could get the collision working properly.
Obviously there are other ways. Here are a few ideas:
1. you don't need to draw anything to detect collisions, you could do it mathematically. That is modelling rather than animation. The model would generate the exact time and location of the collisions, animation would only be used to show the required frames.
2. even when collision detection is based on actual frames, you don't need to do it in real-time, you could calculate a number of new frames ahead of time (at the expense of more memory), and only show some of them, at the right pace.
Either way, you may choose to use floating-point for extra accuracy while calculating, and turn the relevant data into integers when calculating the actual frames.
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|
|
Try System.Diagnostics.Stopwatch
David Anton
Convert between VB, C#, C++, & Java
www.tangiblesoftwaresolutions.com
|
|
|
|
|
|
Timer () only to 1 Ms fastest, write their own a Delay ().
|
|
|
|
|
I'm still new to programming in Windows, so don't kill me if the answer is obvious.
What I've attempted to do is write my own WinMain function. I've based it off of Visual's generated code with a little Programming Windows mixed in combined with my own code.
Well it doesn't work, but I can't spot why.
#include <Windows.h>
#include <strsafe.h>
ATOM RegisterMyClass(HINSTANCE, wchar_t*);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void ErrorExit(LPTSTR lpszFunction);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hpInst, LPSTR cmd, int nCmdShow)
{
HWND hwnd;
MSG msg;
wchar_t myWndClass[] = L"AWindow";
wchar_t myWndTitle[] = L"My Window";
RegisterMyClass(hInst, myWndClass);
hwnd = CreateWindowW(myWndClass, myWndTitle, WS_OVERLAPPEDWINDOW,
10, 10, 300, 300, NULL, NULL, hInst, NULL);
if ( hwnd == NULL )
ErrorExit(L"CreateWindow");
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while ( GetMessage (&msg, NULL, 0, 0 ) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
ATOM RegisterMyClass(HINSTANCE hInst, wchar_t* wndClass)
{
WNDCLASSEX w;
w.cbSize = sizeof(WNDCLASSEX);
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpfnWndProc = WndProc;
w.cbClsExtra = 0;
w.cbWndExtra = 0;
w.hInstance = hInst;
w.hIcon = LoadIcon(NULL, IDI_APPLICATION);
w.hCursor = LoadCursor(NULL, IDC_ARROW);
w.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
w.lpszMenuName = NULL;
w.lpszClassName = wndClass;
w.hIconSm = NULL;
return RegisterClassEx(&w);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
HDC hdc;
PAINTSTRUCT ps;
switch (msg)
{
case WM_CREATE:
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
DefWindowProc(hWnd, msg, wp, lp);
}
return 0;
}
void ErrorExit(LPTSTR lpszFunction)
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(dw);
}
Using Microsofts own ErrorExit code, I get the following message when CreateWindow returns NULL:
CreateWindow failed with error 0: the operation completed successfully
What confuses me is that the MSDN documentation on CreateWindow() says that if the function fails, it returns NULL and to use GetLastError to find out what it was. Well, it returns a null, but then reports that there is no error.
I'm seriously boggled by this one.
|
|
|
|
|
Ah, so close....You've got a very subtle error in your WndProc.
Change your default handling to this:
default:
return DefWindowProc(hWnd, msg, wp, lp);
Your code was dropping the return code of DefWindowProc on the floor and returning zero which is bad news.
Returning zero from WM_NCCREATE instructs CreateWindow to stop the window creation. DefWindowProc will return 1 instead of 0 and allow the creation to proceed.
John
|
|
|
|
|
I knew it had to be something incredibly simple *smacks palm to forehead*. Thanks a bunch.
|
|
|
|
|
hi!
Help me to read data from Comport RS232:
My function to sent data to RS232:
private: public: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
Random^ gen=gcnew Random;
serialPort1->Write(Convert::ToString(gen->Next(0,100)+"P"));
}
and my function to read data from RS232
public: System::Void serialPort1_DataReceived(System::Object^ sender, System::IO::Ports::SerialDataReceivedEventArgs^ e) {
String^ st = serialPort1->ReadExisting();
button1->Text=st;
}
i can buid solution.After that i conect pin 2 and pin 3 of COMPORT.Next when run program had error nowbutton1->text=st;
|
|
|
|
|
Hi,
most if not all asynchronous events are handled by threads from the ThreadPool, not by the main thread, which means you can't touch GUI Controls right away from those handlers. You need to use InvokeRequired/Invoke, as I explain in this article[^] of mine (with C# and VB.NET examples, no C++/CLI, sorry, although the principles are exactly the same).
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|