ぷるぷるの雑記

低レイヤーがんばるぞいなブログ. 記事のご利用は自己責任で.

WindowsのコンソールアプリケーションでGetMessageを使わずにタイマーを使う

メッセージループを自分で書かずにWindowsのコンソールアプリケーションでタイマーを使う方法が無いか調べたところ、 CreateTimerQueueTimer関数 というものを見つけました.

以下プログラムは、約100msごとにHelloという文字列がコンソールに表示されます.

#include <iostream>
#include <Windows.h>

using namespace std;

/* メインスレッド */
void Loop();

/* コールバック */
void CALLBACK OnTimer(PVOID lpParameter, BOOLEAN TimerOrWaitFired);

HANDLE hEvent;
HANDLE hTimer;

int main()
{
    hEvent = CreateEventW(
        NULL,               /* セキュリティ属性   */
        FALSE,              /* 手動リセットオフ   */ 
        TRUE,               /* 初期状態          */
        (LPCWSTR)"PROC1"    /* イベント名        */
    );

    CreateTimerQueueTimer(
        &hTimer,            /* タイマーハンドル             */
        NULL,               /* タイマーキューへのハンドル   */
        OnTimer,            /* コールバック関数             */
        NULL,               /* コールバックに渡すパラメタ   */
        0,                  /* 初めて発火するまでの時間     */
        100,                /* 発火のインターバル           */
        WT_EXECUTEDEFAULT   /* タイマーの種々の設定         */
    );

    Loop();
}

void Loop()
{
    while (1) {
        
        /* 手動リセットオフなので自動的に非シグナル状態になる   */
        WaitForSingleObject(hEvent, INFINITE);
        cout << "Hello" << endl;

    }

}

void CALLBACK OnTimer(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
    SetEvent(hEvent);
}

参考

stackoverflow.com

learn.microsoft.com

Visual Studioがフォルダを移動してもビルドできる仕組み

Visual Studioで作成したソリューションやプロジェクトはフォルダごと場所を移動してもIDE上で正しくビルドすることが出来ます.

ということはパスが自動的に解決されていることになりますが、その仕組みを簡単にまとめました.

プロジェクトのマクロが関わってくるので、必要であれば以下の記事も参考にしてください.

prupru-prune.hatenablog.com

検証バージョン

項目 バージョン
Visual Studio 2017

ソリューションフォルダを移動した場合

ソリューションやプロジェクトのディレクトリを表すマクロは以下になります.

マクロ 説明
$(ProjectDir) プロジェクトのディレクト
$(SolutionDir) ソリューションのディレクト


また、デフォルト時に上記のマクロを参照しているマクロには次のようなものがあります.

マクロ 説明 デフォルト値
$(OutDir) 生成物の出力先 $(SolutionDir)$(Configuration)\
$(IntDir) 中間ファイルの出力ディレクト $(Configuration)\ *1
$(TargetPath) プライマリ出力ファイルへの絶対パス. $(OutDir)$(TargetName)$(TargetExt)
$(TLogLocation) tlogファイルの出力先ディレクト $(IntDir)$(MSBuildProjectName).log


実は$(ProjectDir)と$(SolutionDir)は .slnファイルをIDEで開いた時に自動的に解決されます(.slnファイルへのパスを自動的に認識してマクロに反映してくれるっぽい). したがってその他のプロパティもデフォルトの時、 ソリューションフォルダを移動しようがビルドの生成物の出力先は相対的に不変です.

プロジェクトだけを移動した場合

Visual Studioで作成したプロジェクトは、そのプロジェクト単体でビルドすることが出来ます. つまり、ディレクトリに.slnファイルが存在する必要はありません. プロジェクト単体で立ち上げようと.vcxprojファイルをIDEで開いた時、 .vcxprojファイルと同じパスに仮想的な.slnファイルがあるような振る舞いをします. .vcxprojファイルをIDEで開いた時のソリューションエクスプローラーをみるとそんな感じの振る舞いをしていることが分かります.

言い換えると、 $(ProjectDir)と$(SolutionDir)が同じ値になります.

プロジェクト単体のソリューションエクスプローラー. 仮想的なソリューションが出来ている.

ただし、 .vcxprojファイルの直上ディレクトリにそのプロジェクトをインポートしている.slnファイルがある場合は、.slnファイルをIDEで開いた時と同じ振る舞いになります .

