2012年11月10日土曜日

TZipFile.ZipDirectoryContentsのCOMラッパー

仕事で、VB6でフォルダーを圧縮する必要が出てきて、どうしようかと迷ってた時
DEKOさんが以前フォルダごと圧縮してZipファイルを作成するデモを紹介してたのを
思い出したのでCOM化してVB6,VBAから呼び出せるようにしてみた。

以下、ソース


  1. unit DirZipImp;  
  2.   
  3. {$WARN SYMBOL_PLATFORM OFF}  
  4.   
  5. interface  
  6.   
  7. uses  
  8.   ComObj, ActiveX, SimpleDirZip_TLB, StdVcl;  
  9.   
  10. type  
  11.   TDirZip = class(TAutoObject, IDirZip)  
  12.   protected  
  13.     procedure Compress(const SrcDirName, ZipFileName: WideString); safecall;  
  14.     procedure Extract(const ZipFileName, DestDirName: WideString); safecall;  
  15.   
  16.   end;  
  17.   
  18. implementation  
  19.   
  20. uses ComServ,System.Zip;  
  21.   
  22. procedure TDirZip.Compress(const SrcDirName, ZipFileName: WideString);  
  23. begin  
  24.   TZipFile.ZipDirectoryContents(ZipFileName,SrcDirName);  
  25. end;  
  26.   
  27. procedure TDirZip.Extract(const ZipFileName, DestDirName: WideString);  
  28. begin  
  29.   TZipFile.ExtractZipFile(ZipFileName,DestDirName);  
  30. end;  
  31.   
  32. initialization  
  33.   TAutoObjectFactory.Create(ComServer, TDirZip, Class_DirZip,  
  34.     ciMultiInstance, tmApartment);  
  35. end.  


