PDA

View Full Version : C++ with /clr



Julian
April 20, 2007, 00:38:47
I would like to build a C++ project in Visual Studio 2005 with the .NET common language runtime (i.e. /clr switch on) so that I can mix C++ calls to the Imaging Control with .NET code. I tried building a project and then added the call to DShowLib::InitLibrary(key) to initialize your library but this call throws an exception. The same call runs fine in one of the sample C++ projects which does not use the CLR. Is that the reason for the difference? Is there a way to make this work with the CLR?

Julian

More details:

Error message:

An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in MyApp.exe

Additional information: External component has thrown an exception.

Here's the callstack when the error is thrown:

kernel32.dll!7c812a5b()
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
kernel32.dll!7c812a5b()
msvcr71d.dll!_CxxThrowException(void * pExceptionObject=0x0012db58, const _s__ThrowInfo * pThrowInfo=0x10188a80) + 0x39 bytes C++
TIS_DShowLib07_vc71d.dll!100e546e()
TIS_DShowLib07_vc71d.dll!100e55eb()
TIS_DShowLib07_vc71d.dll!100e52a2()
TIS_DShowLib07_vc71d.dll!1008158f()
msvcr71d.dll!_CallSettingFrame(unsigned long funclet=1241096, unsigned long pRN=256, unsigned long dwInCode=57244) + 0x27 bytes Asm
msvcr71d.dll!_CallCatchBlock2(EHRegistrationNode * pRN=0x0012f008, const _s_FuncInfo * pFuncInfo=0x1018350c, void * handlerAddress=0x100814ba, int CatchDepth=0, unsigned long NLGCode=256) + 0x54 bytes C++
msvcr71d.dll!CallCatchBlock(EHExceptionRecord * pExcept=0x0012e1f0, EHRegistrationNode * pRN=0x0012f008, _CONTEXT * pContext=0x0012e210, const _s_FuncInfo * pFuncInfo=0x1018350c, void * handlerAddress=0x100814ba, int CatchDepth=0, unsigned long NLGCode=256) + 0xab bytes C++
msvcr71d.dll!CatchIt(EHExceptionRecord * pExcept=0x0012e1f0, EHRegistrationNode * pRN=0x0012f008, _CONTEXT * pContext=0x0012e210, void * pDC=0x0012e1c4, const _s_FuncInfo * pFuncInfo=0x1018350c, const _s_HandlerType * pCatch=0x101834e8, const _s_CatchableType * pConv=0x10188a2c, const _s_TryBlockMapEntry * pEntry=0x101834f8, int CatchDepth=0, EHRegistrationNode * pMarkerRN=0x00000000, unsigned char IsRethrow=0) + 0x9a bytes C++
msvcr71d.dll!FindHandler(EHExceptionRecord * pExcept=0x0012e1f0, EHRegistrationNode * pRN=0x0012f008, _CONTEXT * pContext=0x0012e210, void * pDC=0x0012e1c4, const _s_FuncInfo * pFuncInfo=0x1018350c, unsigned char recursive=0, int CatchDepth=0, EHRegistrationNode * pMarkerRN=0x00000000) + 0x23b bytes C++
msvcr71d.dll!__InternalCxxFrameHandler(EHException Record * pExcept=0x0012e1f0, EHRegistrationNode * pRN=0x0012f008, _CONTEXT * pContext=0x0012e210, void * pDC=0x0012e1c4, const _s_FuncInfo * pFuncInfo=0x1018350c, int CatchDepth=0, EHRegistrationNode * pMarkerRN=0x00000000, unsigned char recursive=0) + 0xe4 bytes C++
msvcr71d.dll!__CxxFrameHandler(EHExceptionRecord * pExcept=0x0012e1f0, EHRegistrationNode * pRN=0x0012f008, void * pContext=0x0012e210, void * pDC=0x0012e1c4) + 0x2c bytes C++
ntdll.dll!7c9037bf()
ntdll.dll!7c90378b()
ntdll.dll!7c937860()
ntdll.dll!7c949b34()
ntdll.dll!7c926a44()
ntdll.dll!7c926abe()
ntdll.dll!7c90eafa()
kernel32.dll!7c812a5b()
kernel32.dll!7c812a5b()
ntdll.dll!7c919b3f()
ntdll.dll!7c919aeb()
ntdll.dll!7c919b3f()
ntdll.dll!7c919aeb()
ntdll.dll!7c919d27()
kernel32.dll!7c812a5b()
> msvcr71d.dll!_CxxThrowException(void * pExceptionObject=0x0012e598, const _s__ThrowInfo * pThrowInfo=0x10188a80) + 0x39 bytes C++
TIS_DShowLib07_vc71d.dll!100e546e()
TIS_DShowLib07_vc71d.dll!100e5012()
TIS_DShowLib07_vc71d.dll!100e1665()
TIS_DShowLib07_vc71d.dll!1008146a()
TIS_DShowLib07_vc71d.dll!100a4f94()
TIS_UDSHL07_vc8d.dll!006e60f4()
TIS_UDSHL07_vc8d.dll!006e5f83()
TIS_UDSHL07_vc8d.dll!006e570d()
[External Code]
MyApp.exe!MyApp::Controller::Controller() Line 32 + 0xc bytes C++
MyApp.exe!main(array<System::String^> ^ args = {Length=0}) Line 16 + 0x13 bytes C++
ntdll.dll!7c926abe()
ntdll.dll!7c9268ad()
ntdll.dll!7c91056d()
kernel32.dll!7c80a027()
ntdll.dll!7c91056d()
TIS_UDSHL07_vc8d.dll!0065002e()
ntdll.dll!7c926abe()
ntdll.dll!7c9268ad()
ntdll.dll!7c91056d()
kernel32.dll!7c80261a()
kernel32.dll!7c8025f0()
mscoree.dll!7900837f()
TIS_UDSHL07_vc8d.dll!00730020()
TIS_UDSHL07_vc8d.dll!00750073()
TIS_UDSHL07_vc8d.dll!00730020()
TIS_UDSHL07_vc8d.dll!00750061()
ntdll.dll!7c9106eb()
ntdll.dll!7c9106eb()
mscoree.dll!79011b5f()
kernel32.dll!7c816fd7()

