Windows API Tips
ここにあげたTipsは、プログラム作成時に、Windows95 API バイブルでは解決できなかったプログラム手順を、何かの参考になればとHP化したものです。
Microsoft VC++ 6.0でコンパイルし、以下の環境でテストしました。これ以外の環境では期待通り動作しないかもしれません。

機種OS (Windows)
NEC PC98-NX MateXP Home Edition Version 2002 SP3
FUJITSU FMV-A6230Vista Home Basic SP1
NEC PC-LW45H24DR98 Second Edition 4.10.2222 A


1:ウィンドウキャプションのフォント情報を取得する
2:ウィンドウキャプションの表示/非表示を切り替える
3:プログラムの多重起動を防止する
4:プログラムアイコンをタスクトレイに設置し、ポップメニューを表示する
5:特殊フォルダのパスを求める
6:プログラムへのショートカットを生成する
7:アクティブデスクトップをチェックする
8:壁紙を設定変更する
9:プログラムに関連付けされたファイルを開く
10:ディレクトリをブラウジングする
11:ファイルをゴミ箱経由で削除する
12:ダイアログ・プロシジャーで矢印キーを検出する
13:ワイルドカードのマッチング
14:他プロセスのステータスバーのテキストを取込む
15:タスクバーの位置を求める


サンプルコード・ダウンロード (wtsample.lzh:10KB)

1:ウィンドウキャプションのフォント情報を取得する
 キャプションのフォント情報を取得するには、SystemParametersInfoSPI_GETNONCLIENTMETRICSを使用して、クライアント領域外のメトリック値を取得します。

NONCLIENTMETRICS ncm;

    ncm.cbSize = sizeof(NONCLIENTMETRICS);
    SystemParametersInfo (SPI_GETNONCLIENTMETRICS,sizeof(ncm),(void *)&ncm,0);

 関数が成功すると様々なメトリック値が、ncmに通知され、キャプションフォントに関する情報は、LOGFONT構造体としてlfCaptionFontメンバに通知されます。
 例えばキャプション文字列の幅を求める場合には、次のようにします。

HDC   dc;
HFONT hfcapt, hfold;
char  cpstr[] = "...";
SIZE  cpsize;

    dc = GetDC 〜
    hfcapt = CreateFontIndirect (&ncm.lfCaptionFont);
    hfold = SelectObject (dc,hfcapt);
    GetTextExtentPoint32 (dc,cpstr,sizeof(cpstr)-1,&cpsize);
    DeleteObject (SelectObject(dc,hfold));
    ReleaseDC 〜


2:ウィンドウキャプションの表示/非表示を切り替える
 ウィンドウのキャプションを非表示にしたり、あるいは、元に戻して表示するには、SetWindowLongでウィンドウスタイルを変更します。
 以下は、クローズボタンのみを持つウィンドウについての例です。

DWORD   orgWinId;    // ウィンドウ作成時に取得したウィンドウID

void hideCaption (
     HWND  hw,
     int   noCaption    // true : キャプションを非表示にする
     ) {
DWORD style;

    style = GetWindowLong (hw,GWL_STYLE);
    if (noCaption) {
        SetWindowLong (hw,GWL_STYLE, style & ~(WS_CAPTION | WS_SYSMENU));
        SetWindowLong (hw,GWL_ID,0);
    } else {
        SetWindowLong (hw,GWL_STYLE, style | WS_CAPTION | WS_SYSMENU);
        SetWindowLong (hw,GWL_ID,orgWinId);
    }
    SetWindowPos (hw,NULL,0,0,0,0,SWP_NOZORDER|SWP_NOSIZE|SWP_FRAMECHANGED);
}


3:プログラムの多重起動を防止する
 プログラムの多重起動を防止するには、CreateMutexでミューテックス(Mutual Exclusive)オブジェクトを生成し排他処理を行います。つまり、プログラム起動時に、既に同一のミューテックスオブジェクトが存在する場合には、直ちに終了します。
 但し、全く何もせず終了してしまうと、ユーザの操作を完全に無視してしまうことになるので、「既に起動済み」といったメッセージを表示するか、FindWindowで起動済みプログラムのウィンドウハンドルを取得し、フォアグラウンドに持ってくるのがよいでしょう。
 ミューテックスオブジェクトに付ける名前は、プログラム名に何文字かを付加して一意性を高めたものがよいでしょう。プログラム名は、renameして実行されることを考慮して、実行時に動的に決定するのではなく、コンパイル時の定数として指定します。

