Programm läuft mit MSVC6, aber nicht mit MSVS.NET2003



  • Tag zusammen,

    ich hoffe ich bin im richtigen Forum gelandet. Bei Bedarf bitte verschieben...wusste nicht ob ins IDE- oder MFC- oder ein sonstiges Forum...

    Zu meinem Problem. Ich möchte aus einem eigenen Programm heraus eine Verbindung zum Programm Origin herstellen. Der Hersteller bietet dazu vorgefertigte Klassen an (bzw. ein ganzes Projekt für MSVC6) sowie ein aus diesen Beispiel-Klassen erstelltes Binary.
    Das Problem ist nun, dass der Aufbau der Verbindung mit dem Binary problemlos funktioniert. Kompiliere ich den Code aber selbst, tritt ein Fehler auf und die Verbindung kann nicht hergestellt werden.
    Ich habe mit fähigen (so schien es mir zumindest 😃 ) Supportarbeitern lange an dem Problem gesessen und viele Fehlerquellen bis auf eine ausgeschlossen: meine IDE. Die Supportmitarbeiter nutzen MSVC6, ich nutze MSVS.NET2003.
    Ich habe die Fehlerquelle im Debugger gesucht. Hier etwas Quellcode:

    Der Fall bezieht sich hier auf nOption = ALWAYS_CREATE_NEW;
    Herzstück der Verbindung ist die Klasse COriginClient. Hier der Konstruktor:

    COriginClient::COriginClient(int nOption)
    {
    	//Initialize COM
    	CoInitialize(NULL);
    
    	//Create instance of Origin
    	HRESULT hr = 0;
    	switch( nOption )
    	{
    		case USE_EXIST_FIRST:
    			hr = m_pOApp.CreateInstance( __uuidof(ApplicationSI) );
    			break;
    
    		case ALWAYS_CREATE_NEW:
    		default:
    			hr = m_pOApp.CreateInstance( __uuidof(Application) );
    			break;
    	}
    }
    

    Nach dem Ausführen dieser Zeile

    hr = m_pOApp.CreateInstance( __uuidof(Application) );
    

    ist der Inhalt von n nicht mehr S_OK, sonder S_NOINTERFACE, was im weiteren Programmverlauf der Grund dafür ist, dass die Verbindung fehlschlägt.

    Ich habe tiefer gegraben und die Methode CreateInstance angesehen, die in comip.h definiert ist:

    HRESULT CreateInstance(const CLSID& rclsid, IUnknown* pOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) throw()
        {
            HRESULT hr;
    
            _Release();
    
            if (dwClsContext & (CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER)) {
                IUnknown* pIUnknown;
                hr = CoCreateInstance(rclsid, pOuter, dwClsContext, __uuidof(IUnknown), reinterpret_cast<void**>(&pIUnknown));
    
                if (SUCCEEDED(hr)) {
                    hr = OleRun(pIUnknown);
    
                    if (SUCCEEDED(hr)) {
    					//hier scheint die Wurzel allen Übels zu liegen ;)
                        hr = pIUnknown->QueryInterface(GetIID(), reinterpret_cast<void**>(&m_pInterface));
                    }
    
                    pIUnknown->Release();
                }
            }
            else {
                hr = CoCreateInstance(rclsid, pOuter, dwClsContext, GetIID(), reinterpret_cast<void**>(&m_pInterface));
            }
    
            if (FAILED(hr)) {
                // just in case refcount = 0 and dtor gets called
                m_pInterface = NULL;
            }
    
            return hr;
        }
    

    hr bekommt den Wert S_NOINTERFACE beim Ausführen dieser Zeile zugewiesen:

    hr = pIUnknown->QueryInterface(GetIID(), reinterpret_cast<void**>(&m_pInterface));
    

    Was sich dort abspielt, sagt mir jedoch absolut gar nichts. Und schon gar nicht sagt mir das, warum es mit MSVC6 funktioniert, und mit MSVS.NET2003 nicht. Wohlgemerkt wird auch bei mir alles fehlerfrei kompiliert, nur die Ausführung ruft dann dieses Resultat hervor...
    Also: kann mir jemand sagen, was ich im MSVS.NET2003 ändern muss, damit dieser Fehler nicht mehr auftaucht?

    Ich weiß dass das ein sehr spezielles Problem ist und habe es deswegen zuerst beim Origin Support versucht, die sollten ihr Produkt ja kennen. Tun sie auch, aber nicht ihre IDEs 😃
    Von daher hoffe ich auf eure Hilfe. Wenn ihr irgendwelche weiteren Informationen braucht, kann ich die natürlich gern posten 🙂

    Edit: inzwischen ist mir aufgegangen, dass die Fragestellung mit MFC rein gar nichts zu tun hat, also bitte verschieben? Wäre nett 🤡



  • Was macht denn GetIID()?



  • Hab gleich mal den Anfang der ganzen comip.h eingfügt:

    /***
    * comip.h - Native C++ compiler COM support - COM interface pointers header
    *
    * Copyright (c) Microsoft Corporation. All rights reserved.
    *
    ****/
    
    #if _MSC_VER > 1000
    #pragma once
    #endif
    
    #if !defined(_INC_COMIP)
    #define _INC_COMIP
    
    #include <ole2.h>
    #include <malloc.h>
    
    #include <comutil.h>
    
    #pragma warning(push)
    #pragma warning(disable: 4290)
    
    #pragma push_macro("new")
    #undef new
    
    #include <new.h>
    
    class _com_error;
    
    void __stdcall _com_issue_error(HRESULT);
    struct __declspec(uuid("00000000-0000-0000-c000-000000000046")) IUnknown;
    
    // Provide Interface to IID association
    //
    template<typename _Interface, const IID* _IID /*= &__uuidof(_Interface)*/> 
    class _com_IIID {
    public:
        typedef _Interface Interface;
    
        static _Interface* GetInterfacePtr() throw()
        {
            return NULL;
        }
    
        static _Interface& GetInterface() throw()
        {
            return *GetInterfacePtr();
        }
    
    	// und dann hierhin...
        static const IID& GetIID() throw()
        {
            return *_IID;
        }
    };
    
    template<typename _IIID> class _com_ptr_t {
    public:
        // Declare interface type so that the type may be available outside
        // the scope of this template.
        //
        typedef _IIID ThisIIID;
        typedef typename _IIID::Interface Interface;
    
        // When the compiler supports references in template parameters,
        // _CLSID will be changed to a reference.  To avoid conversion
        // difficulties this function should be used to obtain the
        // CLSID.
        //
    
    	// erst springt er hierhin...
        static const IID& GetIID() throw()
        { 
            return ThisIIID::GetIID(); 
        }
    	...
    

    beantwortet das irgendwie deine Frage? Hab leider den Bereich schon verlassen, in dem weiß, was ich tue. Es werden zwei Methoden aufgerufen, ich hab sie im Quelltext mit Kommentaren markiert.

    Ich könnt heut abend auch mal die komplette comip.h irgendwo hochladen (sowas wie Anhänge scheints hier nicht zu geben, oder bin ich blind?), wenn das jemandem hilft?



  • Wenn man sich zum Vergleich mal die comip.h vom VC6 anschaut, dann gibt es eigentlich keine Unterschiede:

    // Loads an interface for the provided CLSID.
    	// Returns an HRESULT.  Any previous interface is released.
    	//
    	HRESULT CreateInstance(const CLSID& rclsid, IUnknown* pOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) throw()
    	{
    		HRESULT hr;
    
    		_Release();
    
    		if (dwClsContext & (CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER)) {
    			IUnknown* pIUnknown;
    
    			hr = CoCreateInstance(rclsid, pOuter, dwClsContext, __uuidof(IUnknown), reinterpret_cast<void**>(&pIUnknown));
    
    			if (FAILED(hr)) {
    				return hr;
    			}
    
    			hr = OleRun(pIUnknown);
    
    			if (SUCCEEDED(hr)) {
    				hr = pIUnknown->QueryInterface(GetIID(), reinterpret_cast<void**>(&m_pInterface));
    			}
    
    			pIUnknown->Release();
    		}
    		else {
    			hr = CoCreateInstance(rclsid, pOuter, dwClsContext, GetIID(), reinterpret_cast<void**>(&m_pInterface));
    		}
    
    		return hr;
    	}
    

    Auch GetIID() sieht hier genauso aus.

    Wenn Du Zugriff auf einen VC6 hast, dann könntest Du mal versuchen, in beiden IDEs schrittweise durch die Funktionen zu laufen und zu schauen, ob es bei den Argumenten bzw. Rückgabewerten Unterschiede gibt.



  • Schau doch mal im Debugger welchen Wert reinterpret_cast<void**>(&m_pInterface) hat, wenn QueryInterface() betreten wird.


  • Mod

    Ich kann m it nicht vorstellen, dass es hier einen Unterschied gibt, außer VC6 ermittelt eine andere Interface-ID als VC2003.

    Der Fehler liegt in keinem Fall auf der C++/MFC/ATL Seite. S_NOINTERFCAE bedeutet: Da ist ein COM-Objekt, aberdas Interface, nachdem Du fragst ist nicht vorhanden.
    Gib mal die IID direkt an!



  • Also an RTTI für reinterpret_cast liegts nicht, das hab ich probiert. &m_pInterface hat den Wert 0x00000000, was Martins Aussage, dass kein Interface vorhanden ist, stützt, vermute ich mal.
    GetIID() liefert folgendes:

    GetIID	0x00402190 _com_ptr_t<_com_IIID<OrgApplication::IOApplication,&_GUID_91186b48_39f5_11d3_9367_00c04f79eafe> >::GetIID(void)	const _GUID & (void)
    

    Nützt euch das was? Wie gesagt ich versteh selbst nicht mehr was ich hier mache... 😕

    Edit: Das mit RTTI bezog sich auf Jencas Post, aber das hat er inzwischen wegeditiert, also nicht wundern...


  • Mod

    Diese Info nützt Dir nichts, außer, dass Du jetzt weißt welche IID verwendet wird oder verlangt wird. Die Frage wäre einfach ob wirklich beide Interfaces identisch sind.

    Woher bekommst Du "Application"? Durch einen #import?
    Wird wirklich die selbe DLL, TLB, IDL verwendet?



  • Martin Richter schrieb:

    Woher bekommst Du "Application"? Durch einen #import?

    Ich glaube ja, es wird zumindest eine externe Bibliothek verwendet. Aber ich habe keine Ahnung, was da drinsteht, deswegen bin ich mir nicht wirklich sicher. Gibts eigentlich einen Weg, sowas rauszufinden? Zur Sicherheit hier nochmal die ganze Klasse:

    /*------------------------------------------------------------------------------*
     * File Name: OriginClient.cpp													*
     * Creation:  LY 4/7/2004														*
     * Purpose: Implementation of utility functions to access Origin Automation		*
     *			server																*
     * Copyright (C) OriginLab Corp.												*
     * All Rights Reserved															*
     *------------------------------------------------------------------------------*/
    
    #include "StdAfx.h"
    #include ".\originclient.h"
    
    #pragma comment(lib, "comsupp.lib")
    
    COriginClient::COriginClient(int nOption)
    {
    	//Initialize COM
    	CoInitialize(NULL);
    
    	//Create instance of Origin
    	HRESULT hr = 0;
    	switch( nOption )
    	{
    		case USE_EXIST_FIRST:
    			hr = m_pOApp.CreateInstance( __uuidof(ApplicationSI) );
    			break;
    
    		case ALWAYS_CREATE_NEW:
    		default:
    			hr = m_pOApp.CreateInstance( __uuidof(Application) );
    			break;
    	}
    }
    
    COriginClient::~COriginClient(void)
    {
    	//Release the created instance of Origin
    	if( m_pOApp != NULL )
            m_pOApp.Release();		
    
    	//Uninit COM
    	CoUninitialize();
    }
    
    BOOL COriginClient::IsValid()
    {
    	return (m_pOApp != NULL);
    }
    
    BOOL COriginClient::GetWorksheet(LPCSTR lpszWks, _variant_t& val)
    {
    	BOOL bRet = FALSE;
    	if( m_pOApp == NULL )
    		return bRet;
    
    	try
    	{
    		val = m_pOApp->GetWorksheet( _bstr_t(lpszWks) );
    		bRet = TRUE;
    	}
    	catch(...)
    	{
    		TRACE("ERROR during Origin access");
    		bRet = FALSE;
    	}	
    
    	return bRet;
    }
    
    BOOL COriginClient::SetWorksheet(LPCSTR lpszWks, _variant_t val, int nRowStart)
    {
    	BOOL bRet = FALSE;
    	if( m_pOApp == NULL )
    		return bRet;
    
    	_variant_t valRowStart;
    	valRowStart.vt = VT_I4;
    	valRowStart.intVal = nRowStart;
    
    	try
    	{
    		bRet = m_pOApp->PutWorksheet( _bstr_t(lpszWks), val, valRowStart );			
    	}
    	catch(...)
    	{
    		TRACE("ERROR during Origin access");
    	}
    
    	return bRet;
    }
    

    Und das Headerfile noch dazu:

    /*------------------------------------------------------------------------------*
     * File Name: OriginClient.h													*
     * Creation:  LY 4/7/2004														*
     * Purpose: Utility functions to access Origin Automation server				*
     * Copyright (C) OriginLab Corp.												*
     * All Rights Reserved															*
     *------------------------------------------------------------------------------*/
    
    #include "comdef.h"
    #include "comutil.h"
    
    #pragma once
    
    #import ".\Origin.tlb" rename_namespace("OrgApplication")
    using namespace OrgApplication;
    
    #define IS_VALID_ORIGIN_PTR(_p)		( _p != NULL && _p->IsValid() )
    #define ORIGIN_WINTYPE_WKS		2
    
    enum {
    	ALWAYS_CREATE_NEW = 0,
    	USE_EXIST_FIRST
    };
    
    class COriginClient
    {
    public:
    	COriginClient(int nOption = USE_EXIST_FIRST);
    	~COriginClient(void);
    
    public:
    	// This demonstrates how to wrap automation methods and provide
    	// user specified calling arguments
    	BOOL GetWorksheet(LPCSTR lpszWks, _variant_t& val);
    	BOOL SetWorksheet(LPCSTR lpszWks, _variant_t val, int nRowStart = 0);
    
    	//Method to assert the reference to Origin automation server is valid
    	BOOL IsValid();
    
    	// This demonstrates how to allow this class to be used 
    	// as the IOApplicationPtr itself.
    	IOApplicationPtr operator->() const 
    	{ 
    		if( m_pOApp == NULL ) 
    		{
    			_com_issue_error(E_POINTER);
    		}
    
    		return m_pOApp; 
    	}
    
    private:
    	IOApplicationPtr m_pOApp;
    };
    

  • Mod

    Bist Du sicher, dass sich hier

    #import ".\Origin.tlb" rename_namespace("OrgApplication")
    

    Auf die selbe Datei bezogen wird?



  • Ähm ich steh grad aufm Schlauch...was meinst du mit "auf die selbe Datei"?
    Meinst du, ob für das schon kompilierte Binary und meine eigene Kompilierung die selbe Datei verwendet wurde?


  • Mod

    Origin.tlb ist die Datei aus der die Interface-Definitionen kommen!

    Woher ist die, wer hat die erzeugt. Ist es garantiert die selbe, wie im VC6 Projekt?



  • Die Origin.tlb wird vom Hersteller mitgeliefert zu den Klassen für den Zugriff. Ein Mitarbeiter hat mir einen kompletten Projektordner geschickt, u.a. mit einer bereits von ihm kompilierten Debug- und ReleaseVersion. Seine Binaries kann ich ausführen, selbst kompilieren geht auch hier nicht, wie gehabt. In diesem Fall hab ich ja definitiv eine korrekte Origin.tlb verwendet 😕



  • Also ich habe jetzt auf meinem Notebook VC++6 installiert, den Quelltext dort kompiliert. Und siehe da, er lief auf meinem PC auf Arbeit, und tat genau das, was er sollte.
    Kann sich das jemand erklären?


Anmelden zum Antworten