【问题标题】:Make a VB-dll and load it in C++ application制作一个 VB-dll 并将其加载到 C++ 应用程序中
【发布时间】:2012-06-12 13:10:28
【问题描述】:

我有一个问题困扰了整整一周,但我无法自己解决。我一直在谷歌搜索,并在各种论坛中搜索......我发现了很多“这可能有效”,尝试过,但没有,没有成功。如果有人有任何线索,请,请帮助我!

我从外部来源获得了许多用 VB 编写的类和函数,我需要能够在 C++ 应用程序中使用这些类和函数。我的第一个想法是:没问题,我将 VB 代码转换为 dll,然后从我的 C++ 程序中加载它。这虽然比我想象的要难。我的 C++ 程序不是用 Visual Studio 编写的,但为了简单起见,我开始尝试从 Visual Studio C++ 应用程序加载我的 VB dll(用 Visual Studio 2010 编写)。到目前为止,这是我的代码:

VB 代码:DllModule:类库项目

DllModule.vb

Namespace DllModule
  Public Module DllModule

    Public Const DLL_PROCESS_DETACH = 0
    Public Const DLL_PROCESS_ATTACH = 1
    Public Const DLL_THREAD_ATTACH = 2
    Public Const DLL_THREAD_DETACH = 3

    Public Function DllMain(ByVal hInst As Long, ByVal fdwReason As Long,
      ByVal lpvReserved As Long) As Boolean
        Select Case fdwReason
            Case DLL_PROCESS_DETACH
                ' No per-process cleanup needed
            Case DLL_PROCESS_ATTACH
                DllMain = True
            Case DLL_THREAD_ATTACH
                ' No per-thread initialization needed
            Case DLL_THREAD_DETACH
                ' No per-thread cleanup needed
        End Select

        Return True
    End Function

    'Simple function
    Public Function Add(ByVal first As Integer, ByVal sec As Integer) As Integer
        Dim abc As Integer
        abc = first + sec
        Return abc
    End Function
  End Module
End Namespace

DllModule.def

NAME DllModule
LIBRARY DllModule
DESCRIPTION "My dll"
EXPORTS DllMain @1
        Add @2

C++ 代码:TryVbDllLoad:控制台应用程序

TryVbDllLoad.cpp

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <strsafe.h>

extern "C" {
 __declspec(dllimport) int __stdcall Add(int, int);
}

typedef int (__stdcall *ptf_test_func_1_type)(int, int);

int __cdecl _tmain(int argc, _TCHAR* argv[])
{
    HINSTANCE hdll = NULL;

    hdll = LoadLibrary("DllModule.dll");        // load the dll
    if(hdll) {
        ptf_test_func_1_type p_func1=(ptf_test_func_1_type)GetProcAddress(hdll,"Add");

        if(p_func1) {
           int ret_val = (*p_func1)(1, 2);
        } else {
        DWORD dw = GetLastError();
        }

        FreeLibrary(hdll);              // free the dll
    } else {
        DWORD dw = GetLastError();
    }

    return 0;
}

我可以加载 dll,但 GetProcAddess 返回 NULL,错误代码为 127(找不到指定的过程)。

我尝试从 VB 应用程序加载 dll。这有效(即使没有 .def 文件)。但我猜没有创建 C++ 应用程序可以使用的正确入口点(当我在 Dependency Walker 中打开 dll 时,我看不到入口点或函数)。我已经尝试在有和没有“注册 COM 互操作”的情况下编译 VB 代码。

1) 我做错了什么?

2) 如果没有任何好的方法可以正确解决这个问题,我可以做些什么来代替创建 dll?有没有其他方法可以在我的 C++ 应用程序中使用 VB 类和函数?

亲切的问候

萨拉



感谢您的回答马雷!

我的 dll 中一定有某种错误,因为当我尝试注册时使用 regsvr32 我得到:“模块 C:/tmp/DllModule.dll 已加载,但未找到 DllRegisterServer 的起始地址. 检查 C:/tmp/DllModule.dll 是否是有效的 DLL 或 OCX 文件,然后重试。"

另外,当我使用时