マクロ以外の部分

プロパティに設定する値はマクロと固定値を組み合わせることが出来ます. IDEからプロパティを変更すると.vcxprojファイルに対応するプロパティが追記されます. 例えばプロジェクトプロパティの出力ディレクトリを変更すると、.vcxprojファイル上にOutDirプロパティが追加されます.

デフォルト時の.vcxprojファイル

出力ディレクトリを指定した.vcxprojファイル

このような場合はマクロの部分は自動的に解決されつつ、ユーザーが定義した値も反映されます. ソリューションフォルダを移動してもビルドできるようにするために、相対パスで指定しておくのが無難です.

これだけまとめ

  • ビルドに関するパスを自動的に解決されるマクロ+相対パスで指定しているならフォルダを移動しても正しくビルドできる
  • .vcxprojファイルをIDEで開いた時、直上ディレクトリにそのプロジェクトをインポートしている.slnファイルがある場合は.slnファイルを開いた時と同じ振る舞いをする
  • .vcxprojファイルをIDEで開いた時、直上ディレクトリにそのプロジェクトをインポートしている.slnファイルがない場合は仮想的な.slnファイルが.vcxprojファイルと同じ場所に生成されると考える.

*1:暗に$(ProjectDir)を参照している

Visual Studioのプロパティの主なマクロ

Visual Studioはマクロ(≒環境変数)を使用してビルドを行います. このマクロのうち重要そうなものをピックアップしました. バージョンはVS2017を対象にしていますが、最近のVSであれば大きく変わることはないはず.

相対パスで書かれたものは $(ProjectDir) を基準にする様子.

マクロ 具体例 説明
$(CharacterSet) Unicode 使用する文字セット
$(CLRSupport) true/false マネージドコードかどうか
$(ComSpec) C:\WINDOWS\system32\cmd.exe 使用するシェル
$(Configuration) Debug 現在のプロジェクト構成の名前
$(ConfigurationType) Application プロジェクトの生成物の種別を表す
$(DevEnvDir) C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\ Visual Studioのインストールディレクト
$(ExtensionsToDeleteOnClean) .obj;.pdb;(略) プロジェクトのクリーン時に削除するファイル
$(IncludePath) C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include;(略) コンパイル時にヘッダファイルを検索するフォルダ
$(IntDir) Debug\ 中間ファイルの出力ディレクトリ. $(IntermediateOutputPath)のエイリアス
$(LibraryPath) C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\lib;(略) リンク時にオブジェクトを検索するフォルダ
$(OutDir) C:\Users\User_name\source\repos\Solution_name\Debug 生成物の出力先
$(OutputPath) C:\Users\User_name\source\repos\Solution_name\Debug $(OutDir)との違いが不明
$(Platform) Win32 現在のプロジェクトプラットフォームの名前
$(PlatformShortName) x86 現在のアーキテクチャの短い名前
$(ProjectDir) C:\Users\User_name\source\repos\Solution_name\Debug\Project_name\ プロジェクトのディレクト
$(ProjectGuid) AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE プロジェクトのGUID
$(ProjectName) Project_name プロジェクトの名前
$(SolutionDir) C:\Users\User_name\source\repos\Solution_name\ ソリューションのディレクト
$(SolutionName) Solution_name ソリューションの名前
$(TargetDir) C:\Users\User_name\source\repos\Solution_name\Debug\ ビルドのプライマリ出力ファイルのディレクト
$(TargetExt) .exe ビルドのプライマリ出力ファイルの拡張子
$(TargetFileName) Project_name.exe ビルドのプライマリ出力ファイルの名前(拡張子付き)
$(TargetName) Project_name ビルドのプライマリ出力ファイルの名前(拡張子なし)
$(TargetPath) C:\Users\User_name\source\repos\Solution_name\Debug\Project_name.exe ビルドのプライマリ出力ファイルの絶対パス
$(TLogLocation) Debug\MapTest.tlog\ tlogファイルの出力ディレクトリ.
$(windir) C:\WINDOWS システムのフォルダ

参考

learn.microsoft.com

learn.microsoft.com

2024年の目標

2024年今年の目標をば.

情報処理安全確保支援士試験に合格する

基本情報と応用情報は2023年に合格したので、この勢いで高度試験も1つくらい取るつもりです.