HANDLE  hme;

    if ((hme = CreateMutex(NULL,TRUE,"MUTEX object name")) == NULL)
        return 0;
    if (GetLastError() == ERROR_ALREADY_EXISTS) {

        // 既に起動されている場合の処理

        return 0;
        // ミューテックスハンドルは、プロセス終了時にシステムが自動的にクローズ
    }
    // 通常の起動処理



4:プログラムアイコンをタスクトレイに設置し、ポップメニューを表示する
 タスクトレイにアイコンを置くには、ShellファンクションのShell_NotifyIconを使用します。この際、アイコンからのメッセージを処理するための親ウィンドウ(通常は、非可視)が必要になります。また、追加したアイコンは自動的には消滅しないので、プログラム終了時に、同じくShell_NotifyIconで削除します。

// アイコンの設置
/*
アイコンからのメッセージは、NOTIFYICONDATA構造体のhWndで指定したウィンドウに、同構造体のuCallbackMessageで指定したメッセージIDで通知されます。指定するメッセージIDは、ユーザ定義帯域の値を指定します。
*/
setIcon (
    HWND   hw,     // 親ウィンドウのハンドル
    HICON  hicon,  // 設置するアイコンのハンドル
    LPSTR  tiptext // 表示するツールチップ・テキスト
    ) {
int rc;
NOTIFYICONDATA nid;

    nid.cbSize = sizeof(nid);
    nid.hWnd = hw;
    nid.uID = 0;
    nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    nid.uCallbackMessage = WM_USER;
    nid.hIcon = hicon;
    strncpy (nid.szTip, tiptext, sizeof(nid.szTip));
    rc = Shell_NotifyIcon (NIM_ADD, &nid);
    DestroyIcon (hicon);
    return rc;
}

// アイコンの削除
deleteIcon (HWND hw) {
NOTIFYICONDATA nid;

    nid.cbSize = sizeof(nid);
    nid.hWnd = hw;
    nid.uID = 0;
    return Shell_NotifyIcon (NIM_DELETE, &nid);
}

// 親ウィンドウのウィンドウプロシジャー
LRESULT WINAPI wndproc (HWND hw, UINT msg, WPARAM wp, LPARAM lp) {
static HMENU hmpop;

    switch (msg) {
      case WM_CREATE:
hmpop = CreatePopupMenu ();
/*
   メニュー作成
*/
setIcon (wh, LoadIcon (〜), "ツールチップ・テキスト");
return 0;

      case WM_USER:
if (lp == WM_RBUTTONDOWN) {  // ポップアップメニューの表示
POINT  pt;

GetCursorPos (&pt);
SetForegroundWindow (hw);
SetFocus (hw);
TrackPopupMenu (hmpop,TPM_LEFTALIGN|TPM_RIGHTBUTTON,
                pt.x, pt.y, 0, hw, NULL);
PostMessage (hw,WM_NULL,0,0);
return 0;
/*
  これらの一連の手順は、ポップアップメニューが消えなくなったり、
  あるいは、すぐ消えてしまうことを回避するための手順です。
  マイクロソフト サポート技術情報 - 135788参照
*/
}
// その他、ダブルクリックなどのメッセージ処理
return 0;

      case WM_COMMAND:
// メニューコマンドの処理
return 0;

      case WM_CLOSE:
deleteIcon (hw);
DestroyMenu (hmpop);
DestroyWindow (hw);
return 0;

      case WM_DESTROY:
PostQuitMessage (0);
return 0;
    }
}


5:特殊フォルダのパスを求める
 スタートメニューなどWindows上で特別な意味をもつフォルダのパスを求めるには、ShellファンクションのSHGetSpecialFolderPathを使用します。
 但し、Windows95(i.e. 4.0未満)では、このファンクションは実装されていないので、SHGetSpecialFolderLocationSHGetPathFromIDListを組み合わせて使用します。
 例えば、Windows起動時にプログラムを実行するためのショートカットを格納する"スタートアップ"フォルダを求めるには、

[Win95以外]

#include <shlobj.h>
char path[MAX_PATH];

    SHGetSpecialFolderPath (NULL, path, CSIDL_STARTUP, 0);

    // スタートアップ・フォルダ(CSIDL_STARTUP)のパスがpathに格納されます。
    // その他の特殊フォルダのID(CSIDL_*)は、shlobj.hに定義されています。
    // 第4引数に真の値を指定すると、フォルダがないとき作成されます。

