Delegate Funktion wird zu spät aufgerufen
-
Hallo zusammen,
ich nutze in meinem C++/CLI Klassenbibliotheks-Projekt (keine Windows-Forms) ein SDK, dass mir die Ansteuerung einer USB Kamera gewährleisten soll.
Das SDK stellt mehrere Funktionen bereit, mit dessen Hilfe ich Kameraspezifische Parameter (Kontrast, Verschlusszeit etc.) festlegen kann. Das Schießen eines Bildes wird über eine Callback-Funktion realisiert.
typedef void (* FrameDataCallBack)( TProcessedDataProperty* Attributes, unsigned char *BytePtr ); ... SDK_API BUFUSB_StartFrameGrab( int TotalFrames ); SDK_API BUFUSB_InstallFrameHooker( int FrameType, FrameDataCallBack FrameHooker );
Man muss zuvor einen "FrameHooker" festlegen, der dann aufgerufen wird, wenn die Kamera das Bild im internen Puffer erstellt hat. Das Auslösen des Bildes wird mit der Funktion "StartFrameGrab()" gestartet.
In meinem C++/Cli Projekt habe ich das Festlegen des FrameHookers über ein Delegaten realisiert. Mein Code sieht folgendermaßen aus...
Header-Datei:
[UnmanagedFunctionPointer(CallingConvention::Cdecl)] public delegate void FrameCallbackDelegate( TProcessedDataProperty% Attributes, unsigned char *Frameptr ); public ref class cCam : public IDisposable { public: FrameCallbackDelegate^ frameDelegate; void GrabbingFrameCallback(TProcessedDataProperty% Attributes, unsigned char *Frameptr);
Cpp-Datei:
//verschiedene Kameraparameter festlegen ... frameDelegate = gcnew FrameCallbackDelegate(this, &cCam::GrabbingFrameCallback); GCHandle delegateHandle_ = GCHandle::Alloc(frameDelegate); System::IntPtr ip = Marshal::GetFunctionPointerForDelegate( frameDelegate ); FrameDataCallBack cbFunc = static_cast<FrameDataCallBack>( ip.ToPointer() ); if(BUFUSB_InstallFrameHooker(1, cbFunc) < 0 ) {return ERROR;} if(BUFUSB_StartFrameGrab(1) < 0 ) //shoot only one picture {return ERROR;} ... void cCam::GrabbingFrameCallback(TProcessedDataProperty% Attributes, unsigned char *Frameptr) { try { array<unsigned char>^ FrameBuffer = gcnew array<unsigned char>( 3 * ( Attributes.Row * Attributes.Column ) ); Bitmap^ bmp = gcnew Bitmap(Attributes.Column, Attributes.Row, PixelFormat::Format24bppRgb); BitmapData^ bmpData = bmp->LockBits(System::Drawing::Rectangle(0,0,bmp->Width,bmp->Height), ImageLockMode::WriteOnly, PixelFormat::Format24bppRgb); Marshal::Copy( IntPtr(Frameptr), // source FrameBuffer, 0, FrameBuffer->Length); // destination Marshal::Copy(FrameBuffer, 0, bmpData->Scan0, FrameBuffer->Length); bmp->UnlockBits(bmpData); bmp->Save(m_sCompleteCapturePath); //Save picture to file BUFUSB_StopCameraEngine(); delete bmp; } catch(Exception^ ex) { BUFUSB_StopCameraEngine(); ex->Message; } }
das Projekt lässt sich auch Übersetzen und starten. Bei der Ausführung des Programms habe ich nun ein Timingproblem. Sobald die Stelle erreicht wird, an der die SDK-Funktion "StartFrameGrab(1)" aufgerufen wird, springt das Programm nicht gleich in die dafür vorgesehene Delegate-Funktion "GrabbingFrameCallback()". Normalerweise sollte das Programm gleich in diese Funktion reinspringen, damit das geschossene Bild gleich auf die Festplatte gespeichert wird, da im nächsten Programmschritt das Bild ausgewertet werden soll. Da aber das Timing nicht stimmt, springt das Programm nicht in die Grabbing-Funktion und erzeugt nicht das Bild. Daher kann auch der nächste Verarbeitungsschritt nicht ausgeführt werden, da das Bild dazu fehlt und es kommt zum Abbruch des programms...
Ich habe nun in der Doku zum SDK gelesen und entdeckt, dass es was mit der Nachrichtenschleife von Windows zu tun haben muss. Die Kamera-Engine stellt anscheinend nach dem Generieren des Bilds das Event "WM_TIMER" in die Schlange rein, die dann verarbeitet werden kann. Ich hab nun danach gesucht, wie ich dem Programm sagen kann... verarbeite bitte erst das Event, bevor du etwas anderes machst. In der Doku wird auch auf die Funktionen "GetMessage(), TranslateMessage() und DispatchMessage()" verwiesen. Leider habe ich im .Net-framework keine Äquivalenten Funktionen gefunden.
Nun zu meiner Frage.. wisst ihr, ob es äquivalente Funktionen im .Net-Framework gibt? wenn ja, wo finde ich diese? Wichtig ist, dass ich keine Windows-Forms Anwendung habe und somit auf das Application-Objekt (DoEvents()) nicht zugreifen kann. Habt ihr hier eine andere Lösung? wie kann ich das Programm dazu bringen, gleich in die Delegatefunktion zu springen?
Vielen Dank für eure Hilfe!!
-
Wenn das SDK eine MessageQueue verlangt, dann musst Du nun mal eine zur Verfügung stellen. Ob Du das native machst oder mit .NET ist dann Dir überlassen... Du musst aber eine MessagePump haben... die Lösung hast Du ja schon selbst geposted.
Ansonsten frag bei dem SDK Hersteller nach, ob es auch eine Variante ohne MessagePump gibt...