#import "C\tmp\DllModule.dll"

我明白了

fatal error C1083: Cannot open type library file: 'c:\tmp\dllmodule.dll'


我查看了教程的链接,但有一个小问题:在所有项目类型中没有“ActiveX DLL”之类的东西可供选择。是的,我确实有 Visual Studio 2010 Professional(试用版,但仍然如此)。

-- 萨拉

【问题讨论】:

  • 这无法按预期工作,VB.NET 无法生成本机 DLL 入口点。而且您的 C++ 程序无法在不加载 CLR 的情况下直接调用托管代码。最简单的方法是在您的 vb.net 代码中使用 &lt;ComVisible&gt; 属性,并在您的 C++ 程序中使用 #import 指令编写 COM 代码。
  • 感谢您的提示,汉斯。我目前不确定如何使用 或如何在 C++ 程序中编写 COM 代码,但我会进一步研究!

标签: c++ vb.net dll entry-point getprocaddress


【解决方案1】:

感谢所有输入。我遇到了另一种解决问题的方法,使用多文件程序集而不是我的第一个 dll 方法。

我遵循了这个 HowTo 部分:http://msdn.microsoft.com/en-us/library/226t7yxe.aspx#Y749

VB 代码:DllModule:类库项目

DllModule.vb

Imports System.Runtime.InteropServices

Namespace DllModuleNS
    Public Class Class1

        Public Function ClassAdd(ByRef first As Integer, ByRef sec As Integer) As Integer
            Dim abc As Integer
            abc = first + sec
            Return abc
        End Function

    End Class
End Namespace

我使用 Visual Studio(生成 DllModule.dll 文件)和 cmd-line 编译的这个文件:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Vbc.exe /t:module DllModule.vb

(生成 DllModule.netmodule-file)。

C++ 代码:TryVbDllLoad:控制台应用程序

TryVbDllLoad.cpp

#using <mscorlib.dll>

#using ".\..\ClassLibrary1\DllModule.netmodule"
using namespace DllModule::DllModuleNS;

int _tmain(int argc, _TCHAR* argv[])
{
    Class1^ me = gcnew Class1();
    int a = 1, b = 2;
    int xx = me->ClassAdd(a, b);
    return 0;
}

在我更改的 TryVBDllLoad-project 属性中:

  • 通用属性 -> 框架和参考:添加 DllModule-project 作为参考
  • 配置属性 -> C/C++ -> 常规:/clr 标志集
  • 配置属性 -> 链接器 -> 输入:将模块添加到程序集设置为 DllModule.netmodule 的路径 (/ASSEMBLYMODULE:"DllModule.netmodule")

这导致我可以在 VC++ 代码中使用 VB 类 Class1!

问题解决了!


我现在更进一步,将 TryVBDllLoad 项目更改为 dll:

  • 配置属性 -> 常规:配置类型动态库 (.dll)
  • 配置属性 -> 链接器 -> 系统:子系统窗口 (/SUBSYSTEM:WINDOWS)

TryVbDllLoadClass.h

#ifndef TryVbDllLoadClass_H
#define TryVbDllLoadClass_H

class TryVbDllLoadClass
{
public:
    TryVbDllLoadClass();
    int Add(int a, int b);
};

#endif  // TryVbDllLoadClass_H

TryVbDllLoadClass.cpp

#include "TryVbDllLoadClass.h"
#using <mscorlib.dll>

#using ".\..\ClassLibrary1\DllModule.netmodule"
using namespace DllModule::DllModuleNS;


TryVbDllLoadClass::TryVbDllLoadClass() {}

int TryVbDllLoadClass::Add(int a, int b)
{
Class1^ me = gcnew Class1();
int xx = me->ClassAdd(a, b);
return xx;
}

DllExport.h

#ifndef DLLEXPORT_H
#define DLLEXPORT_H

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

#ifdef __dll__
#define IMPEXP __declspec(dllexport)
#else
#define IMPEXP __declspec(dllimport)
#endif  // __dll__

extern "C" {
    IMPEXP int __stdcall AddFunction(int);
}

#endif  // DLLEXPORT_H

DllMain.h

