VC-DLL mit VB-Programm verwenden



  • Bisher habe ich mit Visual-C++ nur DLL gestrickt, die auch von VC-Programmen verwendet werden. Soweit kein Problem. Jetzt geht es darum, eine mit VC erstellte DLL mit einem Visual-Basic Programm zu verwenden. Und das bringe ich nicht auf die Reihe.

    In der DLL sind alle exportierten Funktionen deklariert mit __declspec(dllexport)
    Im Basic werden die DLL-Funktionen deklariert mit
    Public Declare Function funktionsname Lib "filename.dll" (ByVal parametername As vartype) As vartype
    oder so ähnlich.
    Mit dem Erfolg, dass VB zwar die DLL lädt und offensichtlich auch die Funktion findet, aber nicht deren Adresse:
    Runtime error '453': Can't find DLL entry point funktionsname@@YAHHQZ in filename.dll

    Den "dekorierten" Funktionsnamen anzugeben mit
    Public Declare Function funktionsname Lib "filename.dll" Alias "funktionsname@@YAHH@Z" (ByVal parameter As vartype) As vartype
    nützt aber auch nichts.

    Irgendwas mache ich falsch - aber was? Muss ausser __declspec(dllexport) noch was vorgegeben werden, speziell für VB oder fehlt was bei Declare Function? Kann mir jemand auf die Sprünge helfen, wie ich ein Visual-Basic Programm dazu überreden kann, Funktionen aus einer mit Visual-C erstellten DLL zu verwenden?



  • __stdcall statt __declspec(dllexport)

    vb braucht "undekorierte" fuktionsnamen. wenn du die im dependency walker siehst hast du es geschafft.



  • http://www.geocities.com/az_sotftware/Dll.htm
    Hier wird auch beschrieben wie man DLL Dateien für Java, VB, etc. erstellt.



  • Jepp, das isses! Danke für den Link. Da hat sich tatsächlich mal einer die Mühe gemacht, klare Aussagen aufzuschreiben. Im MSDN findet man dagegen den Wald vor lauter Bäumen nicht, schon garnicht sowas. Da muss ein normaldenkender C-Programmierer erstmal drauf kommen, dass bei den dekorierten Funktionsnamen das führende Fragezeichen mit angegeben werden muss, also Alias "?funktionsname@@YAHH@Z". Wirklich sehr dekorativ...

    Jedenfalls kann das VB-Programm damit die Funktionen aus der VC-DLL tatsächlich aufrufen. Und prompt gibt's ein anderes Problem: __stdcall ist nötig, damit die Reihenfolge der Parameter und die Stack-Behandlung übereinstimmt. Hat allerdings auch den Nachteil, dass dann zwar nach wie vor Strings vom VB-Programm als Parameter in die Funktionen reingesteckt werden können, aber umgekehrt kein BSTR als Returnwert zurückgegeben werden kann, weil unter __stdcall kein BSTR mehr bekannt ist. MSDN mein dazu nur lapidar:

    A DLL function cannot return strings unless it is written specifically for use with Automation data types. If it is, the DLL probably supplies a type library that describes the procedures. Consult the documentation for that DLL.

    Ja, ja, RTFM. Hey, the documentation for that DLL, die ich da consulten soll, muss ich selber noch schreiben. CString::AllocSysString() als Returnwert kommt zwar an, wird aber vom VB-Programm nicht als Unicode bzw. WideChar-String erkannt bzw. enthält in jedem 2. Zeichen einen Buchstaben, dazwischen Hyroglyphen. Quick&dirty-Versuch mit einem LPSTR auf ein static char Array innerhalb der DLL erzeugte einen Total-Abschuss von VB. Hatte ich schon erwähnt, dass ich Visual-Basic hasse...?

    Hat jemand noch eine geniale Idee, wie man aus einer (VC-)DLL-Funktion einen String oder notfalls ein fixes char Array an ein VB-Programm zurückgeben kann, ohne gleich ein komplettes OLE/COM-Interface zu implementieren damit für VB eine TLB zu Verfügung steht?



  • Was spricht dagegen den String "By Reference" als Parameter "zurückzugeben"?

    (C) ... char* strIrgendwas ...
    (VB) ... Byval strIrgendwas as String ...
    In VB bei string paradoxerweise "Byval", ist aber effektiv By Reference.



  • Tja, gerade das geht eben nicht, weil die Adresse, die in der C-DLL unten ankommt, eine andere ist als vom VB-Programm oben reingesteckt wurde. Irgendwo dazwischen wird nochmal umkopiert. Und umgekehrt geht's auch nicht, denn wie bitteschön deklariert man im #$*§+@%&-Visual Basic eine DLL-Funktion, die einen String ByVal zurückgibt 😕

    Bisher ist die einzige Möglichkeit, trotz __stdcall überhaupt einen String als Returnwert zurückzugeben, eben CString::AllocSysString(). Weil aber dieser Returnwert in Cpp als LPSTR deklariert werden musste statt dem wegen __stdcall nicht mehr bekanntem BSTR, kommt oben ein Unicode-String an, der nicht als solcher erkannt wird und folglich aus immer abwechselnd einem Buchstaben und einem Null-Byte besteht. Und weil man im #*§+@%&-Visual Basic nicht mal casten oder Bits schieben kann, wird der eben mühsam mit Mid() usw. zerpflückt und wieder auf die Reihe gebracht. Hatte ich schon erwähnt, dass ich #$*§+@%&-Visual Basic hasse...? 😡



  • dann übergib halt ein zeiger wenn du das nicht raffst.
    einfach "byval zeiger as long".
    dein zeiger bekommst du in VB mit StrPtr(deinvbstring)
    must den vb string nur vorher auf die richtige größe allokieren. z.b. mit dein vbstring = string(255,chr(0))

    oder nimm CopyMemory. also möglichkeiten gibts viele.

    btw. so macht es z.B. die winapi:

    C : 
    DWORD WINAPI GetPrivateProfileString(
      LPCTSTR lpAppName,
      LPCTSTR lpKeyName,
      LPCTSTR lpDefault,
      LPTSTR lpReturnedString,
      DWORD nSize,
      LPCTSTR lpFileName
    );
    
    VB :
    Declare Function GetPrivateProfileString Lib "kernel32.dll" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
    

    tut problemlos.
    Also erzähl nix von wegen es wurde nicht funktionieren 🙄



  • Also erzähl nix von wegen es wurde nicht funktionieren 🙄

    Doch, mach' ich - kann ich mir leider nicht verkneifen. 😞

    Schön wär's ja, wenn das so funktionieren würde, aber das tut nicht. Hab' ich alles schon zur Genüge durchgespielt. Z.B. in Anlehnung an
    Public Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
    eine Funktion, die einen String/Buffer und dessen Länge als Parameter bekommt, diesen String überschreibt und die tatsächlich hineingeschriebene Länge als Returnwert zurückgibt. Bei GetWindowsDirectory() funktioniert das auch - aber nicht mit meiner VC-DLL-Funktion. 😡

    Ich weiss nicht, ob ich blöd bin, oder der VC-Linker oder der #$*§+@%&-Visual Basic Compiler. Ich weiss auch nicht, wie GetWindowsDirectory das macht, aber wenn ich in VB ByVal lpBuffer As String reinstecke, kommt der zwar als LPSTR oder auch LPTSTR mit aktuellem Inhalt in der VC-DLL an - wenn ich aber in der DLL-Funktion in diese String-Adresse per strcpy() was reinschreibe, steht das auch nur innerhalb der DLL-Funktion tatsächlich drin - im VB-Programm ändert das an dem reingesteckten String rein garnichts, der hat nach dem Aufruf der DLL-Funktion denselben Inhalt wie vorher, lediglich die Länge des strcpyrten Strings wird ordnungsgemäß zurückgegeben. Ganz offensichtlich ist die String-Adresse, die in der DLL ankommt, nicht die vom VB-Programm hineingesteckte. Da wird der String-Inhalt zwischendurch umkopiert, aber eben nur in eine Richtung. Kann es sein, dass der feine Unterschied zwischen WINAPI und __declspec(dllexport) da eine Rolle spielt und für Selbstüberlistung sorgt? 😕

    Wenn ich in VB bei der Funktionsdeklaration den Parameter als ByRef lpBuffer As String oder einfach lpBuffer As String angebe und dann einen ganz normal mit Dim myString as String und myString = String(ausreichendviel,egalwasfuernchar) angelegten String reinstecken will, schlägt mir der #$*§+@%&-Visual Basic Compiler einen "Type mismatch" um die Ohren.

    Wenn ich dagegen StrPtr(myString) als ByRef lpBuffer As String reinstecke, gibt's zwar im #$§+@%&-Visual Basic keinen Type Mismatch mehr, aber dafür kommt in der VC-DLL auch kein String mehr an - da kann ich dereferenzen und casten soviel ich will, in (char)lpBuffer oder ((char*)lpBuffer) oder (char*)((void*)lpBuffer)steht irgendwas an Speichermüll, was nichtmal wie eine gültige Adresse aussieht - der String-Inhalt ist jedenfalls nicht wiederzufinden.

    Bei VC-DLL an VC-Programm wäre das alles kein Thema. Hatte ich schon erwähnt, dass ich dieses #$*§+@%&-Visual-Basic hasse...?


Anmelden zum Antworten