Delphiが作成したタイプライブラリーは
  1. // ************************************************************************ //  
  2. // 警告  
  3. // -------  
  4. // このファイルはタイプ ライブラリ インポータまたはタイプ ライブラリ エディタで生成されています。  
  5. // 構文エラーがない場合には、エディタはファイルへの変更を構文解析します。  
  6. // ただし、エディタで変更したときは、このファイルは再生成され、  
  7. // コメントやフォーマットの変更は失われます。  
  8. // ************************************************************************ //  
  9. // 2012/11/10 20:48:27 に生成されたファイル (- $Rev: 12980 $, 52614628)  
  10.   
  11. [  
  12.   uuid(A77B985B-35E5-49A6-91CB-5BCD38D54C22),  
  13.   version(1.0)  
  14.   
  15. ]  
  16. library SimpleDirZip  
  17. { 
  18.  
  19.   importlib("stdole2.tlb"); 
  20.  
  21.   interface IDirZip; 
  22.   coclass DirZip; 
  23.  
  24.  
  25.   [ 
  26.     uuid(2CCEF7D7-0EF5-467E-BFEC-F4574049C00D), 
  27.     helpstring("DirZip Object のディスパッチ インターフェイス"), 
  28.     dual, 
  29.     oleautomation 
  30.   ] 
  31.   interface IDirZip: IDispatch 
  32.   { 
  33.     [id(0x000000C9)] 
  34.     HRESULT _stdcall Compress([in] BSTR SrcDirName, [in] BSTR ZipFileName); 
  35.     [id(0x000000CA)] 
  36.     HRESULT _stdcall Extract([in] BSTR ZipFileName, [in] BSTR DestDirName); 
  37.   };  
  38.   
  39.   [  
  40.     uuid(2B59D5EC-076B-4577-8C09-F3968AEFF615),  
  41.     helpstring("DirZip Object")  
  42.   ]  
  43.   coclass DirZip  
  44.   { 
  45.     [default] interface IDirZip; 
  46.   };  
  47.   
  48. };  
  49.   
  50. unit SimpleDirZip_TLB;  
  51.   
  52. // ************************************************************************ //  
  53. // 警告  
  54. // -------  
  55. // このファイルで宣言されている型はタイプ ライブラリから読み取られたデータから  
  56. // 生成されています。このタイプ ライブラリが明示的あるいは(このタイプ ライブラ  
  57. // リを参照しているほかのタイプ ライブラリ経由で)間接的に再インポートされた  
  58. // り、タイプ ライブライブラリの編集中にタイプ ライブラリ エディタの[更新]コマ  
  59. // ンドを実行した場合、このファイルの内容はすべて再生成され、手動で加えた変更  
  60. // はすべて失われます。  
  61. // ************************************************************************ //  
  62.   
  63. // $Rev: 52393 $  
  64. // 下に説明されたタイプ ライブラリから 2012/11/10 20:48:24 に生成されたファイル。  
  65.   
  66. // ************************************************************************  //  
  67. // タイプ ライブラリ: C:\Users\saka_xps\Documents\Saka_Develop\DelProj\SimpleDirZip (1)  
  68. // LIBID: {A77B985B-35E5-49A6-91CB-5BCD38D54C22}  
  69. // LCID: 0  
  70. // ヘルプファイル:  
  71. // ヘルプ文字列:  
  72. // 依存関係リスト:  
  73. //   (1) v2.0 stdole, (C:\Windows\SysWOW64\stdole2.tlb)  
  74. // SYS_KIND: SYS_WIN32  
  75. // ************************************************************************ //  
  76. {$TYPEDADDRESS OFF} // ポインタの型チェックをオフにしてコンパイルすること  
  77. {$WARN SYMBOL_PLATFORM OFF}  
  78. {$WRITEABLECONST ON}  
  79. {$VARPROPSETTER ON}  
  80. {$ALIGN 4}  
  81.   
  82. interface  
  83.   
  84. uses Winapi.Windows, System.Classes, System.Variants, System.Win.StdVCL, Vcl.Graphics, Vcl.OleServer, Winapi.ActiveX;  
  85.   
  86. // *********************************************************************//  
  87. // タイプ ライブラリで宣言される GUID. 以下のプレフィックスを使う:  
  88. //   Type Libraries     : LIBID_xxxx  
  89. //   CoClasses          : CLASS_xxxx  
  90. //   DISPInterfaces     : DIID_xxxx  
  91. //   Non-DISP interfaces: IID_xxxx  
  92. // *********************************************************************//  
  93. const  
  94.   // タイプ ライブラリのメジャー バージョンとマイナー バージョン  
  95.   SimpleDirZipMajorVersion = 1;  
  96.   SimpleDirZipMinorVersion = 0;  
  97.   
  98.   LIBID_SimpleDirZip: TGUID = '{A77B985B-35E5-49A6-91CB-5BCD38D54C22}';  
  99.   
  100.   IID_IDirZip: TGUID = '{2CCEF7D7-0EF5-467E-BFEC-F4574049C00D}';  
  101.   CLASS_DirZip: TGUID = '{2B59D5EC-076B-4577-8C09-F3968AEFF615}';  
  102. type  
  103. // *********************************************************************//  
  104. // タイプ ライブラリで宣言される前方参照  
  105. // *********************************************************************//  
  106.   IDirZip = interface;  
  107.   IDirZipDisp = dispinterface;  
  108. // *********************************************************************//  
  109. // タイプ ライブラリで宣言される CoClass  
  110. // (注意: ここで各 CoClass とデフォルトのインターフェイスをマッピングする)  
  111. // *********************************************************************//  
  112.   DirZip = IDirZip;  
  113.   
  114.   
  115. // *********************************************************************//  
  116. // インターフェイス: IDirZip  
  117. // フラグ: (4416) Dual OleAutomation Dispatchable  
  118. // GUID: {2CCEF7D7-0EF5-467E-BFEC-F4574049C00D}  
  119. // *********************************************************************//  
  120.   IDirZip = interface(IDispatch)  
  121.     ['{2CCEF7D7-0EF5-467E-BFEC-F4574049C00D}']  
  122.     procedure Compress(const SrcDirName: WideString; const ZipFileName: WideString); safecall;  
  123.     procedure Extract(const ZipFileName: WideString; const DestDirName: WideString); safecall;  
  124.   end;  
  125.   
  126. // *********************************************************************//  
  127. // DispIntf:  IDirZipDisp  
  128. // フラグ:     (4416) Dual OleAutomation Dispatchable  
  129. // GUID:      {2CCEF7D7-0EF5-467E-BFEC-F4574049C00D}  
  130. // *********************************************************************//  
  131.   IDirZipDisp = dispinterface  
  132.     ['{2CCEF7D7-0EF5-467E-BFEC-F4574049C00D}']  
  133.     procedure Compress(const SrcDirName: WideString; const ZipFileName: WideString); dispid 201;  
  134.     procedure Extract(const ZipFileName: WideString; const DestDirName: WideString); dispid 202;  
  135.   end;  
  136.   
  137. // *********************************************************************//  
  138. // クラス DirZip は、Create および CreateRemote メソッドを使用して  
  139. // CoClass DirZip が公開するデフォルトのインターフェイス IDirZip の  
  140. // インスタンスを作成する。このタイプ ライブラリのサーバーによって  
  141. // 公開された CoClass オブジェクトに対し、オートメーションを行いたい  
  142. // クライアントが用いるために、これらの関数が存在する。  
  143. // *********************************************************************//  
  144.   CoDirZip = class  
  145.     class function Create: IDirZip;  
  146.     class function CreateRemote(const MachineName: string): IDirZip;  
  147.   end;  
  148.   
  149. implementation  
  150.   
  151. uses System.Win.ComObj;  
  152.   
  153. class function CoDirZip.Create: IDirZip;  
  154. begin  
  155.   Result := CreateComObject(CLASS_DirZip) as IDirZip;  
  156. end;  
  157.   
  158. class function CoDirZip.CreateRemote(const MachineName: string): IDirZip;  
  159. begin  
  160.   Result := CreateRemoteComObject(MachineName, CLASS_DirZip) as IDirZip;  
  161. end;  
  162.   
  163. end.  
