Вызов C dll из VB6, где dll написан с использованием Visual Studio 2013

0

Этот вопрос будет плохо поставлен, но я вращаю свои колеса в разное время, и я не уверен, как выразить это лучше.

Мне нужно написать DLL, используя C, который вызывается из VB6. Я использую Visual Studio Express 2013. Я знаю... VB6 является древним, и я думаю, что менеджеры кода теперь убеждены, что они должны его мусор. Но в то же время это нужно сделать.

Для начала я пытаюсь написать DLL с помощью одной функции, которая ничего не делает, кроме как распечатать сообщение, и это отлично работает при вызове DLL с помощью VB.NET.

Вот что у меня для TinyDll.h.

#ifdef TINYDLL_EXPORTS
#define TINYDLL_API __declspec(dllexport)
#else
#define TINYDLL_API __declspec(dllimport)
#endif

extern TINYDLL_API void __stdcall testdll();

И здесь TinyDll.cpp

#include "stdafx.h"
#include "TinyDll.h"
#include <stdexcept>

using namespace std;

void __stdcall testdll()
{
  printf("Got into the dll.\n");
}

Кстати, я пробовал это с и без __stdcall. Я также попытался использовать файл.def, чтобы отменить имя в DLL, но теперь мне не ясно, что должно работать. Примеры, которые я нашел, показывают, что это должно работать

LIBRARY TinyDll
Exports
  testdll

но это не так. Имя в dll все еще находится в искаженном виде: testdll @@YGXXZ.

Мой тестовый код довольно тривиален, и он отлично работает с VB.NET, но он не будет работать с VB6. Проблема связана с тем, что процесс VB6 не может найти dll и/или найти функции внутри него. Для записи здесь используется код VB6 для тестирования

Declare Sub testdll Lib "TinyDll.dll" Alias "?testdll@@YGXXZ" ()

Sub Main()
  testdll()
End Sub    

Во-первых, я исправлю, что нет необходимости называть regsvr32 или regasm? DLL не является COM-объектом - VB6 вызывает мой код C, а не наоборот. Когда мы пытаемся выполнить любую из этих двух вещей, либо "точка входа DllRegisterServer не найдена", либо "указанный модуль не может быть найден".

В довершение всего, среда разработки VB6 слишком старая, чтобы работать на моей машине с Windows 7, а человек, пытающийся протестировать мою DLL, находится в другом состоянии и является строго программистом VB.

Я читал все, что мог найти, по поиску в Google, поэтому я надеюсь, что кто-то узнает о веб-сайте, в котором четко излагаются факты или показывает рабочий пример.

  • 0
    возможный дубликат вызова функций DLL из VB6
  • 0
    Это похоже на искажение имени в C ++ - вы пробовали extern "C" чтобы подавить это?
Показать ещё 4 комментария
Теги:
dll
vb6

1 ответ

0

Как это часто бывает с таким вопросом (т.е. Одним из них является использование жесткой старой среды, используемой для того, чтобы делать вещи, для которых это никогда не предназначалось), теперь это работает, но неясно, почему именно.

Мы считаем, что без полного пути к dll VB6 не может его найти. Если мы объявим функцию с

Declare Function TestTinyDLL Lib "e:\full\path\down\to\TinyDll.dll" Alias "_testdll@0"

то вызов работает, но он не работает, если полный путь не указан, независимо от того, где находится dll. Мы также обнаружили, что мы можем избежать предоставления полного пути путем "инициализации" dll следующим образом (благодаря: Файл не найден при загрузке dll из vb6 для этой подсказки):

Option Explicit

' Windows API method declarations
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function CallWindowProc Lib "user32" Alias _
    "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, _
    ByVal msg As Any, ByVal wParam As Any, ByVal lParam As Any) _
    As Long
Private Declare Function FormatMessage Lib "kernel32" Alias _
    "FormatMessageA" (ByVal dwFlags As Long, lpSource As Long, _
    ByVal dwMessageId As Long, ByVal dwLanguageId As Long, _
    ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Any) _
    As Long

Declare Function BogusCall Lib "otherdll.dll" Alias "_BogusCall@0" () As Integer

Declare Function TestTinyDLL Lib "TinyDLL.dll" Alias "_testdll@0" () As Integer

Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000


Sub Main()

    InitializeDLL App.Path & "\" & "otherdll.dll", "_BogusCall@0"

    InitializeDLL App.Path & "\" & "TinyDLL.dll", "_testdll@0"

    Dim Version As String

    Version = "TinyDLLTestProgram" & vbCrLf & vbCrLf

    Version = Version & "BogusCall = " & CStr(BogusCall ()) & vbCrLf

    Version = Version & "TestTinyDLL= " & CStr(TestTinyDLL()) & vbCrLf

    Form1.txtOutput.Text = CStr(Version)

End Sub

Sub InitializeDLL(myDLL As String, myFunc As String)

    ' Locate and load the DLL. This will run the DllMain method, if present
    Dim dllHandle As Long
    dllHandle = LoadLibrary(myDLL)

    If dllHandle = 0 Then
        MsgBox "Error loading DLL" & vbCrLf & ErrorText(Err.LastDllError)
        Exit Sub
    End If

    ' Find the procedure you want to call
    Dim procAddress As Long
    procAddress = GetProcAddress(dllHandle, myFunc)

    If procAddress = 0 Then
        MsgBox "Error getting procedure address" & vbCrLf & ErrorText(Err.LastDllError)
        Exit Sub
    End If

    ' Finally, call the procedure
    CallWindowProc procAddress, 0&, "Dummy message", ByVal 0&, ByVal 0&

End Sub

' Gets the error message for a Windows error code
Private Function ErrorText(errorCode As Long) As String

    Dim errorMessage As String
    Dim result As Long

    errorMessage = Space$(256)
    result = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0&, errorCode, 0&, errorMessage, Len(errorMessage), 0&)

    If result > 0 Then
        ErrorText = Left$(errorMessage, result)
    Else
        ErrorText = "Unknown error"
    End If

End Function

Почему это работает, это тайна, но это так. Надеюсь, это поможет кому-то еще столкнуться со старым кодом VB6!

  • 0
    Это работает по-другому - используется позднее связывание, а не прямое связывание. Если вы хотите использовать прямую связь, функции должны иметь префикс __declspec (dllexport). Возможно, добавьте extern "C", если вы не хотите искажения имени.
  • 0
    Он должен работать без пути, при условии, что DLL находится где-то, что Windows может найти его. Например, system32 dir, в том же каталоге, что и EXE, или в текущем рабочем каталоге. Сложность заключается в том, что при выполнении из IDE VB6 «тот же каталог, что и EXE-файл» означает EXE-файл VB6 IDE. Иногда мы используем chdir, чтобы изменить текущий dir на app.path перед вызовом DLL, чтобы их можно было найти при выполнении из IDE.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню