DoboWiki
Top
> .NETプログラミング研究/16 をテンプレートにして作成
.NETプログラミング研究/16 をテンプレートにして作成
開始行:
#title(.NETプログラミング研究 第16号)
#navi(.NETプログラミング研究)
#contents
*.NETプログラミング研究 第16号 [#sd6be91c]
**ピンポイントリンク [#bf313648]
**遅延バインディングによりアンマネージDLL関数を呼び出す [...
#column(注意){{
この記事の最新版は「[[遅延バインディングによりアンマネー...
}}
ここでは.NETで外部のDLLの関数(アンマネージDLL関数)を呼...
-[[統合アーカイバプロジェクト>http://www.madobe.net/archi...
-[[Micco's HomePage>http://www2.nsknet.or.jp/~micco/micin...
***Unlha32.dllを使って書庫を展開する方法 [#s6b5c9fe]
DLL関数の呼び出し方の説明は後にして、まずはUnlha32.dllを...
Unlha32.dllはLHA(.lzh)形式の書庫を操作(圧縮、解凍など)...
Unlha32.dllで書庫を展開するには、通常Unlha関数を使います...
x 書庫名 解凍先フォルダ名 *
などとします。これにオプション等を付加していけば、展開方...
展開に関してはこれだけですが、余計なエラーがないように、...
これで書庫の展開に関するUnlha32.dllの知識は身に付いたもの...
***DllImportによるアンマネージDLL関数の呼び出し [#jd2de5f6]
.NETでアンマネージDLL関数を呼び出す方法としては、DllImpor...
ここではこの方法を紹介することが目的ではないため、DllImpo...
-[[アンマネージ DLL 関数の処理>http://www.microsoft.com/j...
-[[プラットフォーム呼び出しによるデータのマーシャリング>h...
以降、これらの知識がすでにあるものとして話を進めさせてい...
***書庫を展開する [#xfd4bc9f]
以上の知識を基に、いよいよ実際に書庫を展開するコードを書...
#code(vbnet){{
'Imports System.Runtime.InteropServices
'が宣言されているものとする
'DLL の版の取得
<DllImport("unlha32")> _
Private Shared Function UnlhaGetVersion() As UInt16
End Function
'DLL の実行状況の取得
<DllImport("unlha32")> _
Private Shared Function UnlhaGetRunning() As Boolean
End Function
'書庫のチェック
<DllImport("unlha32")> _
Private Shared Function UnlhaCheckArchive( _
ByVal szFileName As String, _
ByVal iMode As Integer) As Boolean
End Function
'書庫操作一般
<DllImport("unlha32")> _
Private Shared Function Unlha( _
ByVal hwnd As Integer, _
ByVal szCmdLine As String, _
ByVal szOutput As String, _
ByVal dwSize As Integer) As Integer
End Function
'/ <summary>
'/ UNLHA32.DLLで書庫を展開する
'/ </summary>
'/ <param name="archiveFile">書庫ファイル名</param>
'/ <param name="extractDir">展開先のフォルダ名</param>
Public Shared Sub LhaExtractArchive( _
ByVal archiveFile As String, _
ByVal extractDir As String)
'指定されたファイルがあるか調べる
If Not System.IO.File.Exists(archiveFile) Then
Throw New ApplicationException("ファイルが見つか...
End If
'DLLのチェック
Try
Dim ver As UInt16 = UnlhaGetVersion()
Console.WriteLine("バージョン:{0}", ver)
Catch
Throw New _
ApplicationException("Unlha32.dllがインストー...
End Try
'動作中かチェック
If UnlhaGetRunning() Then
Throw New ApplicationException("DLLが動作中")
End If
'展開できるかチェック
If Not UnlhaCheckArchive(archiveFile, 0) Then
Throw New ApplicationException("対応書庫ではあり...
End If
'ファイル名とフォルダ名を修正する
If archiveFile.IndexOf(" "c) > 0 Then
archiveFile = """" + archiveFile + """"
End If
If Not extractDir.EndsWith("\") Then
extractDir += "\"
End If
If extractDir.IndexOf(" "c) > 0 Then
extractDir = """" + extractDir + """"
End If
'展開する
Dim ret As Integer = Unlha(0, _
String.Format("x {0} {1} *", archiveFile, extract...
Nothing, 0)
'結果
If ret <> 0 Then
Throw New ApplicationException("書庫の展開に失敗...
End If
End Sub
}}
#code(csharp){{
//using System.Runtime.InteropServices;
//が宣言されているものとする
//DLL の版の取得
[DllImport("unlha32")]
private extern static UInt16 UnlhaGetVersion();
//DLL の実行状況の取得
[DllImport("unlha32")]
private extern static bool UnlhaGetRunning();
//書庫のチェック
[DllImport("unlha32")]
private extern static bool UnlhaCheckArchive(string szFil...
int iMode);
//書庫操作一般
[DllImport("unlha32")]
private extern static int Unlha(int hwnd, string szCmdLin...
string szOutput, int dwSize);
/// <summary>
/// UNLHA32.DLLで書庫を展開する
/// </summary>
/// <param name="archiveFile">書庫ファイル名</param>
/// <param name="extractDir">展開先のフォルダ名</param>
public static void LhaExtractArchive(
string archiveFile, string extractDir)
{
//指定されたファイルがあるか調べる
if (!System.IO.File.Exists(archiveFile))
throw new ApplicationException("ファイルが見つか...
//DLLのチェック
try
{
UInt16 ver = UnlhaGetVersion();
Console.WriteLine("バージョン:{0}", ver);
}
catch
{
throw new ApplicationException("Unlha32.dllがイン...
}
//動作中かチェック
if (UnlhaGetRunning())
throw new ApplicationException("DLLが動作中");
//展開できるかチェック
if (!UnlhaCheckArchive(archiveFile, 0))
throw new ApplicationException("対応書庫ではあり...
//ファイル名とフォルダ名を修正する
if (archiveFile.IndexOf(' ') > 0)
archiveFile = "\"" + archiveFile + "\"";
if (!extractDir.EndsWith("\\"))
extractDir += "\\";
if (extractDir.IndexOf(' ') > 0)
extractDir = "\"" + extractDir + "\"";
//展開する
int ret = Unlha(0,
string.Format("x {0} {1} *", archiveFile, extract...
null, 0);
//結果
if (ret != 0)
throw new ApplicationException("書庫の展開に失敗...
}
}}
うまく行きましたか?普通ならこれで、
「書庫が解凍できました。めでたし、めでたし。」
となって終わるところでしょうが、それでは面白くもなんとも...
***遅延バインディングの意義 [#nbb869e5]
私はこの記事の一番初めに
最終的には「統合アーカイバプロジェクト」に対応したあらゆ...
と書きました。さて、UNLHA32.DLL以外のDLLを使って書庫を展...
例えば"UNZIP32.DLL"(shoda T.さん作)の場合は、先のUNLHA3...
"CAB32.DLL"(宮内邦昭さん作)の場合も同様に、UNLHA32.DLL...
"UNZIP32.DLL"と"CAB32.DLL"の例を示しましたが、実は統合ア...
このような仕様のおかげで、統合アーカイバ仕様のDLLを使用す...
今までの考察からすれば、DLLファイル名と、そのDLLのAPIの頭...
もしDllImportでDLLファイル名と関数の名前(呼び出すDLLエン...
.NETでは無理ですが、実はVC++ではこれは造作ないことです。L...
-[[Visual C++ の概念: 機能の追加 - DLL>http://www.microso...
.NETでも同じことが出来ればよいのですが、果たして可能でし...
***遅延バインディングによる方法 [#r84fcfbf]
その答えが、Richard Birkbyさんが書いた「The Code Project ...
-[[The Code Project - Late binding on native DLLs with C#...
詳しくはこのページを読んでいただきたいのですが、つまりは...
Win32 APIのLoadLibrary関数とGetProcAddress関数により指定...
上記のページからダウンロードできるアーカイバにはソースし...
それでは今度はこの方法で先のコードを書き換えてみましょう...
#code(vbnet){{
'Imports System.Runtime.InteropServices
'が宣言されているものとする
'DLLモジュールをマップ
<DllImport("kernel32")> _
Private Shared Function LoadLibrary( _
ByVal lpLibFileName As String) As Integer
End Function
'マップを解除
<DllImport("kernel32")> _
Private Shared Function FreeLibrary( _
ByVal hLibModule As Integer) As Boolean
End Function
'関数のアドレスを取得
<DllImport("kernel32")> _
Private Shared Function GetProcAddress( _
ByVal hModule As Integer, ByVal lpProcName As String)...
End Function
'以下使用するAPIのためのInvokeFunc
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeGetVersion( _
ByVal funcptr As Integer) As UInt16
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeGetRunning( _
ByVal funcptr As Integer) As Boolean
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeCheckArchive( _
ByVal funcptr As Integer, _
ByVal szFileName As String, _
ByVal iMode As Integer) As Boolean
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeMain( _
ByVal funcptr As Integer, _
ByVal hwnd As Integer, _
ByVal szCmdLine As String, _
ByVal szOutput As String, _
ByVal dwSize As Integer) As Integer
End Function
'/ <summary>
'/ 統合アーカイバ仕様のDLLで書庫を展開する
'/ </summary>
'/ <param name="dllName">DLLファイル名</param>
'/ <param name="funcName">APIの頭に付く文字列</param>
'/ <param name="command">展開のためのコマンド</param>
'/ <param name="archiveFile">書庫ファイル名</param>
'/ <param name="extractDir">展開先のフォルダ名</param>
Public Shared Sub ExtractArchive( _
ByVal dllName As String, _
ByVal funcName As String, _
ByVal command As String, _
ByVal archiveFile As String, _
ByVal extractDir As String)
'指定されたファイルがあるか調べる
If Not System.IO.File.Exists(archiveFile) Then
Throw New ApplicationException("ファイルが見つか...
End If
'DLLをロード
Dim hmod As Integer = LoadLibrary(dllName)
If hmod = 0 Then
Throw New ApplicationException( _
dllName + "のロードに失敗しました")
End If
Try
Dim funcaddr As Integer
'DLLのチェック
'関数のアドレスを取得
funcaddr = GetProcAddress(hmod, funcName + "GetVe...
If funcaddr = 0 Then
Throw New ApplicationException( _
dllName + "がインストールされていません")
End If
Dim ver As UInt16 = InvokeGetVersion(funcaddr)
Console.WriteLine("バージョン:{0}", ver)
'動作中かチェック
funcaddr = GetProcAddress(hmod, funcName + "GetRu...
If funcaddr = 0 Then
Throw New ApplicationException( _
funcName + "GetRunningのアドレスが取得で...
End If
If InvokeGetRunning(funcaddr) Then
Throw New ApplicationException(dllName + "が...
End If
'展開できるかチェック
funcaddr = GetProcAddress(hmod, funcName + "Check...
If funcaddr = 0 Then
Throw New ApplicationException( _
funcName + "CheckArchiveのアドレスが取得...
End If
If Not InvokeCheckArchive(funcaddr, archiveFile, ...
Throw New ApplicationException( _
archiveFile + "は対応書庫ではありません")
End If
'ファイル名とフォルダ名を修正する
If archiveFile.IndexOf(" "c) > 0 Then
archiveFile = """" + archiveFile + """"
End If
If Not extractDir.EndsWith("\") Then
extractDir += "\"
End If
If extractDir.IndexOf(" "c) > 0 Then
extractDir = """" + extractDir + """"
End If
'展開する
funcaddr = GetProcAddress(hmod, funcName)
If funcaddr = 0 Then
Throw New ApplicationException( _
funcName + "のアドレスが取得できませんで...
End If
Dim ret As Integer = InvokeMain(funcaddr, 0, _
String.Format(command, archiveFile, extractDi...
Nothing, 0)
'結果
If ret <> 0 Then
Throw New ApplicationException("書庫の展開に...
End If
Finally
'開放する
If hmod <> 0 Then
FreeLibrary(hmod)
End If
End Try
End Sub
}}
#code(csharp){{
//using System.Runtime.InteropServices;
//が宣言されているものとする
//DLLモジュールをマップ
[DllImport("kernel32")]
private extern static int LoadLibrary(string lpLibFileNam...
//マップを解除
[DllImport("kernel32")]
private extern static bool FreeLibrary(int hLibModule);
//関数のアドレスを取得
[DllImport("kernel32")]
private extern static int GetProcAddress(int hModule,
string lpProcName);
//以下使用するAPIのためのInvokeFunc
[DllImport("Invoke", EntryPoint="InvokeFunc")]
privatelic extern static UInt16 InvokeGetVersion(int func...
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static bool InvokeGetRunning(int funcptr);
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static bool InvokeCheckArchive(int funcptr,
string szFileName, int iMode);
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static int InvokeMain(int funcptr, int hwnd,
string szCmdLine, string szOutput, int dwSize);
/// <summary>
/// 統合アーカイバ仕様のDLLで書庫を展開する
/// </summary>
/// <param name="dllName">DLLファイル名</param>
/// <param name="funcName">APIの頭に付く文字列</param>
/// <param name="command">展開のためのコマンド</param>
/// <param name="archiveFile">書庫ファイル名</param>
/// <param name="extractDir">展開先のフォルダ名</param>
public static void ExtractArchive(string dllName, string ...
string command, string archiveFile, string extractDir)
{
//指定されたファイルがあるか調べる
if (!System.IO.File.Exists(archiveFile))
throw new ApplicationException("ファイルが見つか...
//DLLをロード
int hmod = LoadLibrary(dllName);
if (hmod == 0)
throw new ApplicationException(dllName + "のロー...
try
{
int funcaddr;
//DLLのチェック
//関数のアドレスを取得
funcaddr = GetProcAddress(hmod, funcName + "GetVe...
if (funcaddr == 0)
throw new ApplicationException(
dllName + "がインストールされていません");
UInt16 ver = InvokeGetVersion(funcaddr);
Console.WriteLine("バージョン:{0}", ver);
//動作中かチェック
funcaddr = GetProcAddress(hmod, funcName + "GetRu...
if (funcaddr == 0)
throw new ApplicationException(
funcName + "GetRunningのアドレスが取得で...
if (InvokeGetRunning(funcaddr))
throw new ApplicationException(dllName + "が...
//展開できるかチェック
funcaddr = GetProcAddress(hmod, funcName + "Check...
if (funcaddr == 0)
throw new ApplicationException(
funcName + "CheckArchiveのアドレスが取得...
if (!InvokeCheckArchive(funcaddr, archiveFile, 0))
throw new ApplicationException(
archiveFile + "は対応書庫ではありません");
//ファイル名とフォルダ名を修正する
if (archiveFile.IndexOf(' ') > 0)
archiveFile = "\"" + archiveFile + "\"";
if (!extractDir.EndsWith("\\"))
extractDir += "\\";
if (extractDir.IndexOf(' ') > 0)
extractDir = "\"" + extractDir + "\"";
//展開する
funcaddr = GetProcAddress(hmod, funcName);
if (funcaddr == 0)
throw new ApplicationException(
funcName + "のアドレスが取得できませんで...
int ret = InvokeMain(funcaddr, 0,
string.Format(command, archiveFile, extractDi...
null, 0);
//結果
if (ret != 0)
throw new ApplicationException("書庫の展開に...
}
finally
{
//開放する
if (hmod != 0)
FreeLibrary(hmod);
}
}
}}
これでユーザーがこれらの情報を与えることですべての統合ア...
***ついに完成! [#yc85ef65]
一応の目標は達成したといえますが、せっかくここまで来たの...
書庫の展開に必要なDLLに関する情報はユーザーがXML形式のフ...
ユーザーが与えるXMLファイルは例えば次のように記述するもの...
#code(xml){{
<?xml version="1.0"?>
<ArrayOfArchiverDllInfo xmlns:xsd="http://www.w3.org/2001...
<ArchiverDllInfo>
<FileName>unlha32</FileName>
<FunctionName>Unlha</FunctionName>
<CommandToExtract>x {0} {1} *</CommandToExtract>
</ArchiverDllInfo>
<ArchiverDllInfo>
<FileName>unzip32</FileName>
<FunctionName>UnZip</FunctionName>
<CommandToExtract>-x {0} {1} *</CommandToExtract>
</ArchiverDllInfo>
<ArchiverDllInfo>
<FileName>cab32</FileName>
<FunctionName>Cab</FunctionName>
<CommandToExtract>-x {0} {1} *</CommandToExtract>
</ArchiverDllInfo>
</ArrayOfArchiverDllInfo>
}}
次の例はコンソールアプリです。コマンドライン引数に展開し...
#code(vbnet){{
'C#のコードを'C# to VB.NET Translator'で変換し、修正した...
'http://www.aspalliance.com/aldotnet/examples/translate.a...
Imports System
Imports System.Runtime.InteropServices
Namespace Dobon.Sample.File
Public Class ExtractArchiveWithDll
Public Shared Sub Main(ByVal args() As String)
Dim arg As String
For Each arg In args
'展開先のフォルダ名を決める
'ここではデスクトップ上の書庫ファイル名の...
Dim extractDir As String = _
System.Environment.GetFolderPath( _
System.Environment.SpecialFolder.Desk...
extractDir += "\" + _
System.IO.Path.GetFileNameWithoutExte...
'存在しないフォルダ名を探す
If System.IO.Directory.Exists(extractDir)...
Dim n As Integer = 1
While System.IO.Directory.Exists( _
extractDir + n.ToString())
n += 1
End While
extractDir += n.ToString()
End If
Console.WriteLine("""{0}""を""{1}""に展開...
arg, extractDir)
'展開する
Try
If ExtractArchiveEx(arg, extractDir) ...
Console.WriteLine("展開しました。")
'フォルダを開く
System.Diagnostics.Process.Start(...
Else
Console.WriteLine("展開できません...
End If
Catch ex As Exception
Console.WriteLine(("エラー:" + ex.Mes...
End Try
Next arg
Console.ReadLine()
End Sub
'DLLモジュールをマップ
<DllImport("kernel32")> _
Private Shared Function LoadLibrary( _
ByVal lpLibFileName As String) As Integer
End Function
'マップを解除
<DllImport("kernel32")> _
Private Shared Function FreeLibrary( _
ByVal hLibModule As Integer) As Boolean
End Function
'関数のアドレスを取得
<DllImport("kernel32")> _
Private Shared Function GetProcAddress( _
ByVal hModule As Integer, _
ByVal lpProcName As String) As Integer
End Function
'以下使用するAPIのためのInvokeFunc
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeGetVersion( _
ByVal funcptr As Integer) As UInt16
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeGetRunning( _
ByVal funcptr As Integer) As Boolean
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeCheckArchive( _
ByVal funcptr As Integer, _
ByVal szFileName As String, _
ByVal iMode As Integer) As Boolean
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeMain( _
ByVal funcptr As Integer, _
ByVal hwnd As Integer, _
ByVal szCmdLine As String, _
ByVal szOutput As String, _
ByVal dwSize As Integer) As Integer
End Function
'DLLの情報
Public Structure ArchiverDllInfo
Public FileName As String 'DLLファ...
Public FunctionName As String 'APIの頭...
Public CommandToExtract As String '展開のた...
End Structure 'ArchiverDllInfo
'/ <summary>
'/ 統合アーカイバ仕様のDLLで書庫を展開する
'/ </summary>
'/ <param name="archiveFile">書庫ファイル名</param>
'/ <param name="extractDir">展開先のフォルダ名</p...
'/ <returns>展開できたらTrue</returns>
Public Shared Function ExtractArchiveEx( _
ByVal archiveFile As String, _
ByVal extractDir As String) As Boolean
'指定されたファイルがあるか調べる
If Not System.IO.File.Exists(archiveFile) Then
Throw New ApplicationException("ファイル...
End If
'DLL情報ファイルの存在を確認
Dim dllInfoFile As String = GetAppPath() + "\...
If Not System.IO.File.Exists(dllInfoFile) Then
Throw New ApplicationException( _
"DLL情報ファイルが見つかりません")
End If
'DLLの情報を読み込む
Dim serializer As _
New System.Xml.Serialization.XmlSerialize...
GetType(ArchiverDllInfo()))
Dim fs As New System.IO.FileStream(dllInfoFil...
System.IO.FileMode.Open)
Dim dllInfos() As ArchiverDllInfo
dllInfos = CType(serializer.Deserialize(fs), _
ArchiverDllInfo())
If dllInfos Is Nothing Or dllInfos.Length = 0...
Throw New ApplicationException( _
"DLL情報が読み込めませんでした")
End If
Dim di As ArchiverDllInfo
For Each di In dllInfos
Dim dllName As String = di.FileName
Dim funcName As String = di.FunctionName
'DLLをロード
Dim hmod As Integer = LoadLibrary(dllName)
If hmod = 0 Then
GoTo ContinueForEach1
End If
Try
Dim funcaddr As Integer
'DLLのチェック
'関数のアドレスを取得
funcaddr = GetProcAddress(hmod, _
funcName + "GetVersion")
If funcaddr = 0 Then
GoTo ContinueForEach1
End If
Dim ver As UInt16 = InvokeGetVersion(...
'展開できるかチェック
funcaddr = GetProcAddress(hmod, _
funcName + "CheckArchive")
If funcaddr = 0 Then
GoTo ContinueForEach1
End If
If Not InvokeCheckArchive(funcaddr, _
archiveFile, 0) Then
GoTo ContinueForEach1
End If
Console.WriteLine("対応DLLは{0}です",...
'動作中かチェック
funcaddr = GetProcAddress(hmod, _
funcName + "GetRunning")
If funcaddr = 0 Then
GoTo ContinueForEach1
End If
If InvokeGetRunning(funcaddr) Then
Throw New ApplicationException( _
dllName + "が動作中です")
End If
'ファイル名とフォルダ名を修正する
If archiveFile.IndexOf(" "c) > 0 Then
archiveFile = """" + archiveFile ...
End If
If Not extractDir.EndsWith("\") Then
extractDir += "\"
End If
If extractDir.IndexOf(" "c) > 0 Then
extractDir = """" + extractDir + ...
End If
'展開する
funcaddr = GetProcAddress(hmod, funcN...
If funcaddr = 0 Then
Throw New ApplicationException( _
funcName + "のアドレスが取得...
End If
Dim ret As Integer = InvokeMain(funca...
String.Format(di.CommandToExtract...
extractDir), Nothing, 0)
'結果
If ret <> 0 Then
Throw New ApplicationException( _
dllName + "での書庫の展開に失...
Else
Return True
End If
Finally
'開放する
If hmod <> 0 Then
FreeLibrary(hmod)
End If
End Try
ContinueForEach1:
Next di
Return False
End Function
Private Shared Function GetAppPath() As String
Dim fi As New System.IO.FileInfo( _
System.Reflection.Assembly.GetExecutingAs...
Return fi.DirectoryName
End Function
End Class
End Namespace
}}
#code(csharp){{
using System;
using System.Runtime.InteropServices;
namespace Dobon.Sample.File
{
public class ExtractArchiveWithDll
{
public static void Main(string[] args)
{
foreach (string arg in args)
{
//展開先のフォルダ名を決める
//ここではデスクトップ上の書庫ファイル名...
string extractDir =
System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Desk...
extractDir += "\\" +
System.IO.Path.GetFileNameWithoutExte...
//存在しないフォルダ名を探す
if (System.IO.Directory.Exists(extractDir))
{
int n = 0;
while (System.IO.Directory.Exists(ext...
+ (++n).T...
extractDir += n.ToString();
}
Console.WriteLine("\"{0}\"を\"{1}\"に展開...
arg, extractDir);
//展開する
try
{
if (ExtractArchiveEx(arg, extractDir))
{
Console.WriteLine("展開しました。...
//フォルダを開く
System.Diagnostics.Process.Start(...
}
else
Console.WriteLine("展開できません...
}
catch (Exception ex)
{
Console.WriteLine("エラー:" + ex.Mess...
}
}
Console.ReadLine();
}
//DLLモジュールをマップ
[DllImport("kernel32")]
private extern static int LoadLibrary(string lpLi...
//マップを解除
[DllImport("kernel32")]
private extern static bool FreeLibrary(int hLibMo...
//関数のアドレスを取得
[DllImport("kernel32")]
private extern static int GetProcAddress(
int hModule, string lpProcName);
//以下使用するAPIのためのInvokeFunc
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static UInt16 InvokeGetVersion(int...
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static bool InvokeGetRunning(int f...
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static bool InvokeCheckArchive(
int funcptr, string szFileName, int iMode);
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static int InvokeMain(
int funcptr, int hwnd, string szCmdLine,
string szOutput, int dwSize);
//DLLの情報
public struct ArchiverDllInfo
{
public string FileName; //DLLファ...
public string FunctionName; //APIの頭...
public string CommandToExtract; //展開のた...
}
/// <summary>
/// 統合アーカイバ仕様のDLLで書庫を展開する
/// </summary>
/// <param name="archiveFile">書庫ファイル名</par...
/// <param name="extractDir">展開先のフォルダ名</...
/// <returns>展開できたらTrue</returns>
public static bool ExtractArchiveEx(
string archiveFile, string extractDir)
{
//指定されたファイルがあるか調べる
if (!System.IO.File.Exists(archiveFile))
throw new ApplicationException(
"ファイルが見つかりません");
//DLL情報ファイルの存在を確認
string dllInfoFile =
GetAppPath() + "\\dlls.config";
if (!System.IO.File.Exists(dllInfoFile))
throw new ApplicationException(
"DLL情報ファイルが見つかりません");
//DLLの情報を読み込む
System.Xml.Serialization.XmlSerializer serial...
new System.Xml.Serialization.XmlSerializer(
typeof(ArchiverDllInfo[]));
System.IO.FileStream fs =
new System.IO.FileStream(dllInfoFile,
System.IO.FileMode.Open);
ArchiverDllInfo[] dllInfos;
dllInfos = (ArchiverDllInfo[]) serializer.Des...
if (dllInfos == null || dllInfos.Length == 0)
throw new ApplicationException(
"DLL情報が読み込めませんでした");
foreach (ArchiverDllInfo di in dllInfos)
{
string dllName = di.FileName;
string funcName = di.FunctionName;
//DLLをロード
int hmod = LoadLibrary(dllName);
if (hmod == 0)
continue;
try
{
int funcaddr;
//DLLのチェック
//関数のアドレスを取得
funcaddr = GetProcAddress(
hmod, funcName + "GetVersion");
if (funcaddr == 0)
continue;
UInt16 ver = InvokeGetVersion(funcadd...
if (ver == 0)
continue;
//展開できるかチェック
funcaddr = GetProcAddress(
hmod, funcName + "CheckArchive");
if (funcaddr == 0)
continue;
if (!InvokeCheckArchive(funcaddr, arc...
continue;
Console.WriteLine("対応DLLは{0}です",...
//動作中かチェック
funcaddr = GetProcAddress(
hmod, funcName + "GetRunning");
if (funcaddr == 0)
continue;
if (InvokeGetRunning(funcaddr))
throw new ApplicationException(
dllName + "が動作中です");
//ファイル名とフォルダ名を修正する
if (archiveFile.IndexOf(' ') > 0)
archiveFile = "\"" + archiveFile ...
if (!extractDir.EndsWith("\\"))
extractDir += "\\";
if (extractDir.IndexOf(' ') > 0)
extractDir = "\"" + extractDir + ...
//展開する
funcaddr = GetProcAddress(hmod, funcN...
if (funcaddr == 0)
throw new ApplicationException(
funcName + "のアドレスが取得...
int ret = InvokeMain(funcaddr, 0,
string.Format(di.CommandToExtract,
archiveFile, extractDir),
null, 0);
//結果
if (ret != 0)
throw new ApplicationException(
dllName + "での書庫の展開に失...
else
return true;
}
finally
{
//開放する
if (hmod != 0)
FreeLibrary(hmod);
}
}
return false;
}
private static string GetAppPath()
{
System.IO.FileInfo fi =
new System.IO.FileInfo(
System.Reflection.Assembly.GetExecutingAs...
return fi.DirectoryName;
}
}
}
}}
今回は予定外の大作になってしまいましたが、遅延バインディ...
**コメント [#mbf61691]
#comment
//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2003-09-09 (火) 06:00:00,DOB...
終了行:
#title(.NETプログラミング研究 第16号)
#navi(.NETプログラミング研究)
#contents
*.NETプログラミング研究 第16号 [#sd6be91c]
**ピンポイントリンク [#bf313648]
**遅延バインディングによりアンマネージDLL関数を呼び出す [...
#column(注意){{
この記事の最新版は「[[遅延バインディングによりアンマネー...
}}
ここでは.NETで外部のDLLの関数(アンマネージDLL関数)を呼...
-[[統合アーカイバプロジェクト>http://www.madobe.net/archi...
-[[Micco's HomePage>http://www2.nsknet.or.jp/~micco/micin...
***Unlha32.dllを使って書庫を展開する方法 [#s6b5c9fe]
DLL関数の呼び出し方の説明は後にして、まずはUnlha32.dllを...
Unlha32.dllはLHA(.lzh)形式の書庫を操作(圧縮、解凍など)...
Unlha32.dllで書庫を展開するには、通常Unlha関数を使います...
x 書庫名 解凍先フォルダ名 *
などとします。これにオプション等を付加していけば、展開方...
展開に関してはこれだけですが、余計なエラーがないように、...
これで書庫の展開に関するUnlha32.dllの知識は身に付いたもの...
***DllImportによるアンマネージDLL関数の呼び出し [#jd2de5f6]
.NETでアンマネージDLL関数を呼び出す方法としては、DllImpor...
ここではこの方法を紹介することが目的ではないため、DllImpo...
-[[アンマネージ DLL 関数の処理>http://www.microsoft.com/j...
-[[プラットフォーム呼び出しによるデータのマーシャリング>h...
以降、これらの知識がすでにあるものとして話を進めさせてい...
***書庫を展開する [#xfd4bc9f]
以上の知識を基に、いよいよ実際に書庫を展開するコードを書...
#code(vbnet){{
'Imports System.Runtime.InteropServices
'が宣言されているものとする
'DLL の版の取得
<DllImport("unlha32")> _
Private Shared Function UnlhaGetVersion() As UInt16
End Function
'DLL の実行状況の取得
<DllImport("unlha32")> _
Private Shared Function UnlhaGetRunning() As Boolean
End Function
'書庫のチェック
<DllImport("unlha32")> _
Private Shared Function UnlhaCheckArchive( _
ByVal szFileName As String, _
ByVal iMode As Integer) As Boolean
End Function
'書庫操作一般
<DllImport("unlha32")> _
Private Shared Function Unlha( _
ByVal hwnd As Integer, _
ByVal szCmdLine As String, _
ByVal szOutput As String, _
ByVal dwSize As Integer) As Integer
End Function
'/ <summary>
'/ UNLHA32.DLLで書庫を展開する
'/ </summary>
'/ <param name="archiveFile">書庫ファイル名</param>
'/ <param name="extractDir">展開先のフォルダ名</param>
Public Shared Sub LhaExtractArchive( _
ByVal archiveFile As String, _
ByVal extractDir As String)
'指定されたファイルがあるか調べる
If Not System.IO.File.Exists(archiveFile) Then
Throw New ApplicationException("ファイルが見つか...
End If
'DLLのチェック
Try
Dim ver As UInt16 = UnlhaGetVersion()
Console.WriteLine("バージョン:{0}", ver)
Catch
Throw New _
ApplicationException("Unlha32.dllがインストー...
End Try
'動作中かチェック
If UnlhaGetRunning() Then
Throw New ApplicationException("DLLが動作中")
End If
'展開できるかチェック
If Not UnlhaCheckArchive(archiveFile, 0) Then
Throw New ApplicationException("対応書庫ではあり...
End If
'ファイル名とフォルダ名を修正する
If archiveFile.IndexOf(" "c) > 0 Then
archiveFile = """" + archiveFile + """"
End If
If Not extractDir.EndsWith("\") Then
extractDir += "\"
End If
If extractDir.IndexOf(" "c) > 0 Then
extractDir = """" + extractDir + """"
End If
'展開する
Dim ret As Integer = Unlha(0, _
String.Format("x {0} {1} *", archiveFile, extract...
Nothing, 0)
'結果
If ret <> 0 Then
Throw New ApplicationException("書庫の展開に失敗...
End If
End Sub
}}
#code(csharp){{
//using System.Runtime.InteropServices;
//が宣言されているものとする
//DLL の版の取得
[DllImport("unlha32")]
private extern static UInt16 UnlhaGetVersion();
//DLL の実行状況の取得
[DllImport("unlha32")]
private extern static bool UnlhaGetRunning();
//書庫のチェック
[DllImport("unlha32")]
private extern static bool UnlhaCheckArchive(string szFil...
int iMode);
//書庫操作一般
[DllImport("unlha32")]
private extern static int Unlha(int hwnd, string szCmdLin...
string szOutput, int dwSize);
/// <summary>
/// UNLHA32.DLLで書庫を展開する
/// </summary>
/// <param name="archiveFile">書庫ファイル名</param>
/// <param name="extractDir">展開先のフォルダ名</param>
public static void LhaExtractArchive(
string archiveFile, string extractDir)
{
//指定されたファイルがあるか調べる
if (!System.IO.File.Exists(archiveFile))
throw new ApplicationException("ファイルが見つか...
//DLLのチェック
try
{
UInt16 ver = UnlhaGetVersion();
Console.WriteLine("バージョン:{0}", ver);
}
catch
{
throw new ApplicationException("Unlha32.dllがイン...
}
//動作中かチェック
if (UnlhaGetRunning())
throw new ApplicationException("DLLが動作中");
//展開できるかチェック
if (!UnlhaCheckArchive(archiveFile, 0))
throw new ApplicationException("対応書庫ではあり...
//ファイル名とフォルダ名を修正する
if (archiveFile.IndexOf(' ') > 0)
archiveFile = "\"" + archiveFile + "\"";
if (!extractDir.EndsWith("\\"))
extractDir += "\\";
if (extractDir.IndexOf(' ') > 0)
extractDir = "\"" + extractDir + "\"";
//展開する
int ret = Unlha(0,
string.Format("x {0} {1} *", archiveFile, extract...
null, 0);
//結果
if (ret != 0)
throw new ApplicationException("書庫の展開に失敗...
}
}}
うまく行きましたか?普通ならこれで、
「書庫が解凍できました。めでたし、めでたし。」
となって終わるところでしょうが、それでは面白くもなんとも...
***遅延バインディングの意義 [#nbb869e5]
私はこの記事の一番初めに
最終的には「統合アーカイバプロジェクト」に対応したあらゆ...
と書きました。さて、UNLHA32.DLL以外のDLLを使って書庫を展...
例えば"UNZIP32.DLL"(shoda T.さん作)の場合は、先のUNLHA3...
"CAB32.DLL"(宮内邦昭さん作)の場合も同様に、UNLHA32.DLL...
"UNZIP32.DLL"と"CAB32.DLL"の例を示しましたが、実は統合ア...
このような仕様のおかげで、統合アーカイバ仕様のDLLを使用す...
今までの考察からすれば、DLLファイル名と、そのDLLのAPIの頭...
もしDllImportでDLLファイル名と関数の名前(呼び出すDLLエン...
.NETでは無理ですが、実はVC++ではこれは造作ないことです。L...
-[[Visual C++ の概念: 機能の追加 - DLL>http://www.microso...
.NETでも同じことが出来ればよいのですが、果たして可能でし...
***遅延バインディングによる方法 [#r84fcfbf]
その答えが、Richard Birkbyさんが書いた「The Code Project ...
-[[The Code Project - Late binding on native DLLs with C#...
詳しくはこのページを読んでいただきたいのですが、つまりは...
Win32 APIのLoadLibrary関数とGetProcAddress関数により指定...
上記のページからダウンロードできるアーカイバにはソースし...
それでは今度はこの方法で先のコードを書き換えてみましょう...
#code(vbnet){{
'Imports System.Runtime.InteropServices
'が宣言されているものとする
'DLLモジュールをマップ
<DllImport("kernel32")> _
Private Shared Function LoadLibrary( _
ByVal lpLibFileName As String) As Integer
End Function
'マップを解除
<DllImport("kernel32")> _
Private Shared Function FreeLibrary( _
ByVal hLibModule As Integer) As Boolean
End Function
'関数のアドレスを取得
<DllImport("kernel32")> _
Private Shared Function GetProcAddress( _
ByVal hModule As Integer, ByVal lpProcName As String)...
End Function
'以下使用するAPIのためのInvokeFunc
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeGetVersion( _
ByVal funcptr As Integer) As UInt16
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeGetRunning( _
ByVal funcptr As Integer) As Boolean
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeCheckArchive( _
ByVal funcptr As Integer, _
ByVal szFileName As String, _
ByVal iMode As Integer) As Boolean
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeMain( _
ByVal funcptr As Integer, _
ByVal hwnd As Integer, _
ByVal szCmdLine As String, _
ByVal szOutput As String, _
ByVal dwSize As Integer) As Integer
End Function
'/ <summary>
'/ 統合アーカイバ仕様のDLLで書庫を展開する
'/ </summary>
'/ <param name="dllName">DLLファイル名</param>
'/ <param name="funcName">APIの頭に付く文字列</param>
'/ <param name="command">展開のためのコマンド</param>
'/ <param name="archiveFile">書庫ファイル名</param>
'/ <param name="extractDir">展開先のフォルダ名</param>
Public Shared Sub ExtractArchive( _
ByVal dllName As String, _
ByVal funcName As String, _
ByVal command As String, _
ByVal archiveFile As String, _
ByVal extractDir As String)
'指定されたファイルがあるか調べる
If Not System.IO.File.Exists(archiveFile) Then
Throw New ApplicationException("ファイルが見つか...
End If
'DLLをロード
Dim hmod As Integer = LoadLibrary(dllName)
If hmod = 0 Then
Throw New ApplicationException( _
dllName + "のロードに失敗しました")
End If
Try
Dim funcaddr As Integer
'DLLのチェック
'関数のアドレスを取得
funcaddr = GetProcAddress(hmod, funcName + "GetVe...
If funcaddr = 0 Then
Throw New ApplicationException( _
dllName + "がインストールされていません")
End If
Dim ver As UInt16 = InvokeGetVersion(funcaddr)
Console.WriteLine("バージョン:{0}", ver)
'動作中かチェック
funcaddr = GetProcAddress(hmod, funcName + "GetRu...
If funcaddr = 0 Then
Throw New ApplicationException( _
funcName + "GetRunningのアドレスが取得で...
End If
If InvokeGetRunning(funcaddr) Then
Throw New ApplicationException(dllName + "が...
End If
'展開できるかチェック
funcaddr = GetProcAddress(hmod, funcName + "Check...
If funcaddr = 0 Then
Throw New ApplicationException( _
funcName + "CheckArchiveのアドレスが取得...
End If
If Not InvokeCheckArchive(funcaddr, archiveFile, ...
Throw New ApplicationException( _
archiveFile + "は対応書庫ではありません")
End If
'ファイル名とフォルダ名を修正する
If archiveFile.IndexOf(" "c) > 0 Then
archiveFile = """" + archiveFile + """"
End If
If Not extractDir.EndsWith("\") Then
extractDir += "\"
End If
If extractDir.IndexOf(" "c) > 0 Then
extractDir = """" + extractDir + """"
End If
'展開する
funcaddr = GetProcAddress(hmod, funcName)
If funcaddr = 0 Then
Throw New ApplicationException( _
funcName + "のアドレスが取得できませんで...
End If
Dim ret As Integer = InvokeMain(funcaddr, 0, _
String.Format(command, archiveFile, extractDi...
Nothing, 0)
'結果
If ret <> 0 Then
Throw New ApplicationException("書庫の展開に...
End If
Finally
'開放する
If hmod <> 0 Then
FreeLibrary(hmod)
End If
End Try
End Sub
}}
#code(csharp){{
//using System.Runtime.InteropServices;
//が宣言されているものとする
//DLLモジュールをマップ
[DllImport("kernel32")]
private extern static int LoadLibrary(string lpLibFileNam...
//マップを解除
[DllImport("kernel32")]
private extern static bool FreeLibrary(int hLibModule);
//関数のアドレスを取得
[DllImport("kernel32")]
private extern static int GetProcAddress(int hModule,
string lpProcName);
//以下使用するAPIのためのInvokeFunc
[DllImport("Invoke", EntryPoint="InvokeFunc")]
privatelic extern static UInt16 InvokeGetVersion(int func...
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static bool InvokeGetRunning(int funcptr);
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static bool InvokeCheckArchive(int funcptr,
string szFileName, int iMode);
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static int InvokeMain(int funcptr, int hwnd,
string szCmdLine, string szOutput, int dwSize);
/// <summary>
/// 統合アーカイバ仕様のDLLで書庫を展開する
/// </summary>
/// <param name="dllName">DLLファイル名</param>
/// <param name="funcName">APIの頭に付く文字列</param>
/// <param name="command">展開のためのコマンド</param>
/// <param name="archiveFile">書庫ファイル名</param>
/// <param name="extractDir">展開先のフォルダ名</param>
public static void ExtractArchive(string dllName, string ...
string command, string archiveFile, string extractDir)
{
//指定されたファイルがあるか調べる
if (!System.IO.File.Exists(archiveFile))
throw new ApplicationException("ファイルが見つか...
//DLLをロード
int hmod = LoadLibrary(dllName);
if (hmod == 0)
throw new ApplicationException(dllName + "のロー...
try
{
int funcaddr;
//DLLのチェック
//関数のアドレスを取得
funcaddr = GetProcAddress(hmod, funcName + "GetVe...
if (funcaddr == 0)
throw new ApplicationException(
dllName + "がインストールされていません");
UInt16 ver = InvokeGetVersion(funcaddr);
Console.WriteLine("バージョン:{0}", ver);
//動作中かチェック
funcaddr = GetProcAddress(hmod, funcName + "GetRu...
if (funcaddr == 0)
throw new ApplicationException(
funcName + "GetRunningのアドレスが取得で...
if (InvokeGetRunning(funcaddr))
throw new ApplicationException(dllName + "が...
//展開できるかチェック
funcaddr = GetProcAddress(hmod, funcName + "Check...
if (funcaddr == 0)
throw new ApplicationException(
funcName + "CheckArchiveのアドレスが取得...
if (!InvokeCheckArchive(funcaddr, archiveFile, 0))
throw new ApplicationException(
archiveFile + "は対応書庫ではありません");
//ファイル名とフォルダ名を修正する
if (archiveFile.IndexOf(' ') > 0)
archiveFile = "\"" + archiveFile + "\"";
if (!extractDir.EndsWith("\\"))
extractDir += "\\";
if (extractDir.IndexOf(' ') > 0)
extractDir = "\"" + extractDir + "\"";
//展開する
funcaddr = GetProcAddress(hmod, funcName);
if (funcaddr == 0)
throw new ApplicationException(
funcName + "のアドレスが取得できませんで...
int ret = InvokeMain(funcaddr, 0,
string.Format(command, archiveFile, extractDi...
null, 0);
//結果
if (ret != 0)
throw new ApplicationException("書庫の展開に...
}
finally
{
//開放する
if (hmod != 0)
FreeLibrary(hmod);
}
}
}}
これでユーザーがこれらの情報を与えることですべての統合ア...
***ついに完成! [#yc85ef65]
一応の目標は達成したといえますが、せっかくここまで来たの...
書庫の展開に必要なDLLに関する情報はユーザーがXML形式のフ...
ユーザーが与えるXMLファイルは例えば次のように記述するもの...
#code(xml){{
<?xml version="1.0"?>
<ArrayOfArchiverDllInfo xmlns:xsd="http://www.w3.org/2001...
<ArchiverDllInfo>
<FileName>unlha32</FileName>
<FunctionName>Unlha</FunctionName>
<CommandToExtract>x {0} {1} *</CommandToExtract>
</ArchiverDllInfo>
<ArchiverDllInfo>
<FileName>unzip32</FileName>
<FunctionName>UnZip</FunctionName>
<CommandToExtract>-x {0} {1} *</CommandToExtract>
</ArchiverDllInfo>
<ArchiverDllInfo>
<FileName>cab32</FileName>
<FunctionName>Cab</FunctionName>
<CommandToExtract>-x {0} {1} *</CommandToExtract>
</ArchiverDllInfo>
</ArrayOfArchiverDllInfo>
}}
次の例はコンソールアプリです。コマンドライン引数に展開し...
#code(vbnet){{
'C#のコードを'C# to VB.NET Translator'で変換し、修正した...
'http://www.aspalliance.com/aldotnet/examples/translate.a...
Imports System
Imports System.Runtime.InteropServices
Namespace Dobon.Sample.File
Public Class ExtractArchiveWithDll
Public Shared Sub Main(ByVal args() As String)
Dim arg As String
For Each arg In args
'展開先のフォルダ名を決める
'ここではデスクトップ上の書庫ファイル名の...
Dim extractDir As String = _
System.Environment.GetFolderPath( _
System.Environment.SpecialFolder.Desk...
extractDir += "\" + _
System.IO.Path.GetFileNameWithoutExte...
'存在しないフォルダ名を探す
If System.IO.Directory.Exists(extractDir)...
Dim n As Integer = 1
While System.IO.Directory.Exists( _
extractDir + n.ToString())
n += 1
End While
extractDir += n.ToString()
End If
Console.WriteLine("""{0}""を""{1}""に展開...
arg, extractDir)
'展開する
Try
If ExtractArchiveEx(arg, extractDir) ...
Console.WriteLine("展開しました。")
'フォルダを開く
System.Diagnostics.Process.Start(...
Else
Console.WriteLine("展開できません...
End If
Catch ex As Exception
Console.WriteLine(("エラー:" + ex.Mes...
End Try
Next arg
Console.ReadLine()
End Sub
'DLLモジュールをマップ
<DllImport("kernel32")> _
Private Shared Function LoadLibrary( _
ByVal lpLibFileName As String) As Integer
End Function
'マップを解除
<DllImport("kernel32")> _
Private Shared Function FreeLibrary( _
ByVal hLibModule As Integer) As Boolean
End Function
'関数のアドレスを取得
<DllImport("kernel32")> _
Private Shared Function GetProcAddress( _
ByVal hModule As Integer, _
ByVal lpProcName As String) As Integer
End Function
'以下使用するAPIのためのInvokeFunc
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeGetVersion( _
ByVal funcptr As Integer) As UInt16
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeGetRunning( _
ByVal funcptr As Integer) As Boolean
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeCheckArchive( _
ByVal funcptr As Integer, _
ByVal szFileName As String, _
ByVal iMode As Integer) As Boolean
End Function
<DllImport("Invoke", EntryPoint:="InvokeFunc")> _
Private Shared Function InvokeMain( _
ByVal funcptr As Integer, _
ByVal hwnd As Integer, _
ByVal szCmdLine As String, _
ByVal szOutput As String, _
ByVal dwSize As Integer) As Integer
End Function
'DLLの情報
Public Structure ArchiverDllInfo
Public FileName As String 'DLLファ...
Public FunctionName As String 'APIの頭...
Public CommandToExtract As String '展開のた...
End Structure 'ArchiverDllInfo
'/ <summary>
'/ 統合アーカイバ仕様のDLLで書庫を展開する
'/ </summary>
'/ <param name="archiveFile">書庫ファイル名</param>
'/ <param name="extractDir">展開先のフォルダ名</p...
'/ <returns>展開できたらTrue</returns>
Public Shared Function ExtractArchiveEx( _
ByVal archiveFile As String, _
ByVal extractDir As String) As Boolean
'指定されたファイルがあるか調べる
If Not System.IO.File.Exists(archiveFile) Then
Throw New ApplicationException("ファイル...
End If
'DLL情報ファイルの存在を確認
Dim dllInfoFile As String = GetAppPath() + "\...
If Not System.IO.File.Exists(dllInfoFile) Then
Throw New ApplicationException( _
"DLL情報ファイルが見つかりません")
End If
'DLLの情報を読み込む
Dim serializer As _
New System.Xml.Serialization.XmlSerialize...
GetType(ArchiverDllInfo()))
Dim fs As New System.IO.FileStream(dllInfoFil...
System.IO.FileMode.Open)
Dim dllInfos() As ArchiverDllInfo
dllInfos = CType(serializer.Deserialize(fs), _
ArchiverDllInfo())
If dllInfos Is Nothing Or dllInfos.Length = 0...
Throw New ApplicationException( _
"DLL情報が読み込めませんでした")
End If
Dim di As ArchiverDllInfo
For Each di In dllInfos
Dim dllName As String = di.FileName
Dim funcName As String = di.FunctionName
'DLLをロード
Dim hmod As Integer = LoadLibrary(dllName)
If hmod = 0 Then
GoTo ContinueForEach1
End If
Try
Dim funcaddr As Integer
'DLLのチェック
'関数のアドレスを取得
funcaddr = GetProcAddress(hmod, _
funcName + "GetVersion")
If funcaddr = 0 Then
GoTo ContinueForEach1
End If
Dim ver As UInt16 = InvokeGetVersion(...
'展開できるかチェック
funcaddr = GetProcAddress(hmod, _
funcName + "CheckArchive")
If funcaddr = 0 Then
GoTo ContinueForEach1
End If
If Not InvokeCheckArchive(funcaddr, _
archiveFile, 0) Then
GoTo ContinueForEach1
End If
Console.WriteLine("対応DLLは{0}です",...
'動作中かチェック
funcaddr = GetProcAddress(hmod, _
funcName + "GetRunning")
If funcaddr = 0 Then
GoTo ContinueForEach1
End If
If InvokeGetRunning(funcaddr) Then
Throw New ApplicationException( _
dllName + "が動作中です")
End If
'ファイル名とフォルダ名を修正する
If archiveFile.IndexOf(" "c) > 0 Then
archiveFile = """" + archiveFile ...
End If
If Not extractDir.EndsWith("\") Then
extractDir += "\"
End If
If extractDir.IndexOf(" "c) > 0 Then
extractDir = """" + extractDir + ...
End If
'展開する
funcaddr = GetProcAddress(hmod, funcN...
If funcaddr = 0 Then
Throw New ApplicationException( _
funcName + "のアドレスが取得...
End If
Dim ret As Integer = InvokeMain(funca...
String.Format(di.CommandToExtract...
extractDir), Nothing, 0)
'結果
If ret <> 0 Then
Throw New ApplicationException( _
dllName + "での書庫の展開に失...
Else
Return True
End If
Finally
'開放する
If hmod <> 0 Then
FreeLibrary(hmod)
End If
End Try
ContinueForEach1:
Next di
Return False
End Function
Private Shared Function GetAppPath() As String
Dim fi As New System.IO.FileInfo( _
System.Reflection.Assembly.GetExecutingAs...
Return fi.DirectoryName
End Function
End Class
End Namespace
}}
#code(csharp){{
using System;
using System.Runtime.InteropServices;
namespace Dobon.Sample.File
{
public class ExtractArchiveWithDll
{
public static void Main(string[] args)
{
foreach (string arg in args)
{
//展開先のフォルダ名を決める
//ここではデスクトップ上の書庫ファイル名...
string extractDir =
System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Desk...
extractDir += "\\" +
System.IO.Path.GetFileNameWithoutExte...
//存在しないフォルダ名を探す
if (System.IO.Directory.Exists(extractDir))
{
int n = 0;
while (System.IO.Directory.Exists(ext...
+ (++n).T...
extractDir += n.ToString();
}
Console.WriteLine("\"{0}\"を\"{1}\"に展開...
arg, extractDir);
//展開する
try
{
if (ExtractArchiveEx(arg, extractDir))
{
Console.WriteLine("展開しました。...
//フォルダを開く
System.Diagnostics.Process.Start(...
}
else
Console.WriteLine("展開できません...
}
catch (Exception ex)
{
Console.WriteLine("エラー:" + ex.Mess...
}
}
Console.ReadLine();
}
//DLLモジュールをマップ
[DllImport("kernel32")]
private extern static int LoadLibrary(string lpLi...
//マップを解除
[DllImport("kernel32")]
private extern static bool FreeLibrary(int hLibMo...
//関数のアドレスを取得
[DllImport("kernel32")]
private extern static int GetProcAddress(
int hModule, string lpProcName);
//以下使用するAPIのためのInvokeFunc
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static UInt16 InvokeGetVersion(int...
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static bool InvokeGetRunning(int f...
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static bool InvokeCheckArchive(
int funcptr, string szFileName, int iMode);
[DllImport("Invoke", EntryPoint="InvokeFunc")]
private extern static int InvokeMain(
int funcptr, int hwnd, string szCmdLine,
string szOutput, int dwSize);
//DLLの情報
public struct ArchiverDllInfo
{
public string FileName; //DLLファ...
public string FunctionName; //APIの頭...
public string CommandToExtract; //展開のた...
}
/// <summary>
/// 統合アーカイバ仕様のDLLで書庫を展開する
/// </summary>
/// <param name="archiveFile">書庫ファイル名</par...
/// <param name="extractDir">展開先のフォルダ名</...
/// <returns>展開できたらTrue</returns>
public static bool ExtractArchiveEx(
string archiveFile, string extractDir)
{
//指定されたファイルがあるか調べる
if (!System.IO.File.Exists(archiveFile))
throw new ApplicationException(
"ファイルが見つかりません");
//DLL情報ファイルの存在を確認
string dllInfoFile =
GetAppPath() + "\\dlls.config";
if (!System.IO.File.Exists(dllInfoFile))
throw new ApplicationException(
"DLL情報ファイルが見つかりません");
//DLLの情報を読み込む
System.Xml.Serialization.XmlSerializer serial...
new System.Xml.Serialization.XmlSerializer(
typeof(ArchiverDllInfo[]));
System.IO.FileStream fs =
new System.IO.FileStream(dllInfoFile,
System.IO.FileMode.Open);
ArchiverDllInfo[] dllInfos;
dllInfos = (ArchiverDllInfo[]) serializer.Des...
if (dllInfos == null || dllInfos.Length == 0)
throw new ApplicationException(
"DLL情報が読み込めませんでした");
foreach (ArchiverDllInfo di in dllInfos)
{
string dllName = di.FileName;
string funcName = di.FunctionName;
//DLLをロード
int hmod = LoadLibrary(dllName);
if (hmod == 0)
continue;
try
{
int funcaddr;
//DLLのチェック
//関数のアドレスを取得
funcaddr = GetProcAddress(
hmod, funcName + "GetVersion");
if (funcaddr == 0)
continue;
UInt16 ver = InvokeGetVersion(funcadd...
if (ver == 0)
continue;
//展開できるかチェック
funcaddr = GetProcAddress(
hmod, funcName + "CheckArchive");
if (funcaddr == 0)
continue;
if (!InvokeCheckArchive(funcaddr, arc...
continue;
Console.WriteLine("対応DLLは{0}です",...
//動作中かチェック
funcaddr = GetProcAddress(
hmod, funcName + "GetRunning");
if (funcaddr == 0)
continue;
if (InvokeGetRunning(funcaddr))
throw new ApplicationException(
dllName + "が動作中です");
//ファイル名とフォルダ名を修正する
if (archiveFile.IndexOf(' ') > 0)
archiveFile = "\"" + archiveFile ...
if (!extractDir.EndsWith("\\"))
extractDir += "\\";
if (extractDir.IndexOf(' ') > 0)
extractDir = "\"" + extractDir + ...
//展開する
funcaddr = GetProcAddress(hmod, funcN...
if (funcaddr == 0)
throw new ApplicationException(
funcName + "のアドレスが取得...
int ret = InvokeMain(funcaddr, 0,
string.Format(di.CommandToExtract,
archiveFile, extractDir),
null, 0);
//結果
if (ret != 0)
throw new ApplicationException(
dllName + "での書庫の展開に失...
else
return true;
}
finally
{
//開放する
if (hmod != 0)
FreeLibrary(hmod);
}
}
return false;
}
private static string GetAppPath()
{
System.IO.FileInfo fi =
new System.IO.FileInfo(
System.Reflection.Assembly.GetExecutingAs...
return fi.DirectoryName;
}
}
}
}}
今回は予定外の大作になってしまいましたが、遅延バインディ...
**コメント [#mbf61691]
#comment
//これより下は編集しないでください
#pageinfo([[:Category/.NET]],2003-09-09 (火) 06:00:00,DOB...
ページ名:
▲
▼
[
トップ
] [
新規
|
子ページ作成
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]