views:

646

answers:

3

Hi,

Within my windows app, i'm using a c++ DLL wrapped with a .NET DLLs (specifically - the quickfix engine). While running, once every day (not at any specific time), in one of the a constructor of one of the built-in classes throws a runtime error. Even though the error is caught and reported (to a log file, and the database), I still get the windows 'runtime error' dialog (which offers no recovery/debugging options) and after pressing the 'ok' button (the only one available) my app is terminated.

This happens when running in Debug, Release and even while running within the VS2005 debugger itself.

As a side-note, I have compiled the above-mentioned DLLs locally (since at least one of them includes auto-generated code based on an XML specification).

Anyone? (details follow)

My code:

try
{
    QuickFix.Symbol Symbol = new QuickFix.Symbol();
    report.get(Symbol);
    PairsType instrument = ToPairType(Symbol.getValue());

    if (PairsType.NONE == instrument)
        return;

    QuickFix.MDEntryDate entryDate = new MDEntryDate();
    QuickFix.MDEntryTime entryTime = new MDEntryTime();
    QuickFix.QuoteCondition quoteCondition = new QuoteCondition();
    QuickFix.MDEntryPx MDEntryPxBid = new QuickFix.MDEntryPx();
    QuickFix.MDEntryPx MDEntryPxAsk = new QuickFix.MDEntryPx();

    QuickFix.NoMDEntries noMDEntries = new QuickFix.NoMDEntries();
    report.get(noMDEntries);

    for (uint i = 1; i <= noMDEntries.getValue(); ++i)
    {
        QuickFix44.MarketDataSnapshotFullRefresh.NoMDEntries group =
                new QuickFix44.MarketDataSnapshotFullRefresh.NoMDEntries();

        report.getGroup(i, group);

        if (group.isSetQuoteCondition())
            group.get(quoteCondition);
        if (group.isSetMDEntryDate())
            group.get(entryDate);
        if (group.isSetMDEntryTime())
            group.get(entryTime);

        switch (group.getMDEntryType().getValue())
        {
            case MDEntryType.BID:
                group.get(MDEntryPxBid);
                break;
            case MDEntryType.OFFER:
                group.get(MDEntryPxAsk);
                break;
        }
    }

    // use data...
}
catch (Exception e)
{
    // log the error
}

Error details: Message: External component has thrown an exception Stack trace:

at FIX.message_order.=(message_order* , message_order* )     at std._Tree_nod<std::_Tmap_traits<int,FIX::FieldBase,FIX::message_order,std::allocator<std::pair<int const ,FIX::FieldBase> >,1> >.{ctor}(_Tree_nod<std::_Tmap_traits<int\,FIX::FieldBase\,FIX::message_order\,std::allocator<std::pair<int const \,FIX::FieldBase> >\,1> >* , message_order* _Parg, allocator<std::pair<int const \,FIX::FieldBase> >* _Al)     at std._Tree<std::_Tmap_traits<int,FIX::FieldBase,FIX::message_order,std::allocator<std::pair<int const ,FIX::FieldBase> >,1> >.{ctor}(_Tree<std::_Tmap_traits<int\,FIX::FieldBase\,FIX::message_order\,std::allocator<std::pair<int const \,FIX::FieldBase> >\,1> >* , message_order* _Parg, allocator<std::pair<int const \,FIX::FieldBase> >* _Al)     at FIX.FieldMap.{ctor}(FieldMap* , Int32* order)     at QuickFix.Group..ctor(Int32 field, Int32 delim, Int32[] message_order)     at QuickFix44.MarketDataSnapshotFullRefresh.NoMDEntries..ctor()     at PriceProviders.PriceProvider.onMarketDataRefresh(FixSession session, MarketDataSnapshotFullRefresh report)
A: 

Probably the code in the C++ dll is crashing, can you post the details of that constructor?

1800 INFORMATION
That was my assumption. I do have the code, but since to my comopany QuickFix is a solution package, I have no wish to mess around with it (nor the time, actually). What I'm looking for is a workaround that will allow me to keep using it (detect the crash and restart, maybe) until I find a more stable package
A: 

You could load the QuickFix DLL in a separate AppDomain. That would protect your app from it terminating unexpectedly.

You could test for the app domain terminating from your main program and reload it when required.

App domain

http://msdn.microsoft.com/en-us/library/system.appdomain.aspx

A bit more info on building an app using them

http://msdn.microsoft.com/en-us/library/yk22e11a(VS.71).aspx

I'm assuming you don't have access to the C++ code but. Ick.. what a nasty "plaster" fix.

Arj
As I said in previous comments, I do have the code, but since to my company QuickFix is a solution package, I have no wish to mess around with it (nor the time, actually).So, such an nasty fix is all I require until I get a more stable (probably commercial :() package...
mark as answer pretty please?
Arj
I will :-), however, it seems the .NET wrapper of QuickFix is not that good... the callbacks are not implemented as delegates, which means I cannot use another AppDomain - the callbacks are not domain-aware and always go to the default (initial) domain (the notorious "Cannot pass a GCHandle across AppDomains" issue).
Hm. You'd be looking to always call / restart QuickFix from the "primary" AppDomain. It's hard to tell how the domain is determined for unmanaged call backs, as they know nothing about them but I'm guessing they return to whatever is the default AppDomain? You might try continuing with the two AppDomain approach and see if there's a way to set the 2nd "QuickFix" AppDomain to be the default after it's created? That way the calls might find their way back there. This guy seems to know more http://lambert.geek.nz/2007/05/29/unmanaged-appdomain-callback/
Arj
A: 
Traveling Tech Guy
Yup, that's what I need. However, I've yet to find an elegant way to to that...
Log every parameter you send to a function in that DLL. Pretty soon, a pattern will emerge. E.g. you're sending a number bigger than 32,768 and it fails -> maybe the function can only deal with signed ints. You send in a struct that contains a null field -> maybe the function does not check for null values... etc. etc.
Traveling Tech Guy