[Win95]

LPMALLOC     ppm;
LPITEMIDLIST idl;
char         path[MAX_PATH];

    if (SHGetMalloc (&ppm) == NOERROR) {
if (SHGetSpecialFolderLocation (NULL, CSIDL_STARTUP, &idl) == NOERROR) {
    SHGetPathFromIDList (idl,path);
    ppm->lpVtbl->Free (ppm,idl);
}
ppm->lpVtbl->Release (ppm);
    }

注) SHGetSpecialFolderLocationは、ITEMIDLISTのためにメモリオブジェクトを必要とするため、SHGetMallocでメモリを確保しておかなければなりません。


6:プログラムへのショートカットを生成する
 プログラムへのショートカットを作成するには、COMライブラリのIShellLinkインターフェスを使用します。
 ショートカットをIShellLinkで作成するには、必要最低限のパラメタとして、あらかじめ、プログラムと作成するショートカットのフルパスを求めておく必要があります。
 プログラムのフルパスは、GetModuleFileNameで、また、ショートカットのフルパスは、Tips No.5などで保存先フォルダを求め、パスを生成します。

#include <shlobj.h>
char             programPath[MAX_PATH],
                 shortcutPath[MAX_PATH];
IShellLink *     sl;
IShellLinkVtbl * vp;
IPersistFile *   pf;
WCHAR            work[MAX_PATH];

GetModuleFileName (NULL,programPath,sizeof(programPath));
SHGetSpecialFolderPath (NULL,shortcutPath,CSIDL_STARTUP,1);
strcat (shortcutPath,"\\ShortcutName.lnk");

CoInitialize (NULL);    // COMライブラリを初期化
if (CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
                      &IID_IShellLink, (void **)&sl) == S_OK) {  // *1
vp = sl->lpVtbl;    // ベクターテーブルへのポインタを取り込む
if (vp->QueryInterface (sl,&IID_IPersistFile,(void **)&pf)
                                       == S_OK) {  // *2
vp->SetPath (sl,programPath);       // プログラムパス
vp->SetDescription (sl,NULL);       // 説明(= ツールチップス)
vp->SetArguments (sl,NULL);         // コマンドライン引数
vp->SetWorkingDirectory (sl,NULL);  // 作業ディレクトリ
vp->SetIconLocation (sl,NULL,0);    // Iconのパスまたはインデックス
vp->SetShowCmd (sl,SW_SHOWNORMAL);  // 起動時のウィンドウ表示

MultiByteToWideChar (CP_ACP, 0, shortcutPath,
              -1, work, MAX_PATH);  // パスをユニコードに変換
pf->lpVtbl->Save (pf, work, TRUE);  // ショートカットを保存
pf->lpVtbl->Release (pf);           // IPersistFileへのポインタを破棄
}
vp->Release (sl);   // IShellLinkへのポインタを破棄
}
CoUninitialize ();      // COMライブラリをクローズ

*1 IShellLink用に空のインスタンスを作成し、インスタンスへのポインタを取得する
*2 IPersistFileインターフェスが存在するか問い合わせ、存在する場合には、インターフェスへのポインタを取得する


7:アクティブデスクトップをチェックする
 デスクトップがアクティブデスクトップ状態であるか否かを検査するには、COMライブラリ(No.6の例参照)のIActiveDesktopインターフェスを使用します。

#include <wininet.h>
#include <shlobj.h>
LPACTIVEDESKTOP sl;
COMPONENTSOPT   comopt;

ZeroMemory (&comopt, sizeof(comopt));
CoInitialize (NULL);
if (CoCreateInstance (&CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
                      &IID_IActiveDesktop, (void **)&sl) == S_OK) {
comopt.dwSize = sizeof (COMPONENTSOPT);
sl->lpVtbl->GetDesktopItemOptions (sl, &comopt, 0);  // Desktop情報を取得
sl->lpVtbl->Release (sl);
}
CoUninitialize ();

// comopt.fActiveDesktopが真ならアクティブデスクトップ状態


8:壁紙を設定変更する
 壁紙の変更は、アクティブデスクトップであるか否か(No.7)によって手順が異なります。
 アクティブデスクトップの場合には、COMライブラリ(No.6の例参照)のIActiveDesktopインターフェスを使用し、設定はSetWallpaper、配置方法の指定はSetWallpaperOptionsで行います
 一方、非アクティブデスクトップの場合は、設定をSystemParametersInfoSPI_SETDESKWALLPAPERで、配置方法の指定はレジストリを直接書き換えることにより行います。
 