本当に取りたいのはエンベデッドシステムスペシャリストなのですが、秋試験しかないので春試験で情報処理安全確保支援士試験でも受けようかと思っています.

SOPをはんだづけできるようにする

そのまんま. とりあえずDIPよりもピッチが小さい表面実装ができるようになりたい.

体を動かす習慣を身に着ける

運動しなさ過ぎて体を動かすとすぐ筋肉痛になってしまうので、多少は体を動かしたいです.

3人以上知り合いを増やす

知り合いの定義にもよりますが、会社以外の知り合いを増やしたい.

CHで始まるIC

Jiangsu Qin Heng (WCH) 社のCHから始まる代表的なICをまとめてみた.

CH340シリーズ

末尾にアルファベットが付き、パッケージや追加機能が区別される. 次の機能がある.

  • USB-UART変換
  • USB-パラレルプリンタ変換

回路実装済みボードも多く販売されているが、チップ単体も比較的入手しやすい.

代表的なCH340x
名称パッケージコメント
CH340GSOP-16一番よく目にする
CH340BSOP-16内蔵EEPROMを書き換えて設定を変更できる.
CH340RSSOP-16IrDA対応

CH341シリーズ

CH340シリーズのパワーアップ版. 末尾にアルファベットが付き、パッケージや追加機能が区別される. 種類にもよるが次の機能がある.

  • USB-UART変換
  • USB-パラレルプリンタ変換
  • USB-パラレル(EPP/MEM)変換
  • USB-同期式シリアル変換(I2CやSPI)

EPP/MEMパラレルポートというのが謎だが、EPPはおそらくEnhanced Parallel Portの略かと思われる. MEMパラレルポートは何かわからない.

なぜかチップ単体での販売はあまりなく、回路実装済みボードとして販売されていることがほとんど.

代表的なCH341x
名称パッケージコメント
CH341ASOP-28一番よく目にする. すべての機能を有する
CH341TSSOP-20USB-UART/USB-I2C変換ができる
CH341HSSOP-20USB/SPI変換ができる

CH55xシリーズ

Intel8051の互換MCUで、オリジナルの機能に加え拡張機能が搭載されている.

(オリジナルのIntel8051が発売した時には存在しない)USBを含むペリフェラルを一通り持っている.

代表的なCH55x
名称パッケージコメント
CH551GSOP-16エントリモデル的な感じ?
CH552EMSOP-20
CH552TTSSOP-20CH552Eより機能が豊富

ja.wikipedia.org

tech-blog.cerevo.com

www.slideshare.net

qiita.com

CH32Vシリーズ

32ビットのRISC-Vマイコン. なんやかんやJiangsu Qin Heng (WCH) 社のICとして最初に知ったICかもしれない. 安いものは1個50円もしない.

代表的なCH32Vx
名称パッケージコメント
CH32V003J4M6SOP-8秋月で一個40円. USBは無し.
CH32V305FBP6TSSOP-20秋月で一個350円. クロック144MHz. USB有り.

kanpapa.com

その他

CH344シリーズ

USBの信号を4ポートのUARTへ変換するIC.

CH347シリーズ

CH340シリーズの強化版. USB-UART変換、USB-SPI/I2C変換、USB-JTAG変換が可能なIC.

CH348シリーズ

USBの信号を8ポートのUARTへ変換するIC.

CH376シリーズ

USBメモリやSDカード内のファイルを読み書きできるようになるIC. CMD_RD_USB_DATA0 や CMD_SET_FILE_NAME などを発行することでMCUからファイルシステムを使えるようになるらしい. すごい(小並感).

CH390シリーズ

イーサネットコントローラ. MACとPHYを内蔵.

CH9141シリーズ

BLE(Bluetooth Low Energy)-UART変換IC.

まとめ

調べてみるといろいろなICを出していた.

DLLがあるのに見つからない

DLLを利用するEXEを実行したところ、プログラムと同じフォルダにDLLがあるにも関わらずDLL周りのエラーが生じることがありました.

原因はEXEが利用するDLLがさらにほかのDLLを参照していたことでした.

つまり、EXE --(use)--> DLL1 --(use)--> DLL2 という関係の時、EXEとDLL1は同じフォルダにあるものの、DLL2が不足していたということになります.

また、このような状況の時にもエラーの原因がわかるように、DLLを利用するときは必ずエラーハンドリングを忘れずに書きましょう.