SHOJI's Code
 仕事や趣味で書いた各種言語のプログラミングコード(エクセルVBA,PHP,C/C++/C#,JavaScript等)、その他雑記。
2017.10<<123456789101112131415161718192021222324252627282930>>2017.12
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

C#でとあるコンポーネントを作成しようと思い、そのためにDLLから関数をインポートする必要があったのだが、作っている途中で、Win32のLoadLibrary関数とGetProcAddress関数を利用した動的なロードをC#で行うコンポーネントなど作れないか?と思い、そちらをちょっと作ってみた。

使い方はこんな感じ
デリゲート宣言
delegate Int32 MessageBoxDelegateW(
IntPtr hwnd,
[MarshalAs(UnmanagedType.LPWStr)] string message,
[MarshalAs(UnmanagedType.LPWStr)] string caption,
UInt32 flags);


DllLoader user32 = new DllLoader("user32.dll");
MessageBoxDelegateW MessageBox = (MessageBoxDelegateW)user32.GetDelegate("MessageBoxWA", typeof(MessageBoxDelegateW));
MessageBox(IntPtr.Zero, "あああ", "いいい", 1);

using System;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.ComponentModel;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace SHOJIsCode.Components
{
///
/// アンマネージドDLLを動的にロードします
///

[Description("アンマネージドDLLを動的にロードします")]
public partial class DllLoader : Component
{
#region "API定義"
///
/// アンマネージドDLLのロード
///

/// DLLファイル名
/// モジュールハンドル
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPWStr)] string filename);

///
/// 関数ポインタの取得
///

/// モジュールハンドル
/// 関数名
/// 関数ポインタ
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string functionname);

///
/// ロードしたアンマネージドDLLの開放
///

/// モジュールハンドル
/// 成功時true
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool FreeLibrary(IntPtr handle);
#endregion

#region "メンバ変数"
///
/// DLLのパス
///

private string _path;

///
/// DLLのモジュールハンドル
///

private IntPtr _hLib;
#endregion

#region "プロパティ"
///
/// DLLファイルパス
///

[Browsable(true),
DefaultValue(""),
Description("アンマネージドDLLのファイルパスを設定/取得します。")]
public string DllPath {
get {
try {
/// デザインモードの場合は保存しているパスをそのまま返す
if (DesignMode) return _path;

/// モジュール未ロードでパスが空の場合は空を返す
if (_path==string.Empty) return string.Empty;

/// フルパスにして返す
return Path.GetFullPath(_path);
}
catch {
/// もしもエラーが発生した場合は、そのまま返す
return _path;
}
}
set {
/// デザインモードでない場合のみロード
if (!DesignMode) {
/// DLLのロード処理
Load(value);
}
else {
/// パスだけセット
_path = value;
}
}
}

///
/// DLLファイル名
///

[Browsable(false),
Description("アンマネージドDLLのファイル名を取得します。")]
public string DllName {
get {
try {
/// モジュール未ロードでパスが空の場合は空を返す
if (_path==string.Empty) return string.Empty;

/// ファイル名を取得して返す
return Path.GetFileName(_path);
}
catch {
/// もしもエラーが発生した場合は、空を返す
return string.Empty;
}
}
}

///
/// モジュールハンドル
///

[Browsable(false),
Description("アンマネージドDLLのモジュールハンドルを取得します。")]
public IntPtr ModuleHandle {
get {
/// モジュールハンドルをそのまま返す
return _hLib;
}
}
#endregion


#region "コンストラクタ"
///
/// アンマネージドDLLを動的にロードします
///

public DllLoader()
{
/// 内部初期化
initialize();

/// コンポーネント初期化
InitializeComponent();
}

///
/// アンマネージドDLLを動的にロードします
///

/// DLLのパス
public DllLoader(string dllpath):this()
{
/// DLLのロード
Load(dllpath);
}

///
/// アンマネージドDLLを動的にロードします
///

