C++/CLI with 統合アーカイブ


C++/CLI 電波襲来
C++/CLI 戦線異状なし?
C++/CLI with 統合アーカイブ
スクリプト言語まとん・ブログ
スクリプト言語「まとん」まとめ

Back
Home
 何か、一部で C++/CLI から Win32 API がシームレスに呼び出せないと誤解している方がおられるようなので、サンプルを作ってみました。

 統合アーカイブ・プロジェクトの規定する API を利用して、アセンブリとして C++/CLI で作ったアーカイバ操作クラスを公開できるようラッパーを作ってみました。

 Noah のソースを参照に、このサンプルは作成されています。


 詳細は上のプロジェクトを落として見てみてください。
 それほど複雑な構成はしていません。名前とDLL名をファクトリに渡すと、アーカイバ・クラスが帰ってくるので、それに対してアーカイブ・ファイルを指定することで、DataTable 型でアーカイブ・ファイル中のファイル名のリストを返します。

using namespace System;
using namespace System::Data;
using namespace StdBlue::Archive;

int _tmain()
{
    Archiver^ arch = ArchFactory::CreateArchive(L"Unlha", L"UNLHA32.DLL");
    if ( arch == nullptr ) {
        Console::WriteLine(L"UNLHA32.dll がロードできませんでした。");
        return 1;
    }

    DataTable^ files = arch->GetList(L"CommonArchiverSample.lzh");
    if ( files != nullptr ) {
        Console::WriteLine(L"データ・テーブルは使えますよ〜。");
    }

    return 0;
}
 ここで使用されているのは、Win32 API のうち、LoadLibrary, FreeLibrary, GetProcAddress, GetDesktopWindow, WideCharToMultiByte です。これらの API は比較的使用頻度が高いので、参考になるかと思われます。
 また、このアーカイバはStdBlueArchive.dllというアセンブリになっています。そのため、C# や VB.net から利用することも可能です。
サンプル C#
using System;
using System.Data;
using StdBlue.Archive;

public class Sample
{
    static int Main(string [] args)
    {
        Archiver arch = ArchFactory.CreateArchive("Unlha", "UNLHA32.DLL");
        if ( arch == null ) {
            Console.WriteLine("UNLHA32.dll がロードできませんでした。");
            return 1;
        }

        DataTable fileList = arch.GetList("CommonArchiverSample.lzh");
        if ( fileList != null ) {
     	   Console.WriteLine("データ・テーブルは使えますよ〜。");
        }
        return 0;
    }
};
 プロジェクトは「ユニコードを使用する」にしてあります。

 それだけでは、余りになんなので。

System::String型からマルチバイト文字に変換する

 それほど大したことはやらないです。
 System::String はUNICODEなので、次のような手順で変換できます。
  1. System::String から array<Char>^ に変換する。
  2. 配列の第一要素に pin を刺す。
  3. WideCharToMultiByte で変換する。
 この手順で、System::String型からchar*型に変換することができます。
 具体的なコードでは、
std::string buff;  // MultiByte文字列を入れる STL の basic_string<char>

// System::String型をChar型(UNICODEの wchar_t に対応)に変換
array<Char>^ arr = stringValue->ToCharArray();

// ガベージ・コレクトで移動しないようポインタにピンを刺す
pin_ptr<Char> wptr = &arr[0];

// 変換後文字サイズを取得
char *buffer = 0;
int len = ::WideCharToMultiByte(CP_UTF8, 0, wptr, num, buffer, 0, NULL, NULL);
if ( len > 0 ) {
    // 文字バッファを取得して
    buffer = new char[len + 1];
    memset(buffer, 0, len+1);
    // UNICODE を MultiByte に変換
    ::WideCharToMultiByte(CP_UTF8, 0, wptr, num, buffer, len, NULL, NULL);

    // バッファをMultiByteの文字型に代入
    buff = buffer;
    if ( buffer ) delete [] buffer;
}
 簡単に std::string ConvertToMultiByte(System::String^ stringValue) みたいな関数を用意しておいてもいいですね。