VC++で既存のDLLをラップして拡張版DLLを作成しようとしているのですが、最初でつまづきました。
Visual Studio 2015 でプロジェクトの新規作成から、Win32コンソールアプリ > DLLと
選択してプロジェクトを作成し、いざオリジナルのDLLを取り込もうとして
ソリューションエクスプローラのReferencesを右クリック、「参照の追加」から参照追加の
ダイアログを開いたまではいいのですが、ダイアログ上のメッセージで
『項目が見つかりませんでした』
という表示だけが出て、ボタンはOKとキャンセルしかなく、参照の追加ができないため
全く先に進めなkなりました。
内部でMFCを使う理由は特になく、配布時の簡易さやファイルサイズなどから、MFC DLLでなく
できればWin32 DLLの方が望ましいと考えているのですが、Win32コンソールアプリ の DLL
としてプロジェクトを作成する場合、外部DLLの参照はできないという制約などがあるのでしょうか。
外部DLLの参照について
Re: 外部DLLの参照について
アドバイスありがとうございます! 返信遅れてすみません。
「参照の追加」から行う参照ではなく、インポートライブラリという方法を使うのですね。
#import "C:\mylib\Target.dll"
としてみたのですが、
エラー C1083 タイプ ライブラリ ファイルを開けません。
'c:\mylib\Target.dll':タイプ ライブラリ/DLL の読み込みエラーです。
というエラーになりました。
取り込み方が間違っているでしょうか。(そもそもimportにフルパスでファイル指定するのはあり?)
なおパスを存在しないものに変えると、同じエラーコードですがNo such file or directory
というメッセージが付加されるので、ファイルを読み込みにいこうとはしていると思います。
なお、取り込みたいDLLは、.NET で作られたもののようです。
(C#のプロジェクトからそのまま利用できることが確認できたため)
基本的な質問で申し訳ありませんが、上記でお気づきの点がありましたらアドバイス頂けませんでしょうか。
「参照の追加」から行う参照ではなく、インポートライブラリという方法を使うのですね。
#import "C:\mylib\Target.dll"
としてみたのですが、
エラー C1083 タイプ ライブラリ ファイルを開けません。
'c:\mylib\Target.dll':タイプ ライブラリ/DLL の読み込みエラーです。
というエラーになりました。
取り込み方が間違っているでしょうか。(そもそもimportにフルパスでファイル指定するのはあり?)
なおパスを存在しないものに変えると、同じエラーコードですがNo such file or directory
というメッセージが付加されるので、ファイルを読み込みにいこうとはしていると思います。
なお、取り込みたいDLLは、.NET で作られたもののようです。
(C#のプロジェクトからそのまま利用できることが確認できたため)
基本的な質問で申し訳ありませんが、上記でお気づきの点がありましたらアドバイス頂けませんでしょうか。
Re: 外部DLLの参照について
「インポートライブラリ」について調べてみましたが、
拡張子「.lib」のライブラリファイル?というものが必要ということでしょうか。
手元の資材には、「.lib」のファイルがないのですが、この場合には
まず「.lib」を入手か生成?する必要があるのでしょうか。
調べながら、DLLの呼出には必要な手続きがいろいろあり得る事はおぼろげに見えてきたのですが、
現在やりたいこと(.NET AssemblyのDLL?をVC++で取り込んで利用する)に対してどのような
手続きをとればよいのか見極められておらず、やや困惑しています。
拡張子「.lib」のライブラリファイル?というものが必要ということでしょうか。
手元の資材には、「.lib」のファイルがないのですが、この場合には
まず「.lib」を入手か生成?する必要があるのでしょうか。
調べながら、DLLの呼出には必要な手続きがいろいろあり得る事はおぼろげに見えてきたのですが、
現在やりたいこと(.NET AssemblyのDLL?をVC++で取り込んで利用する)に対してどのような
手続きをとればよいのか見極められておらず、やや困惑しています。
Re: 外部DLLの参照について
#import は Visual C++ の ATL(Active Template Library)プロジェクトで作られたCOM形式のDLLもしくはOCXファイルでなければ参照できません。
C#やVBのプロジェクトの設定から「アセンブリをCOM参照可能にする」にチェックを入れてビルドすれば #import が利用できます。
「Win32プロジェクト」の「ダイナミックリンクライブラリで作られたDLLは Windows APIの「LoadLibrary」「GetProcAddress」「FreeLibrary」を利用して呼び出します。
拡張子が「*.lib」のものは Visual Studio では #pragma comment(lib, "*.lib") と指定するか、
プロジェクトの設定で「追加のライブラリディレクトリ」と「追加の依存ライブラリ」の設定をする必要があります。
また、C#で 「Win32プロジェクト」の「ダイナミックリンクライブラリで作られたDLLは C#からは呼び出せません。
どうするのかというと System.Runtime.InteropServices名前空間の DllImport属性を使います。
C#やVBのプロジェクトの設定から「アセンブリをCOM参照可能にする」にチェックを入れてビルドすれば #import が利用できます。
「Win32プロジェクト」の「ダイナミックリンクライブラリで作られたDLLは Windows APIの「LoadLibrary」「GetProcAddress」「FreeLibrary」を利用して呼び出します。
拡張子が「*.lib」のものは Visual Studio では #pragma comment(lib, "*.lib") と指定するか、
プロジェクトの設定で「追加のライブラリディレクトリ」と「追加の依存ライブラリ」の設定をする必要があります。
また、C#で 「Win32プロジェクト」の「ダイナミックリンクライブラリで作られたDLLは C#からは呼び出せません。
どうするのかというと System.Runtime.InteropServices名前空間の DllImport属性を使います。
Re: 外部DLLの参照について
アドバイスありがとうございます。 この周辺には全く不慣れなため、大変参考になります。 m(_ _)m
頂いたアドバイスを元にDLLの種類やその利用方法を調べてみていますが、複雑ですね。。
次のようなコードを書いてみたのですが、関数アドレスの取得の部分でlpFuncに有効値がとれませんでした。
// DLLロード
HMODULE hModule = LoadLibrary(L"Target.dll");
if (hModule == NULL) {
MessageBox::Show(L"DLLのロードに失敗しました。", L"DLLロード");
return;
}
// 関数のアドレス取得
FARPROC lpFunc = GetProcAddress(hModule, "Draw");
if (lpFunc == NULL) {
MessageBox::Show(L"関数のアドレス取得に失敗しました。", L"DLL関数アドレス");
FreeLibrary(hModule);
return;
}
そこで下記のように dumpbin (C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\binにあるもの)
というものを試してみたところ、有効に呼べそうなメンバーは認識されていないようでした。
(対象のDLLは、VB .NETおよびC#としては利用の実績のあるものです)
C:\mylib>dumpbin /exports Target.dll
Microsoft (R) COFF/PE Dumper Version 14.00.23506.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file Target.dll
File Type: DLL
Summary
2000 .reloc
2000 .rsrc
642000 .text
C:\mylib>
このため、対象のDLLは「Win32プロジェクトのダイナミックリンクライブラリとして作られたもの」では
なさそうだと思われます。
「LoadLibrary」「GetProcAddress」の使い方自体の問題でしょうか、それとも
.NET Assemblyと思われるDLLをVC++で取り込んで利用する場合、上記のアプローチではうまく
いかないということでしょうか。。
頂いたアドバイスを元にDLLの種類やその利用方法を調べてみていますが、複雑ですね。。
次のようなコードを書いてみたのですが、関数アドレスの取得の部分でlpFuncに有効値がとれませんでした。
// DLLロード
HMODULE hModule = LoadLibrary(L"Target.dll");
if (hModule == NULL) {
MessageBox::Show(L"DLLのロードに失敗しました。", L"DLLロード");
return;
}
// 関数のアドレス取得
FARPROC lpFunc = GetProcAddress(hModule, "Draw");
if (lpFunc == NULL) {
MessageBox::Show(L"関数のアドレス取得に失敗しました。", L"DLL関数アドレス");
FreeLibrary(hModule);
return;
}
そこで下記のように dumpbin (C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\binにあるもの)
というものを試してみたところ、有効に呼べそうなメンバーは認識されていないようでした。
(対象のDLLは、VB .NETおよびC#としては利用の実績のあるものです)
C:\mylib>dumpbin /exports Target.dll
Microsoft (R) COFF/PE Dumper Version 14.00.23506.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file Target.dll
File Type: DLL
Summary
2000 .reloc
2000 .rsrc
642000 .text
C:\mylib>
このため、対象のDLLは「Win32プロジェクトのダイナミックリンクライブラリとして作られたもの」では
なさそうだと思われます。
「LoadLibrary」「GetProcAddress」の使い方自体の問題でしょうか、それとも
.NET Assemblyと思われるDLLをVC++で取り込んで利用する場合、上記のアプローチではうまく
いかないということでしょうか。。
Re: 外部DLLの参照について
C++/CLI(VIsual C++のCLRプロジェクト)というのを用いることでC#から呼び出すことができます。
たとえば簡単な関数(名前空間あり)・クラスを呼び出すスタティックライブラリを作ります(Win32プロジェクト
この2つの関数をC#/VB.NET/F#から呼べるようにC++/CLIのラッパークラスを作成します。
このコードはCppSharpというのを用いて実現します。
上記のラッパークラスを呼び出す C#のコードです。
たとえば簡単な関数(名前空間あり)・クラスを呼び出すスタティックライブラリを作ります(Win32プロジェクト
// CppFunctions.h
#pragma once
int CppGlobalFunc(int i);
namespace CppTestNamespace
{
int CppScopedFunc(int i);
}
// CppFunctions.cpp
#include <iostream>
#include "CppFunctions.h"
int CppGlobalFunc(int i)
{
std::cout << "CppGlobalFunc" << std::endl;
return i;
}
namespace CppTestNamespace
{
int CppScopedFunc(int i)
{
std::cout << "CppScopedFunc" << std::endl;
return i;
}
}
このコードはCppSharpというのを用いて実現します。
//CppFunctions.h (C++/CLI)
// ----------------------------------------------------------------------------
// <auto-generated>
// This is autogenerated code by CppSharp.
// Do not edit this file or all your changes will be lost after re-generation.
// </auto-generated>
// ----------------------------------------------------------------------------
#pragma once
#include "CppSharp.h"
#include <../../CppTest/CppFunctions.h>
namespace CppTest
{
}
namespace CppTest
{
public ref class CppFunctions
{
public:
static int CppGlobalFunc(int i);
};
namespace CppTestNamespace
{
public ref class CppFunctions
{
public:
static int CppScopedFunc(int i);
};
}
}
// CppFunctions.cpp(C++/CLI)
// ----------------------------------------------------------------------------
// <auto-generated>
// This is autogenerated code by CppSharp.
// Do not edit this file or all your changes will be lost after re-generation.
// </auto-generated>
// ----------------------------------------------------------------------------
#include "CppFunctions.h"
using namespace System;
using namespace System::Runtime::InteropServices;
int CppTest::CppFunctions::CppGlobalFunc(int i)
{
auto __ret = ::CppGlobalFunc(i);
return __ret;
}
int CppTest::CppTestNamespace::CppFunctions::CppScopedFunc(int i)
{
auto __ret = ::CppTestNamespace::CppScopedFunc(i);
return __ret;
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CppTest;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(CppFunctions.CppGlobalFunc(123));
Console.WriteLine(CppTest.CppTestNamespace.CppFunctions.CppScopedFunc(456));
}
}
}
Re: 外部DLLの参照について
>なお、取り込みたいDLLは、.NET で作られたもののようです。
>(C#のプロジェクトからそのまま利用できることが確認できたため)
さいしょの目的が
>VC++で既存のDLLをラップして拡張版DLLを作成しようとしているのですが、最初でつまづきました。
拡張版DLLであるなら
C#でつくるべきです。C#は.NetFramework上で動くものでありC++Win32の欠点をなくしてメモリー管理(ガベージコレクション)を自動化しています。ポインターは可変であり変わりにハンドル(^)をつかいトラッキング(追跡参照)します。
C#ではDLLはEXEとの差はすくなくいまではEXEも参照設定できます。
過去の遺産であるWin32DLLをC#でつかうことはよくありますが C#のDLLをC++で拡張するのは?ですね。
>(C#のプロジェクトからそのまま利用できることが確認できたため)
さいしょの目的が
>VC++で既存のDLLをラップして拡張版DLLを作成しようとしているのですが、最初でつまづきました。
拡張版DLLであるなら
C#でつくるべきです。C#は.NetFramework上で動くものでありC++Win32の欠点をなくしてメモリー管理(ガベージコレクション)を自動化しています。ポインターは可変であり変わりにハンドル(^)をつかいトラッキング(追跡参照)します。
C#ではDLLはEXEとの差はすくなくいまではEXEも参照設定できます。
過去の遺産であるWin32DLLをC#でつかうことはよくありますが C#のDLLをC++で拡張するのは?ですね。