/// コンテナ
public DllLoader(IContainer container)
{
/// 内部初期化
initialize();

/// コンテナに追加
container.Add(this);

/// コンポーネント初期化
InitializeComponent();
}
#endregion

#region "メソッド"
///
/// アンマネージドDLLをロードします
///

/// DLLのパス
public void Load(string dllpath)
{
/// DLLをロード
IntPtr h = LoadLibrary(dllpath);

/// ハンドルが有効でない場合、例外を発生
if (h==IntPtr.Zero) Marshal.ThrowExceptionForHR( Marshal.GetHRForLastWin32Error() );

/// 既にロードしているモジュールがあればアンロード
if (_hLib!=IntPtr.Zero) Unload();

/// ハンドル、パスをメンバ変数にセット
setHandles(h, dllpath);
}

///
/// アンマネージドDLLをアンロードします
///

public void Unload()
{
/// メンバ変数のチェック
checkHandle();

/// DLLをアンロード
FreeLibrary(_hLib);

/// メンバ変数クリア
clearHandles();
}

///
/// DLL内のエクスポート関数に対するデリゲートインスタンスを取得します
///

/// 関数名
/// デリゲートの型
/// デリゲートインスタンス
public Delegate GetDelegate(string funcname, Type t)
{
/// メンバ変数のチェック
checkHandle();

/// エクスポート関数のポインタを取得
IntPtr ptr = GetProcAddress(_hLib, funcname);

/// ポインタがNULLなら、例外発生
if (ptr==IntPtr.Zero) Marshal.ThrowExceptionForHR( Marshal.GetHRForLastWin32Error() );

/// 関数ポインタをデリゲートに変換し、返す
return Marshal.GetDelegateForFunctionPointer(ptr, t);
}

///
/// DLL内のエクスポート関数に対するデリゲートインスタンスを取得します
///

/// デリゲートの型
/// 関数名
/// デリゲートインスタンス
public T GetDelegate<T>(string funcname)
{
/// デリゲート(Delegate型)を取得し、型パラメータに合わせてキャストし、返す
return (T)(object)GetDelegate(funcname, typeof(T));
}

///
/// DLL内のエクスポート関数を呼び出します
///

/// 関数名
/// デリゲートの型
/// 関数への引数
/// 関数からの戻り値
public object Invoke(string funcname, Type t, params object[] args)
{
/// 取得したデリゲートのDynamicInvokeメソッドで関数を呼び出し、結果を返す
return GetDelegate(funcname, t).DynamicInvoke(args);
}
#endregion

#region "内部関数"
///
/// 内部初期化
///

private void initialize()
{
/// メンバ変数クリア
clearHandles();
}

///
/// メンバ変数のチェック
///

private void checkHandle()
{
/// モジュールハンドルがNULLならば、例外発生
if (_hLib==IntPtr.Zero) throw new InvalidOperationException("モジュールがロードされていません");
}

///
/// メンバ変数のセット
///

/// モジュールハンドル
/// DLLパス
private void setHandles(IntPtr h, string dllpath)
{
/// メンバ変数にセット
_hLib = h;
_path = dllpath;
}

///
/// メンバ変数のクリア
///

private void clearHandles()
{
/// 初期値をセット
setHandles(IntPtr.Zero, string.Empty);
}
#endregion
}
}


テーマ:プログラミング - ジャンル:コンピュータ
コメント
この記事へのコメント
(210,16): エラー CS0246: 型または名前空間名 'T' が見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足しています。
2012/05/15(火) 15:39:20 | URL | #-[ 編集]
Re: タイトルなし
> (210,16): エラー CS0246: 型または名前空間名 'T' が見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足しています。

GetDelegate<T>() の型パラメータの部分を &lt; とかにしてなかったから、消えてましたね。
失礼しました。
2012/08/24(金) 11:31:21 | URL | SHOJI #-[ 編集]
コメントを投稿する

管理者にだけ表示を許可する
トラックバック
この記事のトラックバックURL
この記事へのトラックバック
copyright © 2004-2006 SHOJI, Powered By FC2ブログ all rights reserved.
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。