#include <windows.h>
#include <wininet.h>
#include <shlobj.h>

setWallpaper (
    char * bmPath,  // ビットマップファイルのパス
    int    style    /* 配置方法
 WPSTYLE_CENTER  : 中央に表示
 WPSTYLE_TILE    : 並べて表示
 WPSTYLE_STRETCH : 拡大表示
*/
) {
// 戻り値 = 0 : 設定に成功
//    ≠ 0 : 設定に失敗 (エラー番号)

LPACTIVEDESKTOP     ap;
COMPONENTSOPT       comopt;
HKEY                key;
int                 rc;

rc = 0;
ZeroMemory (&comopt, sizeof(comopt));
CoInitialize (NULL);
if (CoCreateInstance(&CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, 
                          &IID_IActiveDesktop, (void **)&ap) == S_OK) {

IActiveDesktopVtbl* vp;
WALLPAPEROPT        wpopt;
WCHAR               work[MAX_PATH];

vp = ap->lpVtbl;
comopt.dwSize = sizeof(comopt);
vp->GetDesktopItemOptions (ap,&comopt,0);
if (comopt.fActiveDesktop) {
// アクティブデスクトップの場合
MultiByteToWideChar (CP_ACP, 0, bmPath, -1,
                     work, MAX_PATH);       // パスをユニコードに変換
if (vp->SetWallpaper (ap,work,0)) {         // 壁紙を設定
    rc = 1;
} else {
ZeroMemory (&wpopt, sizeof(wpopt));
wpopt.dwSize = sizeof (wpopt);
wpopt.dwStyle = style;
vp->SetWallpaperOptions (ap,&wpopt,0);  // 配置方法を指定
if (vp->ApplyChanges (ap,AD_APPLY_ALL)) // 変更を適用
    rc = 2;
    }
}
vp->Release (ap);
}
CoUninitialize ();

if (comopt.fActiveDesktop)
    return rc;

// 非アクティブデスクトップの場合
if (RegOpenKeyEx (HKEY_CURRENT_USER,"Control Panel\\Desktop",0,
                  KEY_ALL_ACCESS,&key) != ERROR_SUCCESS) {
    rc = 3;
} else {  // 配置方法をレジストリに書き込む
RegSetValueEx (key, "TileWallpaper", 0, REG_SZ,
               style == WPSTYLE_TILE? "1":"0", 2);
RegSetValueEx (key, "WallpaperStyle", 0, REG_SZ,
               style == WPSTYLE_STRETCH? "2":"0", 2);
RegCloseKey (key);

if (!SystemParametersInfo (SPI_SETDESKWALLPAPER,0,bmPath,
                           SPIF_UPDATEINIFILE))
    rc = 4;
    }
    return rc;
}

[壁紙設定時の注意]
SystemParametersInfoで指定できるのはbmpファイルのみ
 SetWallpaperでは、Webコンテンツを直接壁紙として指定できますが、SystemParametersInfoではbmpファイルしか指定できません。従って、JPEGやGIF形式などのファイルは、何らかの方法でbmpファイルに変換しなければなりません。
画像サイズの縮小は行われない
 デスクトップより小さな画像は、拡大指定でデスクトップの大きさに合わせることができますが、その逆はできません。つまり、デスクトップ・サイズを超える部分は表示されません。従って、このような画像全体を表示するには、CopyImageStretchDIBitsなどで画像サイズを調整したものをbmpファイルとして出力する必要があります。
カラー解像度を確認する
 ディスプレイのカラー解像度が、壁紙ファイルの解像度より低い場合、期待通りには表示されないことがあります。カラー解像度は、GetDeviceCapsBITSPIXELで調べることができます。

9:プログラムに関連付けされたファイルを開く
 プログラムからブラウザを起動してhtmlファイルを表示したいといったように、htmやtxtなど、ごく一般的な拡張子を持ったファイルを対応するアプリケーションに開かせるには、レジストリのHKEY_CLASSES_ROOTを検索し、アプリケーションのパスを求めて行うこともできますが、ShellファンクションのShellExecuteを使用すると、より簡単に行うことができます。

ShellExecute (hwnd, func, path, param, dir, show);

