Win32 API memo

Win32 API について、SDK HELP/MSDN に載っていない/分かりにくい事項の覚え書きです。
Homeへ戻る update:2023-10-22

個別API等の動作関連

GetTempPathName(lpszPath, lpszPrefix, uUnique, lpszTempFile)
uUnique == 0 のとき、生成したファイル名で filesize = 0 のファイルが作成される。
→一時ディレクトリを作る時はこのファイルを一旦削除するか、uUnique != 0 で利用する必要あり。
(2000-09-02)
GetTempPath(cchBuffer, lpszTempPath)
cchBuffer は 約 0x7000 未満にしないといけない。
0x7fff 等では例外が発生し、0x8000 では FALSE を返す。
(2000-11-04)
GetFileInformationByHandle()
NEC PC-98x1用 Windows9x 上からネットワーク上の Windows9x(機種問わず)のエントリを見た場合、dwFileAttributesが正常に取得できない。また、nFileSizeHigh/nFileSizeLowが正常で無い場合もある。FindFirstFile()/FileNextFile(), GetFileAttributes()なら問題無いようなので、こちらから情報を得るといいようだ。
(2001-09-08)
FindFirstFile()
FindNextFile()
int 21H AX=714eH/714fH
  • cAlternateFileName はエントリ名が 8.3 文字に収まらない場合に使われる。収まる場合は「""」である。
    更に、小文字などで構成されている場合でも、8.3 形式で収まれば cAlternateFileName は使われない。
    また、短いファイル名の生成機能(NT系のみ、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation)を停止している場合も使われない。
    (2002-05-08)
  • dwCreationTime / dwLastAccessTimeが未対応の場合は値が 0 となるが、これを普通に変換すると「1601-01-01 9:00:00.000」(9時になっているのは、日本が GMT+9 であるため)になる。このため、2桁年表示を「year - 2000」等とするとおかしくなる。もっとも2000年問題関連で対処されている可能性が大きいが(^^;
    (2003-04-22)
  • 表現できない文字(例えばANSI版APIでOEM文字にないUNICODE文字)で構成されたファイル名は、似た文字がある場合はその文字に、似た文字が無ければ「?」になる。 (WideCharToMultiByteでの処理と同じはず。)
    どちらにしても、得られたファイル名を用いてファイル操作をすることはできない。

    例)
    上付き数字2「²」(UNICODE 0xb2)→「2」(ANSI 0x32)
    著作権記号(c)「©」(UNICODE 0xa9)→「c」(ANSI 0x63)
    左斜め上矢印「↖」(UNICODE 0x2196)→「?」(ANSI 0x3f)
    ※「」内にUNICODE文字を使っているため、表示環境によっては正しく表示されません。
    (2002-05-08)
  • ANSI 版では、cFileName に入りきらない長さ、例えば、漢字のみで200文字(ANSI 版なら400bytes相当)のエントリは列挙されず、ERROR_MORE_DATAとなる。
    また、CD-ROM等上のディレクトリを読むときにERROR_MORE_DATAがでる場合がある。常に同じエントリででる訳ではないので、読み取り失敗したのではないかと思われる。
    これらの理由によってERROR_MORE_DATAがでてもFindNextFileで続きを読むことができる。
    (2005-06-23)
  • 短いファイル名の取得は、少なくともWindows7以降において、大きな負担になっており、倍程度の時間が必要となっている(下記表を参照)。
    このため、短いファイル名が不要であれば、FindFirst や FindExInfoStandard を指定した FindFirstFileEx より、FindExInfoBasic を指定した FindFirstFileEx が好ましい。(2023-10-22)
  • FindFirst や、FindFirstFileEx の代わりに FileIdBothDirectoryInfo 等を指定した GetFileInformationByHandleEx を使用することができる。ただし、FindFirst や、FindFirstFileEx と同程度の情報を入手する場合、速度はほとんど変わらない。(下記表を参照, 2023-10-22)
