Susieプラグインは*.spiという拡張子がになってますが、中身はただのDLLに過ぎません。
で、このDLLというやつをVC++で普通に作成してみると、何故かやたらとサイズが大きくなってしまうのです。
何もしないようなDLLをつくっても、40KB超のファイルができてしまいます。
HDDの容量が100GBを越えるのが普通の時代になったとはいえ、無意味にファイルサイズが大きくなるのは、何か納得いかないものがあります。
そこで、このスタートアップコードというやつを省略してやることにします。
これで、プラグインのサイズを、10KB以下にすることができます。
やり方は簡単で、VCのプロジェクトのプロパティで、[リンカ] - [詳細] - [エントリポイント]で、DllMainをエントリポイントに指定するだけです。
makefileなどを使う場合は、リンカオプションで、/ENTRY:"DllMain"とします。
BCCでも、エントリポイントさえ指定すれば、同じことができると思います。
スタートアップコードを省略すると、C/C++ライブラリが使えない以外にも、いくつかの制約が発生します。
これら以外の文字列操作関数は、一切使えません。
strncpy, strcat, stricmpの代わりに、Win32 APIのlstrcpyn, lstrcat, lstrcmpiを使います。
* VC .NETだと、いくつかプロジェクトの設定を変えないと、うまくビルドできませんでした。
- [C/C++] - [全般] - [デバッグ情報の形式] を [無効]に (プロジェクトの規定値から継承)
- [C/C++] - [コード生成] - [C++の例外処理を有効にする] を [いいえ] に
メモリを確保したいだけなら問題はありません。
newなんか使わなくても、HeapAlloc()なり、VirtualAlloc()なりを使えばいいのです。
問題は、2のコンストラクタの呼び出しです。
C++のポリモーフィズムを利用する場合、newは必須です。
class spiBase // プラグインの基底クラス
{
public:
// operatorのオーバーロード
static void* operator new(size_t nSize)
{
// 例外処理しないから、これでいっか
return HeapAlloc(GetProcessHeap(), 0, nSize);
}
static void operator delete(void *p)
{
if (p != NULL)
HeapFree(GetProcessHeap(), 0, p);
}
// その他のメンバは省略
....
}
これで、こころおきなくnew, deleteが使えます。
コンストラクタ、デストラクタの呼び出しはしなくていいのか、と思うかもしれませんが、
operator new, deleteの役割は、あくまでメモリ管理だけです。
メモリハンドルへのポインタを関数のパラメータとしてやり取りする、ハンドルをLocalLock()に渡してメモリブロックを取得するなど、
慣れない人にはかなり使いづらいのではないでしょうか。
解決方法としては、幾つかあると思います。
サンプル : Localハンドルの管理クラス
int GetPicture(LPSTR buf, long len, HANDLE *pHBInfo, HANDLE *pHBm, ...)
{
// 必要な情報を取得する
...
// メモリ確保
LocalHeap lhInfo, lhImage;
BITMAPINFO* pInfo = static_cast<BITMAPINFO*>(lhInfo.Alloc(InfoSize));
BYTE* pImage = static_cast<BYTE*>(lhImage.Alloc(ImageSize));
if (pInfo == NULL || pImage == NULL)
return ErrCode;
// pInfo, pImageに画像情報、画像データを入れる
// エラーが発生したら、何もせずreturnすれば良し
...
// 呼び出し側にLocalハンドルを返す
if (/* 成功なら */){
*pHBInfo = lhInfo.Detach();
*pHBm = lhImage.Detach();
}
return ErrCode;
}
int CallGetPicture(LPSTR filename)
{
// 対応プラグインを調べる
...
// プラグインの呼び出し
HLOCAL hInfo = NULL, hImage = NULL;
int ErrCode = GetPicture(filename, 0, &hInfo, &hImage, ...);
if (/* エラー? */)
return ErrCode;
// 画像情報、画像の取得
LocalHeap lhInfo, lhImage;
BITMAPINFO* pInfo = static_cast<BITMAPINFO*>(lhInfo.Attach(hInfo));
BYTE* pImage = static_cast<BYTE*>(lhImage.Attach(hImage));
// 画像を表示するなり、ファイルに保存するなりする
// エラーが発生したら、何もせずreturnすれば良し
...
// Localハンドルは、自動で解放される
return ErrCode;
}