2

丸 1 週間格闘している問題がありますが、自分では解決できません。私はググって、あらゆる種類のフォーラムを検索してきました...「これはうまくいくかもしれない」ということをたくさん見つけて、試してみましたが、うまくいきませんでした。誰か手がかりがあれば、助けてください!

外部ソースから、C++ アプリケーションから使用できるようにする必要がある、VB で記述された多くのクラスと関数を入手しました。私の最初のことは次のとおりです。問題ありません。VB コードを dll に変換し、C++ プログラムからロードします。これは想像以上に大変でした。私の C++ プログラムは Visual Studio で記述されていませんが、簡単にするために、Visual Studio C++ アプリケーションから (Visual Studio 2010 で記述された) VB dll を読み込もうとすることから始めました。これまでの私のコードは次のとおりです。

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 はエラー コード 127 で NULL を返します (指定されたプロシージャが見つかりませんでした)。

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 を持っています (試用版ですが)。

- サラ

4

2 に答える 2

4

すべての入力に感謝します。最初のdllアプローチではなく、マルチファイルアセンブリを使用して、問題を解決する別の方法を見つけました。

このハウツー セクションに従いました: 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 のプロパティで、次のように変更しました。

  • Common Properties -> Framework and References : DllModule-project を参照として追加
  • 構成プロパティ -> C/C++ -> 一般: /clr フラグを設定
  • 構成プロパティ -> リンカー -> 入力: DllModule.netmodule へのパスに設定されたアセンブリにモジュールを追加 (/ASSEMBLYMODULE:"DllModule.netmodule")

これにより、VC++ コードで VB クラスの Class1 を使用できるようになりました。

問題が解決しました!


さらに一歩進んで、TryVBDllLoad プロジェクトを dll に変更しました。

  • 構成プロパティ -> 一般: Configurationtype 動的ライブラリ (.dll)
  • 構成プロパティ -> リンカー -> システム: サブシステム Windows (/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 と同じように、Visual Studio 以外のプロジェクトに追加できます。

C++ コード : LoadDll : Visual Studio 以外のプロジェクト (この場合は CodeBlocks)

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 クラスを使用できます。ついに...:)

于 2012-06-12T09:39:01.357 に答える
1

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);
   }
}
于 2012-06-08T13:26:16.897 に答える