2 using System.Runtime.InteropServices;
\r
5 namespace NaGet.InteropServices
\r
8 /// CommonArchiverDllの設定
\r
10 public struct CommonArchiverDllConfig
\r
12 public CommonArchiverDllConfig(string dllName, string cmdName, string cmdLineFmt, int versionreq)
\r
16 CmdLineFmt = cmdLineFmt;
\r
17 VersionMoreThan = versionreq;
\r
21 /// DLLの名称。LoadLibraryに渡される
\r
23 public string DllName;
\r
27 public string CmdName;
\r
29 /// コマンドライン形式"{0}"がアーカイブ名、"{1}"が展開先
\r
31 public string CmdLineFmt;
\r
35 public int VersionMoreThan;
\r
39 /// アーカイバDLLを使った書庫展開のエラー
\r
41 public class CommonArchiverDllExtractionException : ApplicationException
\r
46 private string dllName;
\r
51 private int returnValue;
\r
54 /// アーカイバDLLを使った書庫展開のエラー
\r
56 /// <param name="message">メッセージ</param>
\r
57 /// <param name="dllName">対象DLL名</param>
\r
58 /// <param name="returnValue">戻り値</param>
\r
59 public CommonArchiverDllExtractionException(string message, string dllName, int returnValue)
\r
62 this.dllName = dllName;
\r
63 this.returnValue = returnValue;
\r
69 public string DllName {
\r
70 get { return dllName; }
\r
76 public int ReturnValue {
\r
77 get { return returnValue; }
\r
82 /// アーカイバDLLを使った書庫展開器
\r
84 public class CommonArchiverExtracter
\r
87 #region DLL関数のdelegate
\r
92 private delegate ushort ArcGetVersion();
\r
97 private delegate bool ArcGetRunning();
\r
102 private delegate bool ArcCheckArchive(string szFileName, ArchCheckFlag iMode);
\r
107 private enum ArchCheckFlag {
\r
109 /// 簡易モード。先頭の数個のヘッダのみ確認
\r
113 /// 通常モード。すべてのヘッダを確認
\r
117 /// 厳密モード。CRCも含めすべて確認
\r
128 private delegate int ArcGetFileCount(string szFileName);
\r
133 private delegate int ArcMain(IntPtr hWnd,
\r
134 [MarshalAs(UnmanagedType.LPStr)] string szCmdLine,
\r
135 [MarshalAs(UnmanagedType.LPStr)] System.Text.StringBuilder szOutput, uint dwSize);
\r
142 public static readonly CommonArchiverDllConfig[] Configs = {
\r
143 new CommonArchiverDllConfig("7-ZIP32", "SevenZip", "x -y \"{0}\" \"-o{1}\"", 423),
\r
144 new CommonArchiverDllConfig("UNZIP32", "UnZip", "-x -o \"{0}\" \"{1}\" *", 541),
\r
145 new CommonArchiverDllConfig("UNLHA32", "Unlha", "x \"{0}\" \"{1}\" *", 240),
\r
146 new CommonArchiverDllConfig("CAB32", "Cab", "-x \"{0}\" \"{1}\" *", 98),
\r
147 new CommonArchiverDllConfig("TAR32", "Tar", "-x \"{0}\" -o \"{1}\"", 218),
\r
148 new CommonArchiverDllConfig("UNGCA32", "UnGCA", "e \"{0}\" \"{1}\"", 10), // いるかな?
\r
150 //new CommonArchiverDllConfig("UNRAR32", "Unrar", "x -y \"{0}\" \"{1}\" *", -1),
\r
154 /// アーカイブを展開する。適切なDLLで自動的に展開する。
\r
156 /// <param name="arcFile">アーカイブのパス</param>
\r
157 /// <param name="targetDir">展開先ディレクトリ</param>
\r
158 /// <param name="output">アーカイバDLLの展開時の標準出力を格納する</param>
\r
159 /// <param name="hWnd">親フレーム</param>
\r
160 /// <returns>アーカイバDLLが見つかって正しく処理できたらtrue、DLLが見つからなかったらfalse</returns>
\r
161 public static bool ExtractArchive(string arcFile, string targetDir, System.Text.StringBuilder output, IntPtr hWnd)
\r
165 foreach (CommonArchiverDllConfig config in Configs) {
\r
167 ret = ExtractArchiveWith(arcFile, targetDir, config, output, hWnd);
\r
171 } catch (CommonArchiverDllExtractionException) {
\r
173 } catch (DllNotFoundException) {
\r
174 } catch (ApplicationException) {
\r
182 /// 指定したDLLの設定を使ってアーカイブを展開する
\r
184 /// <param name="arcFile">アーカイブのパス</param>
\r
185 /// <param name="targetDir">展開先ディレクトリ</param>
\r
186 /// <param name="config">使用するアーカイバDLLの設定</param>
\r
187 /// <param name="output">アーカイバDLLの展開時の標準出力を格納する</param>
\r
188 /// <param name="hWnd">親フレーム</param>
\r
189 /// <returns>アーカイバDLLの展開時のエラーコード(0なら正常終了)</returns>
\r
190 public static bool ExtractArchiveWith(string arcFile, string targetDir, CommonArchiverDllConfig config, System.Text.StringBuilder output, IntPtr hWnd)
\r
192 if (! File.Exists(arcFile) ) {
\r
193 throw new FileNotFoundException(string.Format("File not found: {0}", arcFile), arcFile);
\r
195 if (! Directory.Exists(targetDir)) {
\r
196 throw new DirectoryNotFoundException("Directory not found: " + targetDir);
\r
199 // 統合アーカイバDLLの解凍先ディレクトリは\で終わらないといけない(重要)
\r
200 if (! targetDir.EndsWith("\\")) {
\r
205 using (DllAccess dll = new DllAccess(config.DllName)) {
\r
206 ArcGetVersion GetVersion = (ArcGetVersion) dll.GetFunction(config.CmdName+"GetVersion", typeof(ArcGetVersion));
\r
207 ushort version = GetVersion();
\r
208 if (version < config.VersionMoreThan) {
\r
209 throw new DllNotFoundException("Dll version is too old.");
\r
213 string cmdLine = string.Format(config.CmdLineFmt, arcFile, targetDir);
\r
214 int retVal = ExtractArchiveWith(config.DllName, config.CmdName, cmdLine, arcFile, output, hWnd);
\r
216 string errorMsg = string.Format("Extraction failure: {0}#{1}() returns {2}.", config.DllName, config.CmdName, retVal);
\r
217 throw new CommonArchiverDllExtractionException(errorMsg, config.DllName, retVal);
\r
223 protected static int ExtractArchiveWith(string dllName, string cmdName, string cmdLine, string arcFile, System.Text.StringBuilder output, IntPtr hWnd)
\r
225 using (DllAccess dll = new DllAccess(dllName)) {
\r
226 ArcGetRunning GetRunning = (ArcGetRunning) dll.GetFunction(cmdName+"GetRunning", typeof(ArcGetRunning));
\r
227 if ( GetRunning() ) { // マルチスレッド対応でないのでビジー時には例外
\r
228 throw new SystemException(dllName + " is busy");
\r
231 ArcCheckArchive CheckArchive = (ArcCheckArchive) dll.GetFunction(cmdName+"CheckArchive", typeof(ArcCheckArchive));
\r
232 if (! CheckArchive(arcFile, ArchCheckFlag.BASIC)) {
\r
233 throw new ApplicationException(dllName + " could not treat the archive file");
\r
236 ArcMain Exec = (ArcMain) dll.GetFunction(cmdName, typeof(ArcMain));
\r
237 int retVal = Exec(hWnd, cmdLine, output, (uint)((output != null)? output.Capacity : 0) );
\r