Stefan Geissler
April 20, 2007, 11:37:37
Hi Julian,

I must surrender, this is completely new to me. But I know Initlibrary will crash, if the ICFiltercontainer.dll is not in the working directory of your application. May this is the problem?

Julian
April 21, 2007, 21:31:59
Thanks Stefan adding that dll solved the problem. It might be nice if your component threw a more friendly error message when that dll was missing.

But I have another problem which probably has a simple answer but I haven't been able to find here. I am trying to create a simple C++.NET Windows application that creates a window and sets the camera running in video grabber mode i.e. I am calling setSnapMode(false). I want the listener frameReady event to fire every time a new frame arrives.

I put the code below (which is modified version of your Callback_vc8 C++ sample though that is a console app and uses snap mode) inside my window constructor and as long as I have that sleep statement at the end, events will fire. However, if the sleep statement terminates or I don't have the sleep statement at all then no events fire. It's as if the framegrabber only functions while the constructor is doing something. How can I keep the framegrabber alive without using the sleep statement there? Do I need to create a new thread that sleeps while the grabber is alive? I thought your grabber.startLive(false) call created its own thread?

Julian

public ref class Controller : public System::Windows::Forms::Form
{
public:
Controller(void)
{
InitializeComponent();

if( !DShowLib::InitLibrary( mykey ) )
{
fprintf( stderr, "The library could not be initialized ");
fprintf( stderr, "(invalid license key?).\n");
exit( 1 );
}

Grabber grabber;

if( !setupDeviceFromFile( grabber ) )
{
return;
}

// Create the GrabberListener object.
// CListener is derived from GrabberListener.
CListener *pListener = new CListener();

// Assign the number of buffers to the cListener object.
pListener->setBufferSize( NUM_BUFFERS );

// Enable the overlay bitmap to display the frame counter in the live video.
grabber.getOverlay()->setEnable( true );

// Register the pListener object for the frame ready and the overlay callback event.
grabber.addListener(pListener, DShowLib::GrabberListener::eOVERLAYCALLBACK);
grabber.addListener(pListener, DShowLib::GrabberListener::eFRAMEREADY );

// Create a FrameTypeInfoArray data structure describing the allowed color formats.
FrameTypeInfoArray acceptedTypes = FrameTypeInfoArray::createRGBArray();

// Create the frame handler sink
tFrameHandlerSinkPtr pSink = DShowLib::FrameHandlerSink::create( DShowLib::eRGB24, NUM_BUFFERS );

// disable snap mode
pSink->setSnapMode( false );

// Apply the sink to the grabber.
grabber.setSinkType( pSink);

// Start the grabber.
grabber.startLive(false);
::Sleep(100000);

}

...
};

}

Julian
April 21, 2007, 21:48:51
I guess I can answer my own question. I just tried putting the startLive call in a button click handler rather than the constructor and there it works fine without the need for any sleep statement. I guess the constructor is not such a good place for this call anyway.

Julian

Stefan Geissler
April 23, 2007, 08:48:45
Julian,

I apologize for the DLL not found error. There should be a better error message.

To your problem: The grabber object is declared in your constructor. This means it will be deleted, when the constructor ends. Thus no frameReady will be called any more. To solve this problem, make the grabber a member of your class:


public ref class Controller : public System::Windows::Forms::Form
{
private:
Grabber grabber; // The grabber now exists as long as the class "Controller" exists.
CListener *pListener; // Same with the Listener.
tFrameHandlerSinkPtr pSink; // And with the sink.

public:
Controller(void)
{
InitializeComponent();

if( !DShowLib::InitLibrary( mykey ) )
{
fprintf( stderr, "The library could not be initialized ");
fprintf( stderr, "(invalid license key?).\n");
exit( 1 );
}


if( !setupDeviceFromFile( grabber ) )
{
return;
}

// Create the GrabberListener object.
// CListener is derived from GrabberListener.
pListener = new CListener();

// Assign the number of buffers to the cListener object.
pListener->setBufferSize( NUM_BUFFERS );

// Enable the overlay bitmap to display the frame counter in the live video.
grabber.getOverlay()->setEnable( true );

// Register the pListener object for the frame ready and the overlay callback event.
grabber.addListener(pListener, DShowLib::GrabberListener::eOVERLAYCALLBACK);
grabber.addListener(pListener, DShowLib::GrabberListener::eFRAMEREADY );

// Create a FrameTypeInfoArray data structure describing the allowed color formats.
FrameTypeInfoArray acceptedTypes = FrameTypeInfoArray::createRGBArray();

// Create the frame handler sink
pSink = DShowLib::FrameHandlerSink::create( DShowLib::eRGB24, NUM_BUFFERS );

// disable snap mode
pSink->setSnapMode( false );

// Apply the sink to the grabber.
grabber.setSinkType( pSink);

// Start the grabber.
grabber.startLive(false);


...
};

}


The "Sleep" is not longer needed in your "Controller" class.