hwnd  :親ウィンドウのハンドル
func  :ファンクション ("open", "print", "explore")
path  :パス(ファイル、ディレクトリ、アプリケーション)
param :アプリケーションへの引数
dir   :デフォルト・ディレクトリ
show  :起動時のウィンドウ表示方法

ex) ShellExecute (hwmain, "open", "test.htm", NULL, NULL, SW_SHOW);

10:ディレクトリをブラウジングする
 ファイルのパスは、コモンダイアログで取得できますが、ディレクトリパスをダイアログからブラウジングしながら取得するには、ShellファンクションのSHBrowseForFolderを使用します。

#include <shlobj.h>
BROWSEINFO   bi;
LPITEMIDLIST idl;
char         direc[MAX_PATH];
LPMALLOC     ppm;

    if (SHGetMalloc(&ppm) == NOERROR) {       // NO.5参照
ZeroMemory (&bi,sizeof(bi));
bi.hwndOwner = hwnd;                  // Dialogの親ウィンドウ
bi.lpszTitle = title;                 // Dialogのウィンドウタイトル
if ((idl = SHBrowseForFolder(&bi)) != NULL) {
    SHGetPathFromIDList (idl,direc);  // NO.5参照
    ppm->lpVtbl->Free (ppm,idl);
}
ppm->lpVtbl->Release (ppm);
    }


 もし、特定のディレクトリからブラウジングしたい場合は、以下のcallback関数を用意し、

static int CALLBACK bdcallback (HWND hwnd, UINT msg, LPARAM lp, LPARAM data) {
// data : initial directory

if (msg == BFFM_INITIALIZED && data)
    SendMessage (hwnd, BFFM_SETSELECTION, (WPARAM)TRUE, (LPARAM)data);
return 0;
}

SHBrowseForFolderを呼び出す前に、BROWSEINFO構造体に、関数とディレクトリを指定します。 

    bi.lpfn = bdcallback;
    bi.lParam = (LPARAM)directory_path;


11:ファイルをゴミ箱経由で削除する
 DeleteFileによる完全削除ではなく、ファイルをゴミ箱経由で削除するには、ShellファンクションのSHFileOperationで、UNDO付き削除を実行します。

#include <windows.h>
SHFILEOPSTRUCT    fileop;

fileop.hwnd = hw;                    // 親ウィンドウのハンドル
fileop.wFunc = FO_DELETE;            // 削除機能
fileop.pFrom = path;                 // 削除対象パス
fileop.pTo = NULL;
fileop.fFlags = FOF_ALLOWUNDO|       // UNDO可(= ゴミ箱に移動)
                FOF_NOCONFIRMATION|  // 確認メッセージなし
                FOF_SILENT;          // プログレス非表示
SHFileOperation (&fileop);


12:ダイアログ・プロシジャーで矢印キーを検出する
 通常、ウィンドウ操作に関連するキー(矢印やTabなど)メッセージは、デフォルトのダイアログ・プロシジャーによって処理され、ユーザ定義のプロシジャーに通知される事はありません。
 これらのキーを検知するには、2つの方法があります。一つは、SetWindowsHookExでダイアログメッセージをフックする方法。もう一つは、サブクラス化したダイアログ・プロシジャーで検知する方法です。ここでは、ダイアログのその他の処理にも応用できるサブクラス化方式の例を示します。

WNDPROC defwproc;

// ダイアログ・メインプロシジャー
PASCAL dlgproc (HWND hwnd, UINT msg, WPARAM wP, LONG lP) {
LRESULT CALLBACK subwproc (HWND hwnd, UINT msg, WPARAM wP, LONG lP);

    if (msg == WM_INITDIALOG) {
        // サブクラス化
        defwproc = (WNDPROC)SetWindowLong (hwnd,GWL_WNDPROC,(UINT)subwproc);
        return 1;
    }

    if (msg == WM_COMMAND) {
        if (LOWORD(wP) == IDOK || LOWORD(wP) == IDCANCEL) {
            SetWindowLong (hwnd,GWL_WNDPROC,(UINT)defwproc);
            EndDialog (hwnd,0);
        }
        return 0;
    }
    return 0;
}
// サブクラス化したプロシジャー
LRESULT CALLBACK subwproc (HWND hwnd, UINT msg, WPARAM wP, LONG lP) {

    if (msg == WM_GETDLGCODE)
        return DLGC_WANTALLKEYS;  // 全てのキーボードインプットを通知する

    if (msg == WM_KEYDOWN) {
        // 処理すべきキー(wP)かどうか判別する
    }
    return CallWindowProc (defwproc, hwnd, msg, wP, lP);
}

