Portierung von Visual c++ nach VC2005 und höher, Zugriff auf DLL-Funktion



  • Hallo,

    Bei der Portierung auf ein neueres Entwicklungssystem stellt sich mir
    folgendes Konstrukt einer DLL-Funktion mit ihrem Aufruf in den Weg.
    (Ja, es stammt noch aus dem letzten Jahrtausend!)

    In der DLL ist folgendes deklariert:
    1. Header

    __declspec (dllexport)  BOOL    _FPEXP bSerInit(CString szIni,WORD wClient,DWORD FAR PASCAL WriteSendEnd( WORD wParam, LPSTR lpData , WORD wWas));//Serielle Schnittstelle initialisieren und öffnen
    

    2. Definition

    BOOL _FPEXP CElCom::bSerInit(CString szIni,WORD wClient,DWORD FAR PASCAL WriteSendEnd( WORD wParam, LPSTR lpData, WORD wWas))
    

    3. Aufruf in der exe, die diese DLL einbindet: (Ja, es steht zwei mal hintereinander der Aufruf von WriteSendEnd(..), ohne Ergebnis-Zuweisung)

    WriteSendEnd( 0, (LPSTR)&theApp,2);
    WriteSendEnd( 0, (LPSTR)this,1);
    
    if(!m_wndCElCom -> bSerInit(szInitDllPath,theApp.m_wClientNummer,&WriteSendEnd))
    {
    ...
    

    Zum besseren Verständnis noch die "WriteSendEnd(..)":

    CMainWindow  *pMainWSE;
    CTheApp		*pAppWSE;
    
    DWORD FAR PASCAL WriteSendEnd( WORD wParam, LPSTR lpData, WORD wWas)
    {   
        SE *seEmpf;
        if(wWas) 
    	{ 
    		switch(wWas)
    		{	case 1:pMainWSE = (CMainWindow *)lpData; break;
    			case 2:pAppWSE = (CTheApp *)lpData; break;
    			case 3:pAppWSE->m_pOwnMainWnd->m_wndCStatic[0].SetWindowText(lpData); break;
    		}
    	}
    	else
    	{
    	  seEmpf=(SE*)lpData;
    	  CString *csEmpString=seEmpf->pcsReceivedString;
    	  if(csEmpString->GetLength()>=1)
    		if(csEmpString[0]=='R')
    		{
    			EnterCriticalSection(&CSec_WriteProt);
    			pMainWSE->m_bRecOK=TRUE;
    			LeaveCriticalSection(&CSec_WriteProt);
    		}
    
    	  if(wParam==10)//Antwort von der Rauchanlage
    	  {
    		if( csEmpString->CompareNoCase("OK\r")==0 || 
    			csEmpString->CompareNoCase("OK")  ==0 || 
    			csEmpString->CompareNoCase("O")   ==0    )
    		{
    			EnterCriticalSection(&CSec_WriteProt);
    			pMainWSE->m_bRecOK=TRUE;
    			LeaveCriticalSection(&CSec_WriteProt);
    		}
    	  }
    	pMainWSE->m_wndCElCom->bOnSendEnd(wParam,(LPARAM)lpData);
    	return (LRESULT) 1;
    
    	}
    	return 1;
    }
    

    Es geht vorwiegend um die Methode bSerInit(..).
    So wie es da Steht, wird es vom Visual C++ 6.0 Compiler übersetzt und auch ausgeführt.
    Nun habe ich es nach VS2005 portiert, und in der exe wird die Signatur
    von bSerInit nicht mehr erkannt (Linker Fehler).
    Ich habe natürlich versucht, diese anzupassen.
    Aber dann kommen nur noch Compiler-Fehler, die besagen, dass die Parameter nicht
    übereinstimmen.

    Was mein Vorgänger bei der Konstruktion gedacht hat, will ich eigentlich gar nicht wissen.

    Aber vielleicht kann mir jemand erklären, wie ich es in VS2005 auflösen kann
    und wie ich es dann am besten verwende. Und warum es in VS 6.0 überhaupt funktioniert hat. Ich habe noch mehr solche Konstrukte.

    Vielen Dank für Eure Mühe



  • Hast du die DLL auch dem Linker unter "Additional Dependencies" mitgegeben?

    Die DLL-Definitionen sind in Ordnung so - was stört dich denn daran?



  • Ja, ich habe diese DLL angegeben. Habe gerade nochmals nachgesehen.
    Es stand zwar zunächst noch eine alte .lib in dem Verzeichnis.
    Die hab ich gegen die neue ausgetauscht; gleicher Effekt:
    "unresolved external symbol "public: int __thiscall CElCom::bSerInit(c"..

    Ich verstehe auch den Funktionsaufruf innerhalb der Signatur nicht.
    Auch der zweimalige Aufruf von "WriteSendEnd", ohne Zuweisung an eine Var,
    ist mir schleierhaft. Wenn diese Funktion einen Wert erhält, so ist ja nur
    der aus dem letzten Aufruf interessant.



  • Och poste doch bitte mal die gesamte Fehlermeldung.



  • elmut19 schrieb:

    Die hab ich gegen die neue ausgetauscht; gleicher effekt:
    "unresolved external symbol "public: int __thiscall CElCom::bSerInit(c"..

    Warum der Linker das nicht auflösen kann ist mit den vorhandenen Infos nicht zu erklären.

    elmut19 schrieb:

    Ich verstehe auch den Funktionsaufruf innerhalb der Signatur nicht. Auch der zweimalige Aufruf von
    "WriteSendEnd", ohne Zuweisung an eine Var, ist mir schleierhaft. Wenn diese Funktion einen Wert erhält, so ist ja nur
    der aus dem letzten Aufruf interessant.

    Wie kommst Du denn darauf ?

    WriteSendEnd( 0, (LPSTR)&theApp,2); 
    WriteSendEnd( 0, (LPSTR)this,1);
    

    Da hier der Code vorliegt, ist doch offensichtlich, das die beiden Aufrufe jeweils eine andere globale
    Variable in der DLL initialisieren.

    CMainWindow  *pMainWSE;
    CTheApp     *pAppWSE;
    
    ...
    
    case 1:pMainWSE = (CMainWindow *)lpData; break;
    case 2:pAppWSE = (CTheApp *)lpData; break;
    

    Es ist wohl davon auszugehen, das bSerInit() die Funktion WriteSendEnd() mit dem Zusatz "3"
    aufruft. Das wiederum sorgt dafür, das ein Text angezeigt wird ...

    Ich würde hier das Lesen eines guten C oder C++ Buchs empfehlen ...

    PS: Der bisher gezeigte Code compiliert mit VS2010 einwandfrei - wie erwartet.



  • Hallo merano und Hustbaer,

    schon mal vielen Dank für die Antworten.
    Noch habe ich den Fehler nicht gefunden.
    Zunächst die ganze Fehlermeldung: (sorry, dass sie unvollständig war)

    error LNK2019: unresolved external symbol "public: int __thiscall CElCom::bSerInit(class ATL::CStringT<char,class StrTraitMFC_DLL<char,class ATL::ChTraitsCRT<char> > >,unsigned short,unsigned long (__stdcall*)(unsigned short,char *,unsigned short))" (?bSerInit@CElCom@@QAEHV?CStringT@DV?CStringT@DV?StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@GP6GKGPADG@Z@Z) referenced in function "public: int __thiscall CMainWindow::bDllDbReglerInit(void)" (?bDllDbReglerInit@CMainWindow@@QAEHXZ)

    Und vielen Dank auch merano.
    ich habe das Programm leider nicht geschrieben. sonst könnte ich auf Deine
    Frage "Wie kommst Du denn darauf ?" antworten. Ich stosse darin leider immer
    wieder auf solche Sachen, die zu meiner Verwirrung beitragen. Ich habe es auch
    extra deswegen mit angegeben. DIe Köpfe einiger Kollegen sind leider höchstens
    mit einem guten Psychologie Buch zu verstehen; aber da hab ich leider keines.

    Aber es ist schon mal gut zu wissen, dass es so auch im neueren Visual Studio gehen müsste. Ich werde noch ein Weilchen Trail&Error versuchen.



  • Ich hab den Fehler nun doch gefunden.
    Vielen Dank nochmal an alle, die mitgeholfen haben.

    Es hat sich herausgestellt, dass der Compiler doch auf eine ältere Version der
    Lib zugeriffen hat, und meine neue befand sich im falschen Verzeichnis (trotz wiederholtem Nachsehen).
    Obwohl sich die Signatur der betroffenen Methoden eigentlich nicht hätte geändert haben sollen, gings schief.

    Meistens hilft eine Nacht Schlaf auch sehr.

    Und nochmals danke an merano.
    Dein Hinweis mit der Initialisierung für die beiden Aufrufe von "WriteSendEnd"
    haben auch ein Stück weitergeholfen. Der Rest geht nun sicher auch über den Debugger, hoffe ich. Nur warum schreibt man dann dafür nicht eine Init-Funktion?

    Aber mit den Gehirnwindungen meines Vorgänger werde ich mich nun selbst wieder befassen.



  • elmut19 schrieb:

    Obwohl sich die Signatur der betroffenen Methoden eigentlich nicht hätte geändert haben sollen, gings schief.

    Die Signatur hat sich dadurch geändert, dass du nun neuere Libraries verwendest.
    In dem Fall wird wohl CString zugeschlagen haben.
    Wenn du genau guckst ist der Typ CString nun ausgeschreiben ATL::CStringT<char,class StrTraitMFC_DLL<char,class ATL::ChTraitsCRT<char> > > ( CString ist ja nur ein typedef ). Bei VC 6 war da noch ein ganz anderer Typ "dahinter".

    elmut19 schrieb:

    Ich verstehe auch den Funktionsaufruf innerhalb der Signatur nicht.

    Das ist kein Funktionsaufruf, sondern ein Funktionsparameter.
    Sieht bloss komisch aus, weil der Typ des Parameters ein Funktionszeiger ist.

    // BOOL _FPEXP bSerInit(CString szIni,WORD wClient,DWORD FAR PASCAL WriteSendEnd( WORD wParam, LPSTR lpData , WORD wWas));
    
    // =>
    
    // typedef für Funktionstyp
    typedef DWORD PASCAL WriteSendEndFunction(WORD, LPSTR, WORD);
    
    // Und mit dem typedef oben kann man den Prototyp dann so schreiben:
    BOOL _FPEXP bSerInit(CString szIni, WORD wClient, WriteSendEndFunction FAR* pWriteSendEnd);
    


  • Ja, auch noch vielen Dank für Deine Erklärung, Hustbaer.
    Die hat mir auch noch geholfen, den Code etwas besser zu verstehen.

    Mit den Funktionspointern muss ich mich noch etwas beschäftigen.


Anmelden zum Antworten