VB6,VBAの呼び出しのサンプルは、


  1. Private Sub CommandButton1_Click()  
  2.     Dim DirZip As SimpleDirZip.DirZip  
  3.       
  4.     Set DirZip = New SimpleDirZip.DirZip  
  5.       
  6.     Call DirZip.Compress("C:\Users\ppp""C:\Users\pp\ppp.zip")      
  7.     Set DirZip = Nothing  
  8.       
  9. End Sub  
  10.   
  11. Private Sub CommandButton2_Click()  
  12.       
  13.     Dim DirZip As SimpleDirZip.DirZip  
  14.       
  15.     Set DirZip = New SimpleDirZip.DirZip  
  16.       
  17.     Call DirZip.Extract("C:\Users\pp\ppp.zip""C:\Users\pp\p")  
  18.       
  19.     Set DirZip = Nothing  
  20.   
  21. End Sub  
C#とかでComを作るより簡単かも。

ところで、タイプライブラリでインターフェイスのメソッド名を編集時にメソッド名が全部消せないのは
仕様なんかしら・・・。
とりあえず2007では消せたんだけど・・・・。

AnsiExtractQotedStr

QuotedStr関数の存在は、知ってたけど、AnsiExtrctQuotedStrの存在は知らなかった。(^^ゞ
ってことで、使ってみた。
以下ソース


  1. program Project1;  
  2.   
  3. {$APPTYPE CONSOLE}  
  4.   
  5. {$R *.res}  
  6.   
  7. uses  
  8.   System.SysUtils;  
  9.   
  10. var  
  11.   s :String;  
  12.   src : PWideChar;  
  13. begin  
  14.   try  
  15.     { TODO -oUser -cConsole メイン : ここにコードを記述してください }  
  16.     s := 'ミリアリア';  
  17.     Writeln(s);  
  18.     s := QuotedStr(s);  
  19.     Writeln(s);  
  20.     src := PwideChar(s);  
  21.     s := AnsiExtractQuotedStr(src,'''');  
  22.     Writeln(s);  
  23.   
  24.     readln;  
  25.   
  26.   except  
  27.     on E: Exception do  
  28.       Writeln(E.ClassName, ': ', E.Message);  
  29.   end;  
  30. end.  


AnsiExtractQuitedStr内のsrcのとこで、直接キャストしようとすると コンパイルエラーが出るので、一度変数受けでキャスト。
で実行結果は、


2012年11月8日木曜日

指定したフォルダの特定のファイルをSJISからUTF8に変更する

今の仕事で使用した、SJIS→UTF8のチャラツール。
ファイル数がすくなければ、手作業でするけど、ファイル数が多いのファイルが
サブディレクトリにわたるので、作ってみた。
諸般の事情により、Delphi2007で作ったので、UTF8への変換にはjclUnicodeの
TWideStringList、ファイルの走査にはJclFileUtilsのTJclFileEnumeratorを利用した。
(変換元ファイルのディレクトリ、変換先のディレクトリの指定にJvclの TJvDirectoryEdit
を使用した。)

以下ソースコード。


  1. unit Unit1;  
  2.   
  3. interface  
  4.   
  5. uses  
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
  7.   Dialogs,JclStrings, JclFileUtils, StdCtrls, Mask, JvExMask, JvToolEdit,jclUnicode;  
  8.   
  9. type  
  10.   TForm1 = class(TForm)  
  11.     Label1: TLabel;  
  12.     Label2: TLabel;  
  13.     JvDirectoryEdit1: TJvDirectoryEdit;  
  14.     JvDirectoryEdit2: TJvDirectoryEdit;  
  15.     Button1: TButton;  
  16.     Memo1: TMemo;  
  17.     Button2: TButton;  
  18.     procedure Button1Click(Sender: TObject);  
  19.     procedure FormCreate(Sender: TObject);  
  20.     procedure FormClose(Sender: TObject; var Action: TCloseAction);  
  21.     procedure Button2Click(Sender: TObject);  
  22.   private  
  23.     { Private declarations }  
  24.     FFileEnumerator: TJclFileEnumerator;  
  25.     FDirCount: Integer;  
  26.     FTaskID: TFileSearchTaskID;  
  27.     FT0: TDateTime;  
  28.     procedure DirectoryEntered(const Directory: string);  
  29.     procedure AddFile(const Directory: stringconst FileInfo: TSearchRec);  
  30.     procedure TaskDone(const ID: TFileSearchTaskID; const Aborted: Boolean);  
  31.   public  
  32.     { Public declarations }  
  33.   end;  
  34.   
  35. var  
  36.   Form1: TForm1;  
  37.   
  38. implementation  
  39. uses Types,StrUtils, VBLikeString;  
  40. {$R *.dfm}  
  41.   
  42. { TForm1 }  
  43.   
  44. procedure TForm1.AddFile(const Directory: stringconst FileInfo: TSearchRec);  
  45. var  
  46.   SourceFileName,TargetFileName : String;  
  47.   TargetDir : String;  
  48.   SourceText : TStringList;  
  49.   TargetText : TWideStringList;  
  50.   LineCount : Integer;  
  51.   WorkStrings : TStringDynArray;  
  52.   //RevArray : Array of String;  
  53.   RevisionString : String;  
  54.   IsHeaderArea : Boolean;  
  55. begin  
  56.   SourceFileName := Directory + FileInfo.Name;  
  57.   
  58.   //変換後ファイルの書き込み先フォルダは、元ファイルのフルパスの変換元フォルダに指定した  
  59.   //文字列を変換後に指定したフォルダに置換すれば良い  
  60.   TargetFileName := ReplaceText(SourceFileName,JvDirectoryEdit1.Text,JvDirectoryEdit2.Text);  
  61.   TargetDir := ExtractFileDir(TargetFileName);  
  62.   
  63.   //ディレクトリがなければ作成する  
  64.   if not(DirectoryExists(TargetDir)) then ForceDirectories(TargetDir);  
  65.   
  66.   SourceText := TStringList.Create;  
  67.   try  
  68.     SourceText.LoadFromFile(SourceFileName);  
  69.     TargetText := TWideStringList.Create;  
  70.     try  
  71.       //TargetText.Text := ReplaceStr(SourceText.Text,'@CRLF',sLineBreak);  
  72.       TargetText.Text := SourceText.Text;  
  73.       TargetText.SaveUnicode := true;  
  74.       TargetText.SaveFormat := sfUTF8;  
  75.       TargetText.SaveToFile(TargetFileName);  
  76.     finally  
  77.       TargetText.Free;  
  78.     end;  
  79.   finally  
  80.     SourceText.Free;  
  81.   end;  
  82.   Memo1.Lines.Add(SourceFileName);  
  83. end;  
  84.   
  85. procedure TForm1.Button1Click(Sender: TObject);  
  86. var  
  87.   RootDirectories: TStrings;  
  88. begin  
  89.   
  90.   FFileEnumerator.SearchOption[fsLastChangeAfter] := false;  
  91.   FFileEnumerator.SearchOption[fsLastChangeBefore] := false;  
  92.   
  93.   RootDirectories := TStringList.Create;  
  94.   try  
  95.     StrToStrings(JvDirectoryEdit1.Text, DirSeparator, RootDirectories, False);  
  96.     FFileEnumerator.RootDirectories := RootDirectories;  
  97.   finally  
  98.     RootDirectories.Free;  
  99.   end;  
  100.   FFileEnumerator.FileMask := '*.c;*.h';  
  101.   FFileEnumerator.SearchOption[fsMinSize] := false;  
  102.   FFileEnumerator.SearchOption[fsMaxSize] := false;  
  103.   FFileEnumerator.IncludeSubDirectories := true;  
  104.   FFileEnumerator.IncludeHiddenSubDirectories := true;  
  105.   FFileEnumerator.CaseSensitiveSearch := false;  
  106.   FDirCount := 0;  
  107.   
  108.   FT0 := Now;  
  109.   FTaskID := FFileEnumerator.ForEach(AddFile);  
  110.   
  111. end;  
  112.   
  113. procedure TForm1.Button2Click(Sender: TObject);  
  114. begin  
  115.   FFileEnumerator.StopTask(FTaskID);  
  116. end;  
  117.   
  118. procedure TForm1.DirectoryEntered(const Directory: string);  
  119. begin  
  120.   Inc(FDirCount);  
  121. end;  
  122.   
  123. procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);  
  124. begin  
  125.   FFileEnumerator.Free;  
  126. end;  
  127.   
  128. procedure TForm1.FormCreate(Sender: TObject);  
  129. begin  
  130.   FFileEnumerator := TJclFileEnumerator.Create;  
  131.   FFileEnumerator.OnEnterDirectory := DirectoryEntered;  
  132.   FFileEnumerator.OnTerminateTask := TaskDone;  
  133.   
  134. end;  
  135.   
  136. procedure TForm1.TaskDone(const ID: TFileSearchTaskID; const Aborted: Boolean);  
  137. begin  
  138.   //  
  139. end;  
  140.   
  141. end.  

TJclFileEnumeratorは、ファイル検索の条件を設定したうえで、検索条件に該当するファイルが
見つかった場合に呼び出すメソッドを指定してForEcahメソッドを実行すれば、都度、指定した
メソッドを呼び出してくれるので、ForEachに指定しメソッドにSJIS→UTF8の変換処理を
書けばよい。(ソース上ではAddFile)

TStringListを使ってファイルを読み込み、そのテキストをTWideStringListに
渡して、 をTWideStringListでUTF-8を指定して保存することにより、UTF-8変換を
実施した。(このへんは、Delphi 2009以降ならもっとスマートにできる思う。)