外部DLLの参照について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
とめ

外部DLLの参照について

#1

投稿記事 by とめ » 11ヶ月前

VC++で既存のDLLをラップして拡張版DLLを作成しようとしているのですが、最初でつまづきました。

Visual Studio 2015 でプロジェクトの新規作成から、Win32コンソールアプリ > DLLと
選択してプロジェクトを作成し、いざオリジナルのDLLを取り込もうとして
ソリューションエクスプローラのReferencesを右クリック、「参照の追加」から参照追加の
ダイアログを開いたまではいいのですが、ダイアログ上のメッセージで
 『項目が見つかりませんでした』
という表示だけが出て、ボタンはOKとキャンセルしかなく、参照の追加ができないため
全く先に進めなkなりました。

内部でMFCを使う理由は特になく、配布時の簡易さやファイルサイズなどから、MFC DLLでなく
できればWin32 DLLの方が望ましいと考えているのですが、Win32コンソールアプリ の DLL 
としてプロジェクトを作成する場合、外部DLLの参照はできないという制約などがあるのでしょうか。

YuO
記事: 909
登録日時: 7年前
住所: 東京都世田谷区

Re: 外部DLLの参照について

#2

投稿記事 by YuO » 11ヶ月前

Win32 DLLを利用するには,DLLを直接参照するのでは無く,インポートライブラリと呼ばれるライブラリをリンクします。
DLLをビルドすると,同時に作成される他,libコマンドに/defパラメータ(と.DEFファイル)を渡してインポートライブラリを作成することもできます。

同一ソリューションにDLLのプロジェクトが存在する場合には,参照で可能なようですが。これは特殊な例だと考えた方がよいでしょう。

xiaozhu_c1

Re: 外部DLLの参照について

#3

投稿記事 by xiaozhu_c1 » 11ヶ月前

アドバイスありがとうございます! 返信遅れてすみません。

「参照の追加」から行う参照ではなく、インポートライブラリという方法を使うのですね。

#import "C:\mylib\Target.dll"

としてみたのですが、
 エラー C1083 タイプ ライブラリ ファイルを開けません。
  'c:\mylib\Target.dll':タイプ ライブラリ/DLL の読み込みエラーです。
というエラーになりました。
取り込み方が間違っているでしょうか。(そもそもimportにフルパスでファイル指定するのはあり?)

なおパスを存在しないものに変えると、同じエラーコードですがNo such file or directory
というメッセージが付加されるので、ファイルを読み込みにいこうとはしていると思います。

なお、取り込みたいDLLは、.NET で作られたもののようです。
(C#のプロジェクトからそのまま利用できることが確認できたため)

基本的な質問で申し訳ありませんが、上記でお気づきの点がありましたらアドバイス頂けませんでしょうか。

xiaozhu_c1

Re: 外部DLLの参照について

#4

投稿記事 by xiaozhu_c1 » 11ヶ月前

「インポートライブラリ」について調べてみましたが、
拡張子「.lib」のライブラリファイル?というものが必要ということでしょうか。

手元の資材には、「.lib」のファイルがないのですが、この場合には
まず「.lib」を入手か生成?する必要があるのでしょうか。

調べながら、DLLの呼出には必要な手続きがいろいろあり得る事はおぼろげに見えてきたのですが、
現在やりたいこと(.NET AssemblyのDLL?をVC++で取り込んで利用する)に対してどのような
手続きをとればよいのか見極められておらず、やや困惑しています。

naohiro19
記事: 252
登録日時: 7年前
住所: 愛知県

Re: 外部DLLの参照について

#5

投稿記事 by naohiro19 » 11ヶ月前

#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属性を使います。

xiaozhu_c1

Re: 外部DLLの参照について

#6

投稿記事 by xiaozhu_c1 » 11ヶ月前

アドバイスありがとうございます。 この周辺には全く不慣れなため、大変参考になります。 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++で取り込んで利用する場合、上記のアプローチではうまく
いかないということでしょうか。。

wu--hu--

Re: 外部DLLの参照について

#7

投稿記事 by wu--hu-- » 11ヶ月前

いろいろMSのプログラミング関連の「発明」を見てきたが、
彼らの狙いはいったいなんなんでしょうか。
プログラマーの過労死?

naohiro19
記事: 252
登録日時: 7年前
住所: 愛知県

Re: 外部DLLの参照について

#8

投稿記事 by naohiro19 » 1ヶ月前

C++/CLI(VIsual C++のCLRプロジェクト)というのを用いることで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;
	}
}
この2つの関数をC#/VB.NET/F#から呼べるようにC++/CLIのラッパークラスを作成します。
このコードは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;
}
上記のラッパークラスを呼び出す C#のコードです。

コード:

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));

        }
    }
}

Math

Re: 外部DLLの参照について

#9

投稿記事 by Math » 1ヶ月前

>なお、取り込みたいDLLは、.NET で作られたもののようです。
>(C#のプロジェクトからそのまま利用できることが確認できたため)
さいしょの目的が
>VC++で既存のDLLをラップして拡張版DLLを作成しようとしているのですが、最初でつまづきました。
拡張版DLLであるなら
C#でつくるべきです。C#は.NetFramework上で動くものでありC++Win32の欠点をなくしてメモリー管理(ガベージコレクション)を自動化しています。ポインターは可変であり変わりにハンドル(^)をつかいトラッキング(追跡参照)します。
C#ではDLLはEXEとの差はすくなくいまではEXEも参照設定できます。
過去の遺産であるWin32DLLをC#でつかうことはよくありますが C#のDLLをC++で拡張するのは?ですね。

 

返信

“C言語何でも質問掲示板” へ戻る