FindFirst(), FindFirstFileEx(), GetFileInformationByHandleEx()
FindFirst, FindFirstFileEx, GetFileInformationByHandleEx による特定ディレクトリの全エントリ取得の速度比較例を以下に示す。
いずれも、VMWare 上の仮想マシン上の Windows を用いて、C:\Windows\WinSxS 内を対象にし、FindFirst による計測を1度行った後、表に記載の API を使用して本測定している。
※計測値は1回計測の値である為、数msの誤差がある。 ※計測は次の書庫内の実行ファイルを使った。 findfirst.zip
Windows7
(エントリ数 14627)
Windows8.1
(エントリ数 12695)
Windows10
(エントリ数 13724)
FindFirst27.3ms14.5ms53.1ms
FindFirstFileEx
(FindExInfoBasic)
7.1ms7.5ms41.2ms
FindFirstFileEx
(FindExInfoBasic
FIND_FIRST_EX_LARGE_FETCH)
6.3ms10.5ms18.8ms
FindFirstFileEx
(FindExInfoStandard)
22.6ms15.4ms54.3ms
FindFirstFileEx
(FindExInfoStandard
FIND_FIRST_EX_LARGE_FETCH)
30.4ms19.8ms33.1ms
GetFileInformationByHandleEx
(FileIdBothDirectoryInfo)
30.6ms20.7ms33.1ms
GetFileInformationByHandleEx
(FileIdExtdDirectoryInfo)
-11.2ms17.6ms
GetFileInformationByHandleEx
(FileFullDirectoryInfo)
-13.0ms21.0ms
(2023-10-22)
RegisterDragDrop (OLE2 D&D)
内部で作成される別スレッドで監視を行っている
(2001-02-04)
GetDiskFreeSpace
  • Windows 9x では 各種値が FAT16 の範囲内に調節される(次の例を参照)。
    lpSectorsPerCluster * lpBytesPerSector ≦ 32768
    lpFreeClusters & lpClusters ≦ 65535
    ※ディスク容量は 2Gbytes 以内に丸められる。
  • Windows NT/2000 では各種値が 16bit を超えることがあるため、ディスク容量が 2Gbytes/4Gbytes を越え、signed long/unsigned long の範囲外になる。
  • Windows 2000 以降で可能な Disk Quota が有効である場合、各種クラスタ数は Quota の制限値に沿った値になる。
(2001-02-20)
GetDiskFreeSpaceEx
  • Windows95B(OSR2)、WindowsNT 4.0 以降対応のため、それ以前の Windows に対応するには手動でインポートを行う必要がある。
  • Windows 9x(PC, NEC98x1を問わない) でネットワークドライブ(ドライブ名形式/UNC形式を問わない)の容量を求めると、そのドライブの総容量が 2Gbytes を超える場合、各種容量が 2Gbytes 以内に丸められる(GetDiskFreeSpaceと同じ処理)。
  • Windows NT4.0/2000 では Disk Quota で丸められた空き容量/総容量と実ドライブの空き容量を求めることができる。
(2001-02-20)
CompareString
dwCmpFlags で使用される、NORM_xxx、LINGUISTIC_ は、同等か否かの比較用フラグである。ソートのための比較に使用しても、CSTR_GREATER_THAN / CSTR_LESS_THAN の変化は得られず、並び順が変わらない。
ソートのための比較フラグは、SORT_STRINGSORT / SORT_DIGITSASNUMBERS のみになる。
(2020-04-18)
MoveFile
異なるボリュームに対してファイルの移動ができないことになっているが、実際は可能になっている。(95B/NT4/2000で確認)
※エントリの付け替えによる高速移動と区別する方法が見当たらず、MoveFileで待たされることがある。
(2001-04-04)
NotifyChangeEventLog
このAPIで得られるシグナル状態は、PulseEventによって変化する。つまり、待機API(WaitForSingleObject等)内で変化しないと取得できない。例えば、
while ( WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0 );
というコードを書いてもイベントログの書き込みがされたことをすべて検出できない。
→GetNumberOfEventLogRecordsを併用したほうがよさそうだ
(2001-12-06)
PulseEvent
待機API(WaitForSingleObject等)によって待機している場合でないとPulseEventの効果が期待できない。例えば、
while ( WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0 );
というコードを書くと検出漏れが発生する

(2001-12-06)
SetWindowText
GetWindowText
WM_SETTEXT
WM_GETTEXT
?etWindowTextとWM_?ETTEXTは基本的に同じ動作だが、条件によっては異なる動作となる。
  • 別プロセスのEdit controlに対してテキスト内容の取得・設定を行う場合、WM_?ETTEXTは動作するが、?etWindowTextは使用できない。
  • WM_?ETTEXT で正しいテキストを取得できない場合、SendMessageではなくSendMessageA/SendMessageWを使ってコード体系を変えてみるとよい。
