簡易メモリアロケータ

最近面白そうな機能満載の携帯がいっぱい出てきて、意味無く携帯を新しくしたいです。どっちかっていうと、時間潰しができて遊べる携帯(^^;;; 早くDOCOMOからiPhone出てくれないかな~。坂本龍一がCMやってたSamsungも良いなぁ。面白そうなやつは全部ソフトバンクなんだなぁ~。DOCOMOももっと変わったもん出して欲しいなぁ。

そんなことはさておき、

ローカルスコープ内で、使い捨てみたいな使い方をするような小さなメモリを確保するとき、たとえば、Win32APIでなんらかの文字列を受け取るときのバッファとか、いちいちnewでメモリ確保して、使い終わったらdeleteして・・・が面倒くさい。特にC#を覚えてnewしっぱなしでdeleteする必要がない言語に慣れきってしまうとC++は非常にやりづらい。

と、かなり前に思って、以前ずっとかなり前にWin32APIの勉強のため書いていた簡易メモリアロケータを引っ張り出してきて、ちょこっと手直し。

正直、メモリアロケータなんて大層なもんじゃなくて、コンストラクタでnewしてメモリを確保して、スコープから抜けるとデストラクタでdeleteする、という超簡単なもん。

手直ししたのは、コンストラクタとデストラクタでメモリの確保と解放する際に、newとdelete演算子を使わず、Windowsの Heap系のAPIで置き換えたことと、& 演算子をオーバーロードして、内部バッファのポインタを返すようにしたことの2点。Advanced Windows のメモリ管理を参考に参照カウンタも付けてみました(^^;

ほとんどサンプルと同じになっちゃった(^^;

具体的には・・・

CAllocator alloc(MAX_PATH); //MAX_PATHバイトのメモリ確保
CAllocator allocs[5] = {100,100,100,100,100}; //配列とか、
CAllocator alloc; alloc->Alloc(100); //などでメモリ確保
CAllocator alloc; alloc.Alloc(100); //などでメモリ確保

メモリブロックのポインタを得るには、*演算子。

LPSTR lpStr = reinterpret_cast<LPSTR>(*alloc);

スコープを抜けるとデストラクタがコールされて、メモリが解放。参照数がゼロになると、プライベートヒープハンドルも解放。

修正すべき欠点は、スレッドセーフじゃない。複数スレッドで使用すると参照カウンタとかで競合が起きるし。大きなメモリ(たとえば1MBとか)を確保したいときとかは、VirtualAlloc系を使うべき、らしい。
まぁ・・・スレッドをおこすようなプログラムは複雑になればなるほどC#の方が安全で簡単なんで。

追記) &演算子で確保したメモリのポインタをリターンしてますが、スコープを抜けると問答無用でメモリ解放してしまうので、気をつけないといけません。CAllocatorを動的に確保すればいいんでしょうけど、それだと意味がなくなる(^^;

これをベースに実用的に使えるまで改良していきたいと思います。


8月30日、ところどころ修正しました。

シェルエクステンション

以前に作ったクリップボード関連のツールをシェルエクステンションで実装しよう、と思って長い間放置していたんですが・・・昼休みと、昨日、今日帰ってから寝るまでの時間で突貫工事で仕上げました(^^ ついでにテキストファイルの内容をコピーする機能も追加。なかなか重宝してます(^^

CF_TEXT2File

CF_TEXT2File

処理の中心となるクリップボードの処理は既に作ってあったので、後はシェルエクステンションのコンテキストメニューハンドラを実装するだけ・・・すぐできると思ってましたが・・・デバッグが思うようにできなくて時間がかかってしまいました。一度エクスプローラ上で右クリックしてコンテキストメニューを出すと、そのエクスプローラ・プロセスを終了させないとシェルエクステンション本体(DLL)を上書きできないので非常に面倒。しかも・・・不用意にデスクトップを右クリックしてしまうと・・・デスクトップ(エクスプローラ)の再起動がかかる・・・

で、やっと望む動作をして完成・・・したと同時に気付いたよ。

「Virtual PC 上のXPでデバッグすりゃいいじゃん!」

年取るのは、いやだねぇ(ーー;;;

また、暇があったら、CF_HDROP フォーマットにも対応させよう。っと。

寒すぎですねぇ

数年前なら平気で撮影会とか行ってましたが(笑)

原点回帰して、C++とWin32APIで組むのが最近はまりつつあります。まぁ、当たり前ですけど、同じ機能のものをC#やPerlとPerlモジュール、WSHで組めば圧倒的に早くバグがない安全なものが完成するんですけど、家で使うツールぐらいはねぇ・・・少々バグがあっても無問題だし・・・ってことで、ほとんど忘れかけていたC++を持ち出して夜遅くまでエディタとデバッガと睨めっこです。

昨日から書き始めたのが、

  • クリップボードの内容(CF_TEXT)をファイルに書き出す。
  • テキストファイルの内容をクリップボードに転送する。

ただ、これだけ。非常に簡単。

何に使うのかというと・・・、ブラウザなどでテキストをコピーしてどっかに保存するとき・・・

  1. デスクトップを右クリック→新規作成→テキストドキュメント でファイル作成
  2. 作成したファイルをエディタで開いてペースト(貼り付け)
  3. 保存する。

という、一連のステップが非常にメンドクサイ(^^;; ただ、一回だけなら・・・別に良いんだけど・・・。

というわけで・・・レジストリを弄って「デスクトップを右クリック→新規作成」のメニューに「クリップボード」項目を作成。これが選択されたら、もしクリップボードにテキスト形式(CF_TEXT)のデータがあれば、新規にファイルを作成してそこにペースト&保存するようにした。

e5908de7a7b0e69caae8a8ade5ae9a-1

プログラム的には、一個関数を作ればいい程度のものですが、再利用したいので強引にC++風にする。

class CClipboardText
{
  //コピーコンストラクタと代入演算子は使用禁止
  CClipboardText(const CClipboardText& rhs);
  CClipboardTexT& operator=(const CClipboardText& rhs);

protected:
  LPBYTE lpData; //内部データのためのバッファ
  size_t cbLen; //バッファのサイズ

public:
  //コンストラクタとデストラクタ
  CClipboardText();
  virtual ~CClipboardText();

  //公開メソッド
  virtual bool Save(LPTSTR lpOut);
  virtual bool Load(LPTSTR lpIn);
};

要は、コンストラクタで Win32 APIのOpenClipboard()とGetClipboardData()を呼んで内部データバッファにデータを読み出し、Saveメソッドでファイルに書き出す。デストラクタで内部データバッファの解放とWin32APIのCloseClipboard()をコールするだけ。
あとは、適当なタイミングでインスタンスを作成して、save()すればいい。

//クリップボードのテキストデータをファイルに書き出す。
//使い捨て?のオブジェクトなので変数を用意せず、無名のまま使用(^^;
CClipboardText().Save(TEXT("ファイル名"));

要は、コンストラクタで Win32 APIのOpenClipboard()とGetClipboardData()を呼んで内部データバッファにデータを読み出し、Saveメソッドでファイルに書き出す。デストラクタで内部データバッファの解放とWin32APIのCloseClipboard()をコールするだけ。
あとは、適当なタイミングでインスタンスを作成して、save()すればいい。

//クリップボードのテキストデータをファイルに書き出す。
//使い捨て?のオブジェクトなので変数を用意せず、無名のまま使用(^^;
CClipboardText().Save(TEXT(&quot;ファイル名&quot;));

まだLoadメソッドが未実装。今日中に完成して連休は終わりです(^^;;;

追記)
・・・と、思ったけど、ContextmenuHandlerにしてシェルエクステンションで実装する方が、よりスマートで、いいかもしれない。でもVistaだとエクスプローラ・シェルがさらに重くなりそうな悪寒が・・・。