extendsでクラスの継承が出来る。
extends.phpで、
BaseClassを継承したDerivedClassを用意し、BaseClassのメンバも使えるか試す。
DerivedClassからも、BaseClassのメンバを使えた。
Sample/php/class/extends/src/class at master · bg1bgst333/Sample · GitHub
extendsでクラスの継承が出来る。
extends.phpで、
BaseClassを継承したDerivedClassを用意し、BaseClassのメンバも使えるか試す。
DerivedClassからも、BaseClassのメンバを使えた。
Sample/php/class/extends/src/class at master · bg1bgst333/Sample · GitHub
CREATESTRUCTは、CreateWindowによってWM_CREATEが呼ばれた時に、ウィンドウ作成情報を格納している構造体。
CREATESTRUCTA (winuser.h) - Win32 apps | Microsoft Docs
WM_CREATEのlParamは、CREATESTRUCTへのポインタにキャストでき、ウィンドウ作成情報が格納されている。
Window.hで、
ウィンドウ名m_wstrWindowNameを持ち、ウィンドウハンドルをキーとし、CWindowオブジェクトポインタを値とするマップm_mapWindowMapもある。
メンバのWindowProcにウィンドウメッセージ処理を書く。
Window.cppでは、
WM_DESTROYで、ウィンドウ名をメッセージボックス出力するぐらい。
あとはDefWindowProcに任せる。
CREATESTRUCT.cppで、
2つのウィンドウを作成する。
ウィンドウ名を"Window1", "Window2", とし、それぞれCWindowオブジェクトを作成し、そのポインタをCreateWindowの最後の引数に渡す。
WM_CREATEなら、lParamからlpCreateStructを取り出し、lpCreateStruct->lpCreateParamsで、CWindowオブジェクトポインタpWindowを取り出す。
pWindowは、ウィンドウ名m_wstrWindowNameも持っているので、そこにlpCreateStruct->lpszNameをセットする。
hwndをキー、pWindowを値として、ウィンドウマップに登録。
WM_CREATE以外なら、ウィンドウマップからpWindowを取得する。
pWindowが無い場合は、DefWindowProcを呼ぶ。
pWindowがある場合は、pWindow->WindowProcを呼ぶ。
2つのウィンドウが表示。
Window1を閉じると、
WM_DESTROYのウィンドウ名表示にWindow1と出る。
最初からやり直して、今度はWindow2を閉じる。
Window2が出る。
それぞれのウィンドウごとに、CWindowオブジェクトを割り当てて、内部の状態も独立して別に持てるし、ウィンドウプロシージャも別々にすることができそう。
Sample/winapi/CREATESTRUCT/CREATESTRUCT/src/CREATESTRUCT at master · bg1bgst333/Sample · GitHub
Task.ContinueWithで、完了した時に実行する継続タスクを指定する。
Task.ContinueWith メソッド (System.Threading.Tasks) | Microsoft Docs
[雑記] スレッド プールとタスク - C# によるプログラミング入門 | ++C++; // 未確認飛行 C
MainClass.csで、
t.ContinueWithで、コンソールでx.Resultを出力するラムダ式を指定。
xはタスクtであり、x.Resultは、tで指定したラムダ式の戻り値。
Funcは5秒の処理で、メインスレッドが先に終わらないように10秒待っている。
実行開始時。
5秒で結果出力の継続タスク。
10秒で完全終了。
Sample/dotnet/Task/ContinueWith/src/Task_ at master · bg1bgst333/Sample · GitHub
Activity.onSaveInstanceStateで保存したデータは、Activity.onRestoreInstanceStateが呼ばれた時に復元する。
Activity | Android デベロッパー | Android Developers
MainActivity.javaで、
onRestoreInstanceStateの中で、inState.getStringにKEY_TEXTVIEW1_STRINGを指定して取得したtextを、textview1にセット。
起動時の状態。
button1以外はない。
button1を押すと、
"ABCDE"がセットされる。
Ctrl+F11を押すと、
横向きになるが、"ABCDE"は表示されたまま。
きちんと保存と復元が効いている。
Sample/android/Activity/onRestoreInstanceState/src/Activity at master · bg1bgst333/Sample · GitHub
赤外線通信において、接続相手の情報などは、accept時などにSOCKADDR_IRDA形式で格納される。
SOCKADDR_IRDA (af_irda.h) - Win32 apps | Microsoft Docs
ここから本格的に赤外線通信をしていくが、まずは準備など。
この日のために、数年前から中古で買っておいたSTOLA。
ようやく今日、日の目を見る。
そしてSigmatelのIrDAドングル。
最後の1本。
もうおそらく製造も販売もしていない。
壊れやすいので、これが壊れたら終わり。
ひたすらアドレス帳に登録していく。
もちろん架空の情報を。
当初はここを参考にWindows10で準備。
この時点で赤外線はない。
コマンドプロンプトの管理者実行。
Microsoft Windows [Version 10.0.18363.900] (c) 2019 Microsoft Corporation. All rights reserved. C:\WINDOWS\system32>netcfg -u ms_irdanetcfg -c p -I ms_irda ms_irdanetcfg をアンインストールしようとしています ... ... ms_irdanetcfg はインストールされていません。 ... 完了しました。 ms_irda をインストールしようとしています ... ... 失敗しました。エラー コード: 0x80070002。 C:\WINDOWS\system32>
なぜか失敗。
PowerShellでやり直す。
PS C:\WINDOWS\system32> get-WindowsCapability -online -Name "Network.Irda~~~~0.0.1.0" Name : Network.Irda~~~~0.0.1.0 State : NotPresent DisplayName : IrDA 赤外線 Description : IrDA デバイスのサポート。特別な IrDA ハードウェアが必要です。 DownloadSize : 604101 InstallSize : 1236233 PS C:\WINDOWS\system32>
して、
PS C:\WINDOWS\system32> Remove-WindowsCapability -online -Name "Network.Irda~~~~0.0.1.0" Path : Online : True RestartNeeded : False PS C:\WINDOWS\system32>
して、
PS C:\WINDOWS\system32> add-WindowsCapability -online -Name "Network.Irda~~~~0.0.1.0" Path : Online : True RestartNeeded : False PS C:\WINDOWS\system32>
これはかかった。
そして、
PS C:\WINDOWS\system32> get-WindowsCapability -online -Name "Network.Irda~~~~0.0.1.0" Name : Network.Irda~~~~0.0.1.0 State : Installed DisplayName : IrDA 赤外線 Description : IrDA デバイスのサポート。特別な IrDA ハードウェアが必要です。 DownloadSize : 604101 InstallSize : 1236233 PS C:\WINDOWS\system32>
これで使えるのでは。
赤外線が出現。
クリックして設定。
保存先を変更。
ドングルを接続していない時はこうなる。
接続しているとこうなる。
設定の変更とかよくやるけど効果なし。
(9660にすると受信しやすいとか昔あったけどなあ。)
STOLAから1件のアドレス送信をずっと試してたけど、どうも現在のWindows10だと反応もしない。
Windows7だと反応した。
ドライバかな・・・。
(Windows7は以前からドライバのインストールとか既に準備済みだった模様。
Windows10の初期のドライバを入れていても、Windows10の最近のバージョンで動くかは不明だし。)
STOLAで赤外線受信にするとPCから送信するための画面も出る。
(この時irftpが出るのかな。)
というわけでなんとか標準の赤外線通信はできそう。
ただし、全件送信時の認証には対応してなかった気がするので1つずつだけ。
さて、これをどうやってプログラムで実現するか。
// ヘッダファイルのインクルード #include <tchar.h> // TCHAR型 #include <winsock2.h> // Windowsソケット #include <windows.h> // 標準WindowsAPI #include <af_irda.h> // IrDA // _tmain関数の定義 int _tmain(int argc, TCHAR *argv[]){ // main関数のTCHAR版. // 変数の宣言と初期化. WSADATA wsaData; // WinSockの初期化に必要なWSADATA構造体変数wsaData. int iRet; // WSAStartupの結果を格納するiRet. int soc; // ソケットsoc. int iBind; // バインド結果iBind. SOCKADDR_IRDA soc_addr = {AF_IRDA, 0, 0, 0, 0, "OBEX"}; // soc_addrをこのように初期化. // WinSockの初期化. iRet = WSAStartup(MAKEWORD(2,2), &wsaData); // WSAStartupでWinSockの初期化. if (iRet == 0){ // 0なら成功. // 結果成功の出力. _tprintf(_T("WSAStartup success!\n")); // "WSAStartup success!"を出力. // 赤外線ソケットの作成. soc = socket(AF_IRDA, SOCK_STREAM, 0); // socketでAF_IRDAなsocを作成. if (soc != INVALID_SOCKET){ // INVALID_SOCKETでない時. // ソケットディスクリプタを出力. _tprintf(_T("soc = %d\n"), soc); // socを出力. // バインド iBind = bind(soc, (const struct sockaddr *)&soc_addr, sizeof(SOCKADDR_IRDA)); // bindでsocにsoc_addrをバインド. if (iBind != SOCKET_ERROR){ // SOCKET_ERRORでなければ. // 結果成功の出力. _tprintf(_T("bind success!\n")); // "bind success!"と出力. } else{ // SOCKET_ERROR. // 結果失敗の出力. _tprintf(_T("bind failed!\n")); // "bind failed!"と出力. } // socを閉じる. closesocket(soc); // closesocketでsocを閉じる. } // 終了処理. WSACleanup(); // WSACleanupで終了処理. } // プログラムの終了. return 0; }
SOCKADDR_IRDAのsoc_addrを上記のように初期化し、バインドしてみる。
WSAStartup success! soc = 128 bind failed! 続行するには何かキーを押してください . . .
失敗する。
標準の"Irmon"が邪魔しているからだ。
Irmonを停止させる。
停止状態。
こうすると、
WSAStartup success! soc = 128 bind success! 続行するには何かキーを押してください . . .
バインド成功。
(なのでサービス停止とかを扱ったが、プログラムでやる必要もなくなった。
また、PCが送信側の場合はirftpプロセスが邪魔になった記憶があった気がしたので、
プロセス制御も扱ったが、この先で使うことはなかったので、勘違いだったかもしれない。)
ひとまずこの部分をクリアしたので、
// 赤外線ソケットの作成. soc = socket(AF_IRDA, SOCK_STREAM, 0); // socketでAF_IRDAなsocを作成. if (soc != INVALID_SOCKET){ // INVALID_SOCKETでない時. // ソケットディスクリプタを出力. _tprintf(_T("soc = %d\n"), soc); // socを出力. // バインド iBind = bind(soc, (const struct sockaddr *)&soc_addr, sizeof(SOCKADDR_IRDA)); // bindでsocにsoc_addrをバインド. if (iBind != SOCKET_ERROR){ // SOCKET_ERRORでなければ. // 結果成功の出力. _tprintf(_T("bind success!\n")); // "bind success!"と出力. // リッスン iListen = listen(soc, 1); // listenで1つ待ち受ける. if (iListen != SOCKET_ERROR){ // SOCKET_ERRORでなければ. // 結果成功の出力. _tprintf(_T("listen success!\n")); // "listen success!"と出力. // アクセプト acc = accept(soc, (struct sockaddr *)&acc_addr, &acc_addr_len); // acceptで待ち受けて, アクセプトソケットをaccに格納. if (soc != INVALID_SOCKET){ // INVALID_SOCKETでない時. // アクセプトソケットディスクリプタやアドレス情報を出力. _tprintf(_T("acc = %d\n"), acc); // accを出力. _tprintf(_T("acc_addr.irdaAddressFamily = %hu\n"), acc_addr.irdaAddressFamily); // acc_addr.irdaAddressFamilyを出力. _tprintf(_T("acc_addr.irdaDeviceID = %02X %02X %02X %02X\n"), acc_addr.irdaDeviceID[3], acc_addr.irdaDeviceID[2], acc_addr.irdaDeviceID[1], acc_addr.irdaDeviceID[0]); // acc_addr.irdaDeviceIDを出力. iServerNameLen = MultiByteToWideChar(CP_ACP, 0, acc_addr.irdaServiceName, -1, NULL, 0); // MultiByteToWideCharで長さを取得. MultiByteToWideChar(CP_ACP, 0, acc_addr.irdaServiceName, -1, tszServerName, iServerNameLen); // MultiByteToWideCharで変換. _tprintf(_T("acc_addr.irdaServiceName = %s\n"), tszServerName); // tszServerNameを出力. // accを閉じる. closesocket(acc); // closesocketでaccを閉じる. } } else{ // SOCKET_ERROR. // 結果失敗の出力. _tprintf(_T("listen failed!\n")); // "listen failed!"と出力. } } else{ // SOCKET_ERROR. // 結果失敗の出力. _tprintf(_T("bind failed!\n")); // "bind failed!"と出力. } // socを閉じる. closesocket(soc); // closesocketでsocを閉じる. }
接続先情報を出力する。
C# + .NET Frameworkで赤外線通信をする時は、32feet.NETを使うだろう。
これのIrDA Clientのサンプルをビルドして起動すると、
16進数8桁のDeviceIDが出ると思う。
これと同じものが、上のコンソールプログラムでも、
WSAStartup success! soc = 128 bind success! listen success! acc = 132 acc_addr.irdaAddressFamily = 26 acc_addr.irdaDeviceID = CB 42 06 90 acc_addr.irdaServiceName = LSAP-SEL2 続行するには何かキーを押してください . . .
出る。
残念ながらSTOLAは毎回DeviceIDが変更される仕組みになっている模様。
DeviceIDは固定の端末もある。
(1度だけスクショと同じIDが出た時があったのだが、スクショし忘れる失態・・・。)
さて、ここまで来たら、あとは赤外線通信をするだけだ。
https://www.ttc.or.jp/application/files/5015/5417/2604/JF-IR007.10v2.pdf
ここに赤外線通信仕様がある。
(以前のURLリンクから変わった模様。)
PDFにおける66ページ目に例があるので、それを参考にするといい。
最低限、1件のアドレスを受信できるプログラムを作った。
(いろいろ実装すると大変なのであくまで最低限。)
結果はこんな感じ。
鈴木一郎.vcfが保存されてる。
こんな感じのvCardが送られてくる。
いやはや、WinSockでこれをやるのは大変。
32feet.NETもたいして変わらないけど、これよりはマシ。
Sample/winapi/SOCKADDR_IRDA/SOCKADDR_IRDA/src/SOCKADDR_IRDA at master · bg1bgst333/Sample · GitHub
ここまでサービス制御やプロセス制御についてやってきたのも、赤外線通信をするため。
まずは、赤外線通信用のソケットをAF_IRDAを指定して作成する。
IrDA and socket | Microsoft Docs
基本的にWinSockを使うので、ws2_32.libをリンク。
実行すると、
WSAStartup success! soc = 128 続行するには何かキーを押してください . . .
ソケット自体は、何もしなくても作れる。
Sample/winapi/AF_IRDA/AF_IRDA/src/AF_IRDA at master · bg1bgst333/Sample · GitHub
PathStripPathで、パスからファイル名部分を取り出す。
PathStripPathA function (shlwapi.h) - Win32 apps | Microsoft Docs
WindowsAPIPath
GetFileTitleとかやり方はいくつかあるけど、コンソールアプリならshlwapi.lib系のほうが何かと近そうなので。
(GetFileTitleはcomdlg32.libなのでウィンドウアプリ系っぽい。)
shlwapi.libをリンク。
ファイル、フォルダ、それからドライブルートフォルダだけの場合、そしてデバイス形式の場合どうなるか。
tszFilePath = test.txt tszFolderPath = folder tszDrivePath = C: tszDeviceName = explorer.exe 続行するには何かキーを押してください . . .
ルートフォルダだとドライブレターだけになるし、デバイス形式でもファイル名を取ることが出来た。
Sample/winapi/PathStripPath/PathStripPath/src/PathStripPath at master · bg1bgst333/Sample · GitHub