(2002-02-02)修正
FindFirstChangeNotification
エラーの返値は、INVALID_HANDLE_VALUEだが、NULLが帰ってくることがある。(Win2000 SP3 で MAX_PATH を越えるパスを指定したときに確認)

(2002-11-08)
SelectObject
フォントの切り替えはかなりコストが掛かるようだ。
ppv.exe は、tab を矢印で表示させるときに、一時的に SelectObject を使って Symbolフォント切り替えている。この状態で tab code が大量に入っているファイルを表示させたとき、画面描画中であることががはっきりわかるほど遅くなる。

(2003-04-19)
ImpersonateNamedPipeClient
ImpersonateNamedPipeClientは、「パイプから直前に読み取ったメッセージ」の送信元クライアントに偽装することができる。つまり、ReadFile等で予めメッセージを読んだ後に、ImpersonateNamedPipeClientを使う必要がある。
ConnectNamedPipeを実行した直後等は、まだメッセージを読んだことにならないので、ImpersonateNamedPipeClientを実行してもエラーになる。
(2003-09-20)
ToAscii(uVirtKey, uScanCode, lpbKeyState, lpwTransKey, fuState)
変換された結果が入る lpwTransKey は WORD だが、実際は下位バイトのみ書き換えられ、上位バイトは ToAscii の実行前と同じ値である。
(Windows2000 SP4で確認、2004-11-27)
ReadConsoleInput
SetConsoleModeでENABLE_MOUSE_INPUTを指定し、コンソールのプロパティで簡易編集を解除した状態では、ReadConsoleInputでマウスカーソルの位置を取得できる。
この位置は、Windows2000/XPならスクリーンバッファ内の座標に収まるが、WindowsNTではバッファ外の座標も入る(X, Y = -1, -1等)
(2005-11-26)
SHGetFileInfo
  • SHGFI_ICON のみを指定すると、SHFILEINFOの.hIconと.iIconにそれぞれ結果が返されるが、Desktop.ini等によるアイコン指定が無効になる。(2007-08-11)(勘違いだったようだ 2013-11-05)
  • SHGFI_ICON | SHGFI_SYSICONINDEX を指定すると、SHFILEINFOの.iIconは Desktop.ini等によるアイコン指定が反映されたイメージリストのインデックスが取得できる。ただし、ショートカットなどのオーバレイは反映されない。
    SHFILEINFOの.hIconにはオーバレイも反映されたアイコンが新規に作成され、格納される。
    (2007-08-11)
  • SHGFI_ICONを指定したとき、戻り値がtrueであっても.hIconがnullになることがある。Sleep(10)等で待ってから再取得すれば成功するようだ。
    (Windows7 SP1で確認、2013-11-05)