13:ワイルドカードのマッチング
 文字列とワイルドカードをマッチングするには、light-weight utility APIsのPathMatchSpecを使用します。単にワイルドカードにマッチするファイルを探すのなら、FindFirstFileを使えばよいわけですが、この場合は実際に入出力動作が伴うので、これを回避したい時に、PathMatchSpecを使用します。
 但し、PathMatchSpecは、純粋に文字列とワイルド・パターンとのマッチングなので、DOSのショート・ファイル名を扱う場合は注意が必要です。例えば、*.htmは、FindFirstFileでは、foo1.htmとfoo2.html(foo2~1.htm)がマッチしますが、PathMatchSpecでは、foo1.htmしかマッチしません。
 また、PathMatchSpecは、Internet Explorer 3.0以降のコンポーネント(shlwapi.dll)として提供される機能なので、それより古いバージョンでは利用できません。

#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>

    printf ("%s\n",PathMatchSpec (name,"*.htm") ? "matched" : "unmatched");

14:他プロセスのステータスバーのテキストを取込む
 ステータスバーに書込まれたテキストは、SB_GETTEXTメッセージを当該ウィンドウに送ることで取り出すことができますが、送り先が自プロセスでない場合、双方のプロセスの仮想アドレス空間が異なるため、SB_GETTEXTを受けた側では、引数として渡された仮想アドレスを実アドレスに変換することができず異常終了します。
 そこでこのような問題を解決するために、次のような手順を経てプロセス間のデータ交換を行います。
  • VirtualAllocEx関数で、相手側プロセスのメモリ空間に領域を確保する
  • その領域にステータスバーのテキストを取り出す
  • ReadProcessMemory関数でそのテキストを自プロセスのメモリに取り込む

 但し、この手順はWindows NT系の場合で、9x系ではメモリマップドファイルを使用します。

#include <windows.h>
#include <shlobj.h>
int    sl;
HANDLE hproc;
DWORD  pid;
char   wk[64];

    HWND hw = FindWindow (0,"他プロセスのウィンドウ"),
    hsw = FindWindowEx (hw,0,STATUSCLASSNAME,0); // ステータスバーのハンドルを取得
    if (!hw || !hsw) {  // エラー処理
        return;
    }
    sl = SendMessage (hsw,SB_GETTEXTLENGTH,0,0); // 取得テキストの長さを求める
    if (!sl) {          // テキストなし処理
        return;
    }
    GetWindowThreadProcessId (hsw,&pid); // ウィンドウ作成元のプロセスIDを求める
    if ((hproc = OpenProcess             // プロセスをオープンしハンドルを求める
                 (PROCESS_VM_OPERATION|PROCESS_VM_READ, 0, pid)) != NULL) {
        void *mem = VirtualAllocEx       // そのプロセスのメモリ空間に領域を確保する
                 (hproc, 0, sl+4, MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
        if (mem) {
            SendMessage (hsw,SB_GETTEXT,0,(int)mem);             // テキストを取り出す
            ReadProcessMemory (hproc,mem,wk,sizeof(wk)-1,NULL);  // 自メモリに読み込む
            VirtualFreeEx (hproc,mem,0,MEM_RELEASE);
        } else {
            // VirtualAllocEx失敗
        }
        CloseHandle (hproc);    
    }

15:タスクバーの位置を求める
 タスクバーは位置、サイズが可変で、表示方法にもオプションがあるため、その状態を確認できないとデスクトップ全体を描画領域として使いたいとき、期待通りの結果が得られません。
 タスクバーの状態を知るにはShellファンクションのSHAppBarMessageを使用します。

#include <windows.h>
#include <stdio.h>

APPBARDATA  tb;
int         bstat;

    tb.cbSize = sizeof(tb);
    bstat = SHAppBarMessage (ABM_GETSTATE,&tb);  // 表示状態を求める
    SHAppBarMessage (ABM_GETTASKBARPOS,&tb);     // 位置サイズを求める
    printf ("left=%d, top=%d, bottom=%d, right=%d\n",
            tb.rc.left, tb.rc.top, tb.rc.bottom, tb.rc.right);
    printf ("AutoHide %s\n", bstat & ABS_AUTOHIDE ? "ON" : "OFF");
    printf ("AlwaysOnTop %s\n", bstat & ABS_ALWAYSONTOP ? "ON" : "OFF");


©2000 YMan