何か、一部で 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なので、次のような手順で変換できます。
- System::String から array<Char>^ に変換する。
- 配列の第一要素に pin を刺す。
- 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) みたいな関数を用意しておいてもいいですね。