SHFileOperation
SHFileOperationの実行中に実行元のウィンドウを閉じてPostQuitMessageを実行しても、途中で止まって、場合によってはプロセスが残ったままになる。
このため、SHFileOperationの実行後、実行元のウィンドウを閉じたかどうかを確認し(例えば、IsWindow)、既に閉じていた場合はPostQuitMessageを再度実行する必要がある。
※SHFileOperationの実行中は、実行元の入力を抑制しない為、実行元のメッセージループが回る疑似バックグラウンド状態になる。
(2007-12-01)
UnhookWindowsHookEx
UnhookWindowsHookExを実行しただけでは、全てのプロセスにフックしたDLLは全て解放されない。これは、DLLが解放されるタイミングが該当プロセスでGetMessage等を呼び出したときだからである。このため、DLLをすぐに解放したいときは、UnhookWindowsHookExの後にPostMessage(HWND_BROADCAST, WM_NULL, 0, 0)を実行するとよい。
※SetWindowsHookExによりDLLがフックするタイミングもGetMessage等を呼び出したときと思われる。
(2008-08-24)
CreateDIBitmap
Windows7で、CreateDIBitmapで作成したビットマップへの部分描画(DrawIconEx, BitBlt等)を行うと、描画していない部分も書き換わる。
CreateDIBSectionを使ってビットマップを作成すれば問題ない。
(2011-07-23)
CreateSymbolicLink
Windows7で、TRUE であるにもかかわらず、失敗して ERROR_PRIVILEGE_NOT_HELD となっていることがある
(2014-11-08)
SetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc)
hWnd が NULL の場合のみ、ユーザーオブジェクト(ユーザーリソース)を1つ使用する。メッセージ処理用のWindowを内部で使用しているようだ。
このとき、lpTimerFunc に渡される ID は、nIDEvent ではなく、内部で作成された ID となる。このため、KillTimer に nIDEvent を渡してもタイマーを終了・破棄することができず、ユーザーオブジェクトを使用したままとなる。
(2023-09-23)
WM_xBUTTONUP
WM_xBUTTONDOWN
WM_xBUTTONDBLCLK
最小化時等でクライアント外の座標が渡されることがある。
(2000-09-02)
WM_MOUSEWHEEL
SendMessageによって呼ばれているようだ。
(2000-09-02)
WM_INITMENU
任意のメニュー/ポップアップメニューがアクティブになるときに発生する。また、一旦メニューループを抜けない限り再発生しない。具体例は次の通り。
  • TrackPopupMenuで任意メニューをアクティブにするとき
  • メニューバー上のメニューを非アクティブ時に選択/アクティブにしたとき
  • システムメニュー(タイトルバー左端をクリック、タイトルバーを右クリック、Alt+Spaceで出るメニュー)をアクティブにするとき
