C言語でタスクバープログレス

C言語で、Windows のタスクバーにプログレス表示する小さいデモ。以下のコードをビルドする。

ole32.dll の API を使っているので、gcc なら -lole32 オプションを付けて libole32.a をリンクする。VC++ なら ole32.lib をリンカオプションに付けてリンクする。

#include <windows.h>
#include <shobjidl.h>

void SetTBP(HWND hwnd) {
  ITaskbarList3 *ppv;
  CLSID clsid;
  IID iid;
  CLSIDFromString(OLESTR("{56FDF344-FD6D-11d0-958A-006097C9A090}"), &clsid);
  IIDFromString(OLESTR("{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF}"), &iid);
  CoCreateInstance(&clsid, NULL, CLSCTX_ALL, &iid, (void **)&ppv);
  ppv->lpVtbl->SetProgressValue(ppv, hwnd, 50, 100);
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) {
  SetTBP(CreateWindow("BUTTON", 0, WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0));
  return MessageBox(0, 0, 0, 0);
}

起動すると、小さいウィンドウとメッセージボックスが出てきて、小さいウィンドウのほうのタスクバーアイテムの左半分が緑色に染まる。

▓▓▓▓▓░░░░░

ただし、現時点で最新の gcc 4.8.1 ではコンパイルエラーになる。なぜならば、ヘッダファイル shobjidl.h の SetProgressValue のプロトタイプ宣言の引数部分が間違っているからだ。

132 行目に、

STDMETHOD(SetProgressValue)(THIS_ ULONGLONG,ULONGLONG) PURE;

とあるので、

STDMETHOD(SetProgressValue)(THIS_ HWND,ULONGLONG,ULONGLONG) PURE;

と書き換えるといい。

あるいは、#include <shobjidl.h> の代わりに、以下のコードによって ITaskbarList3 および SetProgressValue を定義するという荒技もある。

#define INTERFACE ITaskbarList3
DECLARE_INTERFACE(INTERFACE) {
  void *p[9];
  STDMETHOD(SetProgressValue)(THIS_ HWND, ULONGLONG, ULONGLONG);
};
#undef INTERFACE

これでやる場合は、void *p[9]; とあるように、SetProgressValue の定義が、メモリアドレス的に考えて、4 byte 単位で上から 10 番目になるようにすればいいっぽい。CoCreateInstance 関数というのは、おそらくだが、構造体ポインタポインタを受け取ると、そのアドレスを 4 byte ずつずらしながら、関数アドレスを代入していっている。