简体   繁体   中英

Simple C++ .Net console app crashing in 64 bit Win7

My company uses a 3rd-party DLL to interface to some hardware (I've renamed it hwLib here). It was written long ago in VB6, I think. The DLL comes with an installer to register itself, etc.

We have a C# app that uses it and which runs just fine on XP and Win7, 32 or 64 bit. But I wrote a simple C++ console app which runs fine on XP/32 bit but crashes on Win7/64 bit.The console app looks like this,

#include "stdafx.h"
using namespace System;

int main(array<System::String ^> ^args)
{
    using namespace hwLib;
    ChwLib^ myLib = gcnew ChwLib();
    String^ str = myLib->GetDllVersion();
    Console::WriteLine(L"Hello hwLib");
    Console::WriteLine(str);
    Console::ReadLine();  //to keep window open til you hit the "any" key
    return 0;
}

Unhandled Exception: System.InvalidCastException: Unable to cast COM object of type 'hwLib.ChwLibClass' to interface t ype 'hwLib._ChwLib'.

This operation failed because the QueryInterface call on the COM component for the interface with IID '{E0560D1E-9A54-4EBF-83E8-D7BD2C936512}' failed due to the following error:

No such interface supported (Exception from HRE SULT: 0x80004002 (E_NOINTERFACE)). at System.StubHelpers.StubHelpers.GetCOMIPFromRCW(Object objSrc, IntPtr pCPCMD, Boolean& pfNeedsRelease) at hwLib.ChwLibClass.GetDllVersion() at main(String[] args) at mainCRTStartupStrArray(String[] arguments)

The C# program, which is a much bigger and more complex program, else I would post it here, runs without problems on the same system.

COM is before my time - I took a course in it maybe 10 or 15 years ago but I don't remember it - Any suggestion on how to start debugging this? Thanks!!

COM provides thread-safety guarantees for a COM component that declares itself to not support threading. Any component written in VB6 certainly does this. Directed by an entry in the registry named ThreadingModel.

Your test program does not provide a safe home for such a component, your console mode app creates a Multi-Threaded Apartment, MTA for short. Which promises to not provide thread safety. COM then creates its own STA thread to run the code for the component. Every call to the component will be marshaled from the main thread to that helper thread.

But it then runs into a wall in your case, your component doesn't have the required proxy/stub registered. Extra code that COM needs to figure out how to copy the method's arguments. Easy in .NET thanks to Reflection, not in COM. The proxy/stub is selected by entries in the HKCR\\Interface registry key, a VB6 component always uses the standard marshaller that works with the type library. The E_NOINTERFACE error code is for the IMarshal interface, COM's last gasp to find a way, not implemented by VB6.

Short from getting the registration right, the band-aid is to let your console mode app create an STA thread instead of an MTA thread. That's very easy to do, it just takes an attribute:

[STAThread]
int main(array<System::String ^> ^args)
// etc..

COM now no longer creates that helper thread and calls don't have to marshaled. This isn't actually enough, an STA thread must also pump a message loop. Application::Run() as is probably used in your larger C# program. The message loop provides the way to marshal calls, very similar to Control.BeginInvoke() and Dispatcher.BeginInvoke(). You might get away with it since you don't actually make calls on the component from another thread. But many COM components rely on the message loop to do their own stuff. You'll know you have a problem when you see deadlock or the component doesn't raise an event. The VB6 code could use a Timer for example, it won't tick without that message loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM