这个问题将会很糟糕,但我正在大力推动我的车轮,而且我不确定如何更好地表达它。
我需要编写一个使用C的DLL,它将从VB6中调用。我正在使用Visual Studio Express 2013.我知道...... VB6很古老,我认为代码的管理者现在确信他们应该把它搞砸了。但与此同时,这需要做到。
首先,我试图编写一个带有单个函数的DLL,除了打印消息之外什么都不做,并且在使用VB.NET调用DLL时工作正常。
这是我对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程序员。
我已经通过谷歌搜索阅读了所有可以找到的内容,所以我希望有人知道一个明确列出事实或展示工作实例的网站。
答案 0 :(得分:0)
就像这种问题经常出现的情况一样(也就是说,一个涉及一个硬壳旧环境被用来做它从来没有意义的东西),它现在有效,但目前还不清楚为什么。
我们认为没有完整的dll路径,VB6找不到它。如果我们用
声明函数Declare Function TestTinyDLL Lib "e:\full\path\down\to\TinyDll.dll" Alias "_testdll@0"
然后调用工作,但如果没有给出完整路径,无论dll在哪里,它都不起作用。我们还发现,我们可以通过如下“初始化”dll来避免提供完整路径(感谢:File not found when loading dll from 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代码!