#define __dll__
#include "dllExport.h"
#include " TryVbDllLoadClass.h"

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
    return 1;
}

TryVbDllLoadClass * my;

IMPEXP int __stdcall AddFunction(int first, int second)
{
    my = new TryVbDllLoadClass();
    int res = my->Add(first, second);
    delete my;
    return res;
}

然后我可以将这个 dll 添加到非可视化工作室项目中,就像普通的 dll 一样:

C++-code : LoadDll : Non-Visual-Studio-project(本例中为 CodeBlock)

main.cpp

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "dllExport.h"

typedef int( * LPFNDLL_CREATE)(int, int);
HINSTANCE hDLL;
LPFNDLL_CREATE func;

using namespace std;

int main()
{
    cout << "Hello world!" << endl;
    int key = 35;

    hDLL = LoadLibrary("TryVbDllLoadClass.dll");

    if(hDLL)
    {
        cout << "Loaded: " << hDLL << endl;

        func = (LPFNDLL_CREATE) (GetProcAddress(hDLL, "_AddFunction@4"));
        if(func != NULL)
        {
            cout << "Connected: " << func << endl;
            cout << "Function returns: " << func(key, key) << endl;
        }
        else cout << " ::: fail: " << GetLastError() << endl;

        FreeLibrary(hDLL);
        cout << "Freed" << endl;
    }
    else cout << " ::: fail: " << GetLastError() << endl;

    printf("-> Goodbye world!\n");
    return 0;
}

通过这种方式,我可以使用在 Visuabl Studio 之外创建的现有 C++ 项目中提供的 VB 类。最后...:)

【讨论】:

  • 不错的萨拉!真的很好,感谢您提供解决方案!
【解决方案2】:

使用 VB,您不会得到“正常”的 DLL(至少以前是这种情况)。 而且您不会获得函数的入口点。

但正如我所理解的,你有 VB 源代码,你可以用它做任何事情 有必要的。这是一个可能的解决方案:

http://www.codeproject.com/Articles/21/Beginner-s-Tutorial-Calling-Visual-Basic-ActiveX-D

但首先尝试这种不太复杂的方法, 因为我认为 VB dll 始终是 COM dll,所以你可以:

使用 Windows 命令注册 dll

regsvr32  F:\proj\VBDllModule.dll

现在你的 C++ 代码:

#import "F:\proj\VBDllModule.dll"

using namespace DllModule;

void CDialogTestDlg::OnButton1()
{
 HRESULT hresult;
 CLSID clsid;
 _CTest *t; // a pointer to the CTest object
 _bstr_t bstrA = L"hello";
 _bstr_t bstrB = L" world";
 _bstr_t bstrR;
 ::CoInitialize(NULL);
  hresult=CLSIDFromProgID(OLESTR("VBTestLib.CTest"), &clsid);
  hresult= CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,
                               __uuidof(_CTest),(LPVOID*) &t);
  if(hresult == S_OK)
  {
     bstrR  = t->vbConcat(bstrA , bstrB);
     AfxMessageBox((char*)bstrR);
   }
}

【讨论】:

  • 感谢汉斯·帕桑特! ComVisible 是至关重要的,但是当你设置它时,上面的示例代码就可以工作了。
  • 该教程(从 1999 年开始)是关于调用 VB6 DLL 而不是 VB.Net DLL。我想如果你确保你的 VB.Net DLL 是 COM 可见的,它可能仍然有效。
  • 我在链接下提供的示例有效且简单明了,但我认为链接中的旧示例做得更干净,并提供了一些背景知识。当需要在 c++ 应用程序中调用 vb dll 时,我会做类似的事情。 (我已经用 c# dll 做了很多,但使用了明确的 IDL。我认为当 COM 新手时这可能会令人不安)。 @OP 请让我们知道您是否可以那样调用您的 dll。
  • @Mare ,我尝试了您的建议,但不幸的是没有成功。查看原始帖子底部的结果。
  • 你用regsrv32注册你的dll了吗?如果是,您还可以尝试 tlbimp.exe 从您的 vb dll 生成类型库。这可能更容易使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多