(2001-06-19)
メニューバーをアクティブにしたときに、WM_INITMENUのwParamで得られるメニューハンドルは、SetMenu() で設定/GetMenu()で得られるメニューハンドルと同じ値である。
システムメニューをアクティブにしたときも SetMenu() で設定したメニューハンドルと同じ値である。しかし、
(1)メニューバーがないときはWM_INITMENUでシステムメニューかどうかを判別する方法が用意されていないようだ。
(2)得られたメニューハンドルに対してWM_INITMENU内でModifyMenu()やSetMenuItemInfo()を行っても反映されない。
(DrawMenuBar()をWM_INITMENU内で実行しても反映されない。)
WM_INITMENU内であってもGetMenuState()で得たメニューハンドルに対して変更する必要があるが、WM_INITMENU内でGetMenuState()を実行すると異常終了するので、予めハンドルを用意する必要がある。
(2010-09-20)
WM_INITMENUPOPUP
任意のポップアップメニューがアクティブになるときに発生する。同じメニューループであってもアクティブになる度に発生する。 (2001-06-19)
EM_GETSEL
EM_SETSEL
EM_LIMITTEXT
EM_LINEINDEX
WindowsXP 以降でビジュアルスタイルの ANSI 版エディットボックスを開いているにも関らず、EM_GETSEL / EM_SETSEL / EM_LIMITTEXTで UNICODE 版の動作をする。
例えば、次のコードでは XP 以外では FALSE を返すが、XP では TRUE となる。
[WinXP] Common Control 6.0 の EM_LIMITTEXT による入力制限によれば仕様ということである。
(ビジュアルスタイルではANSI版/完全なANSI変換は提供せず、UNICODE版のみ提供のようだ)
また、エディットボックスが UNICODE版 の動作をするかは IsWindowUnicode を使えば判定できる。(2003-12-6)
※ Windows 8.1 で ANSI 版の動作をするようになった。(2017-12-30)(勘違いだった 2018-10-20)
BOOL CheckXPEditBox(void){
    DWORD lP, wP;
    HWND hWnd;
    BOOL result;

    hWnd = CreateWindowA("EDIT", "漢字", 0, 0, 0, 0, 0, NULL, NULL, hInstance, 0);
    ShowWindow(hWnd, SW_HIDE);

    SendMessageA(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
    SendMessageA(hWnd, EM_GETSEL, (WPARAM)&wP, (LPARAM)&lP);
    if ( GetWindowTextLengthA(hWnd) > (lP - wP) ){
        result = TRUE;
    }else{
        result = FALSE;
    }
    PostMessage(hWnd, WM_CLOSE, 0, 0);
    return result;
}
※キーボードフックを行うプログラムがあるときなど、
 このコードで検出できない状況もある。
(2003-12-06)
EM_SETSEL
無条件に文字列の末尾を指定する方法として -1 を指定するのが一般的だが、この値だと失敗することがあるようだ。正の最大値 0x7fffffff を使えば回避できるようだ。
manifest 適用 XPで、ANSI版エディットボックスを使用したときにこの現象を確認した
(2004-09-20)

特定機能関連

プロパティシート関連
  • アクティブ時にキーボードフォーカス移動ができない。→Ver5.0で対応
    (2000-09-02)
  • アクティブ時に内部でキーボードフォーカスの再設定が行われるが、その時、WM_COMMANDが生成されることがある。→これで状態取得を行っているとうまくいかない。特にラジオボタン
    (2000-09-02)
  • プロパティシートの大きさは、最初のページの大きさから決められる。
    最初のページのフォントが設定されていないとき、[OK]/[キャンセル]/[適用]等の場所を差し引いた大きさになり、
    環境によって余分な空白ができたり、一部のコントロールが隠れてしまうことがある。
    (2007-9-23)
RAS関連
RAS 関連の API が入った DLL を動的読込みする場合は RASAPI32.DLL を読込むことになると思うが、RASAPI32.DLLがあってもそれに関連する DLL がない場合があり、GetProcAddressが成功しても API の実行時に DLL の読込み失敗ダイアログが表示されることがある。
(2000-9-2)
Popup Menu
  • Popup Menu は表示中の PopupWindow の Window Class("#32768") ではなく、別のところで制御しているらしく、サブクラス化が困難な模様。また、メッセージループも内部で行っているため、大本のメッセージループではメッセージをつかまえることが困難。
     PopupMenuをマウスのホイールで選択できるかどうかを試していたのだか、このために挫折(^^;。
    (2001-2-4)
    フックはどうやらWH_MSGFILTERで対処するようだ(2010-8-8)
  • メニューテキスト中のタブ文字(\t)は、WindowsXP/2003まではインデント処理であるが、WindowsVista以降では両端揃えの区切りになる。
    ※インデント : タブより右の文字列が左揃え
    ※両端揃え : タブより左は左揃え、タブより右は右揃え
  • MF_MENUBARBREAK, MFT_MENUBARBREAK, MF_MENUBREAK, MFT_MENUBREAK を付けると複数段のメニューが作成できる。しかし、WindowsXP以降ではビジュアルスタイルが適用されず、しかも表示速度等が低下する。
    (2010-8-8)
Listbox
LBS_HASSTRINGS でないオーナードローのリスト ボックスは、LB_ADDSTRING等で任意の値を設定することができる。
 しかし、Windows XP 上では 0 等の値を使用すると正しくアイテムが格納されなくなる。
※SP1 で修正されている。
(2002-9-27)
FILETIME
西暦1601年 01/01 0:00:00(UTC)からの100ns単位の経過時間を表す。現在使われているグレゴリオ暦が1582年から使われているため、それに近くてきりのいい年から始めているようだ。
FILETIMEがオーバーフローを起こすのは西暦約60,000年である。
FILETIMEが 0x7fff ffff ffff ffff(西暦約30,800年)を越えるとSystemTimeToFileTime()でエラーになる。
日常使う時間の単位との換算は次の通り。
1秒10,000,0000x0098 9680
1分600,000,0000x23c3 4600
1時間36,000,000,0000x0008 61c4 6800
1日864,000,000,0000x00C9 2A69 C000
1980-1-1 00:00:00
(FAT, MS-DOSで扱える最初の日)
UTC : 0x01A8 E79F E1D5 8000
JST : 0x01A8 E754 71ED D800
2000-1-1 00:00:00UTC : 0x01BF 53EB 256D 4000
JST : 0x01BF 539F B585 9800

※うるう秒があるため現実の日時と上記値とのずれが生じる(1972年~2012年で25秒)。
※国際原子時(TAI)との差はうるう秒を含めて35秒ある。
(2012-07-07)
画面描画
WindowsXPで「ドラッグ中にウィンドウの内容を表示する」を有効にした状態でウィンドウをドラッグすると、その後ろのウィンドウに未描画部分が残ることがある。この現象は親ウィンドウのみ発生して、子ウィンドウでは発生しない。
(2004-12-18)
ウィンドウハンドルの有効チェック(IsWindow)
長時間スワップ時などの高負荷状態では、対象ウィンドウが存在するにもかかわらずウィンドウハンドルが無効の扱いとなり、IsWindow, SendMessage, SendMessageTimeout, GetWindowThreadProcessId等でエラーになる。
※詳細を調べていないが、LPCでやりとりしている雰囲気があるので、自プロセスのウィンドウハンドルなら有効のままだが、別プロセスのウィンドウハンドルが無効になると思われる。

このような高負荷状態でもウィンドウハンドルが有効かどうか判定する方法は、一般的なAPIにはない模様。(試していないが、ToolHelp32やPSAPI辺りを使って該当ウィンドウハンドルが一覧中にあるかどうかを判断すればできるかもしれない。ただし、コストは大きい。)

もし、該当ウィンドウを所有するプロセスが存在しているかどうかを知りたいために、ウィンドウハンドルの有効性を判断するなら、予めプロセスIDを取得して、これの有効性をOpenProcess等を用いて判断したほうが良さそうである。
(2006-04-29)
画面のスケーリング(デスクトップ上のテキストやその他の項目を縮小又は拡大)
マニフェスト、SetProcessDPIAware / SetProcessDpiAwareness で高DPI対応を宣言すると、ウィンドウのスケーリング処理が行われなくなる。
動的な画面スケーリングに対応していない物は次のとおり。これらは再ログインしないと変化しない。
※Windows10 1703(RS2, Creators Update)では、dpiAwarenessにPerMonitorV2が追加され、PerMonitorV2を指定するとこれらも動的変更されるようになった。
  • SystemParametersInfo, GetSystemMetrics, GetDeviceCaps … 変更前の値が維持される
  • メニュー … フォント大きさ、メニュー高さが変化しない。但しモニタ別のDPI変更には対応。
  • プロパティシート…DPI仮想化が有効になり、拡大縮小される
  • ダイアログ…フォント大きさが変化しない。
    ※PerMonitorV2指定時に動的変更するが、ダイアログのフォント指定が必要。
  • ボタン、ツールボックス、ツリー、ヘッダ等 … CCM_DPISCALEのSendMessageで対応する。但し、フォントや画像等を指定しているときは、これらの大きさを調整しないので、再指定する必要がある。Rebarのバンド幅も変更されない。
高DPI対応を宣言したプロセスで、SystemParametersInfo, GetSystemMetricsを使用して画面に関するサイズを得る場合は、「(取得値 * (GetDpiForMonitorやWM_DPICHANGEDで得たDPI)) / (GetDeviceCapsで得たDPI)」とすることで適切な値になる。
(2017-05-13)
ICCプロファイル付きビットマップとクリップボード
CF_DIBV5 を使って ICCプロファイル付きビットマップをクリップボードに SetClipboardData で格納した場合、CF_DIB によるクリップボードの取得が可能であるが、ICCプロファイル の分だけ画像がずれた形になる。
CF_DIB が CF_DIBV5 から BITMAPV5HEADER + ビットマップ + ICCプロファイル の形に誤変換してしまうためである。
このため、CF_DIBV5 を格納した後、BITMAPV5HEADER + ビットマップ の形で CF_DIB を追加格納すると、CF_DIB の画像のズレを抑えることができる。 ※ BITMAPINFOHEADER + ビットマップだと、CF_DIB が BITMAPV5HEADER のサイズで BITMAPINFOHEADER となる。
(Windows10 RS1で確認、2016-09-03)
コンソール
Windows10 1607(RS1, Anniversary Update)でエスケープシーケンスによる着色(16色)やカーソル操作が可能になった。
また、Windows10 1703(RS2, Creators Update)でフルカラー着色が可能になった。
但し、エスケープシーケンスによる着色を行うと、コンソールウィンドウの窓サイズが変更されると表示内容が全て失われる
(2017-5-13)
Windows Terminal
  • GetConsoleWindow で取得できるウィンドウ(PseudoConsoleWindow)は、表示に使われる Window ではない。
  • 以下の操作を行ったとき、画面最下行で一度に複数行を表示してもスクロールを行わず、一行分しか表示されない。
    GetConsoleScreenBufferInfoEx(hStdout, lpConsoleScreenBufferInfoEx);
    SetConsoleScreenBufferInfoEx(hStdout, lpConsoleScreenBufferInfoEx);
(2023-09-23)

プラットホーム(Win32/Win32c/Win32s)による動作違い関連

※Win32 は WindowsNT/2000/XP/2003、Win32c は Windows95/98/98SE/Me、Win32s は Windows3.1にWin32sを組み込んだ状態です。
GetWindowRect()
GetWindowPlacement()
  • Win32c では常に FALSE
  • Win32/Win32s は TRUE

(2000-9-2)
TimerProc()(SetTimer/WM_TIMER)
  • Win32/Win32s ではメッセージループを用意しなくても、モーダルダイアログボックスさえあれば、タイマーが動作する。
  • Win32cでは、モーダルダイアログのみだして、メッセージループを用意しない場合、タイマーが他のメッセージのついでにしか動作しなくなる。

(2000-9-2)
TrackPopupMenu()
TPM_RETURNCMD指定は、Win32sでは無効。
(2000-9-2)
戻り値は、Win32では32bit、Win32cでは16bitに丸められる。
(2004-11-20)
OpenFileMapping()
Win32cでは、名前付ファイルマッピングで既存のマップがないと作成してしまうようだ。
(2000-9-2)
SetClipboardData
Win32ではOSが元のクリップ内容を元に別の形式を自動作成する(ex)CF_TEXTからCF_UNICODETEXT)が、Win32cでは行われない
(2003-3-24)
EnableWindow(HWND hWnd, BOOL bEnable)
Windows95では bEnable は TRUE(1) FALSE(0) のみ解釈し、0, 1 以外の値では機能しない。
Windows2000では 0 か 0 以外で解釈する。
(2002-11-24)
MapDialogRect(HWND hwndDlg, LPRECT lprc)
Win32cでは、lprcの中身によってはDivideBy0例外が発生する。
(2006-04-29)
CallNextHookEx(HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)
パラメータにあるhhkは、Win32cではSetWindowsHookExの戻り値、Win32では最新の英語版MSDNでは、「Ignored.」になっている。
※一時期の英語版MSDNでは、Win32のみの記載になっていた。
(2007-04-21)
コンソール
Win32c上のコンソールは次の問題がある。
  • SetConsoleWindowInfo()等を用いて窓の大きさを大きくすると、DOS Appplication の実行時におかしくなる。
  • ReadConsoleInput()では、IMEによる漢字入力が使用できない。

(2000-9-2)
  • SetConsoleTextAttribute等で文字属性が指定できるが、COMMON_LVB_xxxx 系が画面に反映されない(PC, NEC98x1 にて確認)

(2001-2-4)
時間管理精度
インターバル処理をするために、最短はどの程度の間隔で行えるかを調べてみた。
※計測、制御、ゲーム目的ではないので、時間自体の精度や、最長呼び出し間隔等は考慮していない。
Windows95Windows98/MEWindowsNT系
(Workstation)
WindowsNT系
(Server)
Windows3.1+Win32s
(NEC PC9801)
Windows98
(NEC PC9801)
Sleep13ms5ms10ms15ms1ms5ms
Sleep
(timeBeginPeriod=1ms)
1ms1ms1ms1ms1ms1ms
timeGetTime1ms1ms10ms15ms1ms1ms
timeGetTime
(timeBeginPeriod=1ms)
1ms1ms1ms1ms1ms1ms
GetTickCount13ms5ms10ms15ms25ms5ms
GetTickCount
(timeBeginPeriod=1ms)
1ms1ms10ms15ms25ms1ms
SetTimer55ms55ms10ms15ms25ms25ms
SetTimer
(timeBeginPeriod=1ms)
55ms55ms10ms15ms25ms25ms
QueryPerformanceFrequency1,193,180Hz1,193,180Hz3,579,545Hz3,579,545Hz1,193,180Hz2,457,600Hz
※55ms は IBM-PC のインターバルタイマ(i8254)由来の値。1,193,180Hzの2の16乗分周値。
※13ms は 55ms の四分の一。1,193,180Hzの2の14乗分周値。
※1,193,180Hzは、IBM-PCのシステムタイマ(i8254)由来の値。3,579,545Hzの3分周値。
※3,579,545Hzは、ACPIタイマー由来の値。この周波数はテレビ放送のNTSCの色副搬送波周波数でもある(発振器が安く、入手しやすい)。
尚、これらの値は、OSが同じでも使用しているハードウェアによって異なる値になることがある。
また、計測値から求めた値であるため、実際とは異なる場合がある。
更に、常に同じ間隔で使えるわけではなく、スレッドのタイムスライス(20ms)等の要因で遅れることもある。このため、正確な間隔を期待してはいけない。
(Windowsでms単位の正確な時間管理を期待するのは、もともとそのようなリアルタイム重視の設計をしていないので見当違いである)
(2006-04-29)
ms 単位で正確な時間を管理する必要がある場合、正確な間隔で処理できることを期待したアルゴリズムを使わず、QueryPerformanceCounter, timeGetTime, GetTickCount 等を用いてより正確な時間差を求め、その時間差に応じた処理を行う必要がある。
また、各カウンタのオーバフローも考慮する必要がある。
(2004-4-11)
パラメータチェック
Win32ではAPIのパラメータチェックが厳密である。
例えば、フラグ指定のパラメータは、対応しているフラグ以外を指定するとエラーになる。また、内部にサイズ指定がある構造体は、厳密にサイズが一致しないとエラーになる(サイズを多めにしてもエラーになる)。ディレクトリパスを格納するバッファのサイズも32K以上を指定するとエラーになる。※32Kは「\\?\~」を用いたときの最大値
逆に、Win32c/Win32s はこれらのチェックがされていない。

これに関連して、新しいWindowsで追加されたフラグを指定する場合は、古いWindowsでエラーとなるため、どちらでも機能するようにするためにはバージョンによる場合分けが必要になる。
(2005-6-23)

UNICODE

WORD境界
一部のAPIは引数にUNICODE文字列を与えるときに、アラインメントをWORD境界に合わせないと意図する動作をしない。
  • MessageBoxW は、ウィンドウの幅計算が正しく行えなくなり、幅広になる。
  • TextOutW は、文字列の表示に失敗する。
  • RegQueryValueExW は、lpszSubKey の文字列が WORD 境界にあっていないと、値の取得に失敗する。
  • CreateMutexW は、エラーになる。

(2004-10-4)
DLL
ANSI前提のDLLをLoadLibraryWで読み込もうとすると、例外を発生する場合があるようだ。UNxxx.DLLやSusie Plug-inでLoadLibraryWではだめで、LoadLibraryAなら読める例がいくつかあった。
(2004-4-12)
Borland C++
BCC32 で UNICODE 文字列を使う場合に(個人的に?)問題となる挙動。
  • TextOutW(hWnd, 0, 0, L"Text", 4)等とした場合、L"Text"のWORD境界あわせをしてくれないため、APIによっては失敗したり異常動作したりする。
    (2004-4-11)
  • BCC32 5.0 では、1つのTEXT() マクロを使って複数行の文字列をまとめて指定すると、全てUNICODE文字列として扱う。
    (2004-11-20)

その他

TRUE/FALSE
BOOL 型のとき、FALSE で比較することは問題無いですが、TRUE で比較すると、TRUEのつもりで様々な真となる値を書いてしまったときに対処できません。
自分でも気をつけているはずだったのですが、ふと grep をかけると、かなりの場所で TRUE で比較してました(^^;。
自信があっても定期的に調べることが大切ですね。
(2000-12-21)
WINMM.DLL / sndPlaySound
sndPlaySound か WINMM.DLL 自体かは調べていないが、WINMM.DLL のロードは秒単位で待たされる場合がある
(2001-2-4)
バッファのチェック
WindowsXP SP2以降で、バッファとそのサイズをパラメータとして指定するAPIは、そのサイズの範囲内でバッファが有効であるかのチェックがされる。つまり、指定したバッファにサイズ分のページが割り当てられていない場合は、エラーになる。
(2008-9-21)

Homeへ戻る
Copyright(c)1997-2017 TORO/高橋 良和 E-mail: toroid.jp @​gmail.com
access counter用
TORO's Library

Software

 Windows
  PPx
  DLL,SusiePlugin
 MS-DOS
 SHARP PC-E500

Hardware

 SHARP PC-E500

Data

 Information
  PPx Help
 DOS 上で LFN
 Source
 Config Memo
 Win32 API memo

Message Board

 Software