はじまり 前回に続いて、Rust言語でWin32APIを使ってみたメモ。 $ rustup default nightlyを実行してnightl版にしておく必要がある。 Win32APIのEnumWinodws()がコールバック関数を引数に持つので、Rust言語で どういう記述になるのかを実際に書いてみた。GUI用のマクロ #![windows_subsystem = "windows"] は、今回不要なものの残してある。特に害はない。 気づいた点: (1) グローバル変数名は大文字に強要される様だ。 orz これだと定数との区別が?になる。 callBackProc()の動作: (1) タイトル中に不要な文字列(Default、MSCTFIME)を持つアプリは無視し、 それ以外の起動中のアプリのタイトル名を表示する。 (2) この例の場合、最後に見つかったアプリのウインドウハンドル(HANDLE_APP)が取得できるので それを使っていろいろできる。 実行結果: コマンドラインで実行すると起動中のアプリのタイトル文字をつらつらと表示する。 src/main.rs/* * Windows File open dialog demo. * rustc 1.25.0-nightly (6828cf901 2018-01-06) * This file must be saved as UTF-8 format. * * 2018/01/13 by audin */ #![windows_subsystem = "windows"] extern crate winapi; extern crate user32; /* usnused use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; use std::iter::once; */ use std::ptr::null_mut; use std::result; use winapi::um::winuser::*; use winapi::shared::windef::*; use winapi::shared::minwindef::*; const SZW_SIZE_MAX: usize = 512; // Type alias to simplify representation. type Result<T> = result::Result<T,String>; type TSzwBuf = [u16; SZW_SIZE_MAX]; static mut SZW_BUF: TSzwBuf = [0; SZW_SIZE_MAX]; // Convert from TSzwBuf([u16;512]) to String type. fn szw_to_string( szwbuf: &TSzwBuf ) -> Result<String> { szwbuf.iter() .position(|wch| wch == &0) .ok_or("String : Can't find zero terminator !".to_owned()) .and_then(|ix| String::from_utf16( &szwbuf[..ix] ) .map_err(|e| e.to_string())) } // Convert from String to Vec<u16> with trailing \0. /* unused function fn str_to_szw(str_body: &str) -> Vec<u16> { return OsStr::new(str_body) .encode_wide() .chain(once(0)) // 終端文字\0を追加 .collect::<Vec<u16>>(); } */ static mut HANDLE_APP: HWND = null_mut(); #[allow(non_snake_case)] unsafe extern "system" fn callBackProc( hWnd: HWND, _lparam: LPARAM) -> BOOL{ GetWindowTextW( hWnd, SZW_BUF.as_mut_ptr(), SZW_BUF.len() as i32); if let Ok(sTitle) = szw_to_string( &SZW_BUF ) { if sTitle.len() > 0 { if (None != sTitle.find("Default")) || (None!=sTitle.find("MSCTFIME")) { // Eliminate verbose stings } else { // Result in HANDLE_APP is equal to the Window handle of a last application found. HANDLE_APP = hWnd; println!("{}",sTitle); // List up application tilte with UTF-8 string. } } }; TRUE // Continue enumeration to find a next Window activating. } fn main() { unsafe { EnumWindows( Some(callBackProc), 0); if HANDLE_APP != null_mut() { // Some codes using Window handle } } }tomlファイルには前回に加えて「windef」と「minwindef」を追加した。 「commdlg」は未使用だけど残した。 Cargo.toml[package] name = "enumwindows" version = "0.1.0" authors = ["audin"] [dependencies] user32-sys="0.2.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.3", features = ["winuser","commdlg","windef","minwindef"] }
2018年01月08日
Rust言語:Win32api:: EnumWinodwsのメモ 2018
2018年01月07日
Rust言語でWin32apiしてみたメモ 2018
はじまり Rust言語の練習のためWin32APIのファイルオープンダイアログを起動する 簡単なソフトを作ってみたメモ。 Rust winapiのページ https://github.com/retep998/winapi-rs 今時、Win32API直たたきはアレだけど、一応やってみた。 ./target/debug/win32_fopen_dlg.exe or ./target/release/win32_fopen_dlg.exe をコマンドラインから実行してファイルを選択すると、ファイル名を表示するだけ。 ファイル未選択でキャンセルすると別なメッセージが出るだけ。 なソフト。 以下のソースコードは日本語を含むので「UTF-8」で保存する必要がある。 src/main.rs/* * Windows File open dialog demo. * rustc 1.22.1 (05e2e1c41 2017-11-22): stable. * This file must be saved as UTF-8 format. * * 2018/01/02 by audin */ #![windows_subsystem = "windows"] extern crate winapi; extern crate user32; use std::env; use std::ffi::OsStr; use std::iter::once; use std::os::windows::ffi::OsStrExt; use std::ptr::null_mut; use std::mem::size_of; use winapi::um::commdlg::{OPENFILENAMEW, OFN_HIDEREADONLY}; use winapi::um::commdlg::GetOpenFileNameW; use std::result; const SZW_SIZE: usize = 512; // Type alias to simplify representation. type Result<T> = result::Result<T,String>; type TSzwBuf = [u16; SZW_SIZE]; // Open the fileopen dialog with Windows GUI. #[allow(non_snake_case)] fn file_open_dialog() -> Result<String> { let szwFilter = str_to_szw("プログラム:(*.exe)\0*.exe\0すべて:(*)\0*\0"); let szwTitle = str_to_szw("ファイルを選択します"); let mut szw_buf: TSzwBuf = [0; SZW_SIZE]; let mut dlgOpen = OPENFILENAMEW { lStructSize: size_of::<OPENFILENAMEW>() as u32, //DWORD, hwndOwner: null_mut(), // HWND, hInstance: null_mut(), // HINSTANCE, lpstrFilter: szwFilter.as_ptr(), // LPCWSTR, lpstrCustomFilter: null_mut(), // LPWSTR, nMaxCustFilter: 0, // DWORD, nFilterIndex: 0, // DWORD, lpstrFile: szw_buf.as_mut_ptr(), // LPWSTR, nMaxFile: szw_buf.len() as u32, // DWORD, lpstrFileTitle: null_mut(), // LPWSTR, nMaxFileTitle: 0, // DWORD, lpstrInitialDir: null_mut(), // LPCWSTR, lpstrTitle: szwTitle.as_ptr(), // LPCWSTR, Flags: OFN_HIDEREADONLY, // DWORD, nFileOffset: 0, // WORD, nFileExtension: 0, // WORD, lpstrDefExt: null_mut(), // LPCWSTR, lCustData: 0, // LPARAM, lpfnHook: None, // LPOFNHOOKPROC, lpTemplateName: null_mut(), // LPCWSTR, pvReserved: null_mut(), // *mut c_void, dwReserved: 0, // DWORD, FlagsEx: 0, // DWORD, }; match unsafe { GetOpenFileNameW(&mut dlgOpen) } { 0 => Err("Nothing is selected !".to_string()), _ => szw_to_string( &szw_buf ), } } // Convert from TSzwBuf([u16;512]) to String type. fn szw_to_string( szwbuf: &TSzwBuf ) -> Result<String> { szwbuf.iter() .position(|wch| wch == &0) .ok_or("String : Can't find zero terminator !".to_owned()) .and_then(|ix| String::from_utf16( &szwbuf[..ix] ) .map_err(|e| e.to_string())) } // Convert from String to Vec<u16> with trailing \0. fn str_to_szw(str_body: &str) -> Vec<u16> { return OsStr::new(str_body) .encode_wide() .chain(once(0)) // 終端文字\0を追加 .collect::<Vec<u16>>(); } fn main() { let args = env::args().collect::<Vec<String>>(); if args.len() >= 2 { println!("{}", &args[1]); } else { match file_open_dialog() { Ok(file_path) => println!("{}", file_path), Err(e) => println!("{}", e), }; } }上のコードの (1) 黄色い部分で、 コンソールウインドウを出さない様にしている。 (2) 赤い部分は、winapi 0.3.0以降で変更になった書き方。 winapi 0.2.8 までは use winapi::GetOpenFileNameW; の様に短く書けたんだけど winapi 0.3.0以降は上記のフル指定で書く必要がある。 さらに Cargo.tomlに追加設定が必要。 Cargo.toml[package] name = "win32_fopen_dlg" version = "0.1.0" authors = ["audin"] [dependencies] user32-sys="0.2.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.3", features = ["winuser","commdlg"] }
上で、winapi 0.3.0以降を使う時は緑色の部分の追加が必要。 さらに赤い部分で、どのモジュールファイルを使うのかを指定する必要がある。 例えば、GetOpenFileNameW()というAPIの指定方法は、以下のページの一番上の行の検索欄に "GetOpenFileNameW"を入れる。 https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/index.html すると以下の様にフル指定方法がわかる。 https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/um/index.html?search=GetOpenFileNameW また例えば、 USB_DEVICE_SPEEDという定数を使いたい場合、 https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/shared/usbspec/type.USB_DEVICE_SPEED.html?search=USB_DEVICE_SPEED 上の様になるので、Cargo.tomlの featuresは、 features = ["winuser","commdlg","usbspec"] となり、ソースコードには use winapi::shared::usbspec::USB_DEVICE_SPEED; を追加する。 umとかsharedの様な上位階層はfeaturesに指定する必要はない様だ。 native-windows-gui Win32APIのGUIラッパーを作った人がいました。 https://github.com/gabdube/native-windows-gui gitでクローンして Cargo.tomlのあるフォルダで、 cargo run --example showcase cargo run --example canvas cargo run --example templating などと、exapmlesフォルダの中のファイルをコンパイルすると、 ./target/debug/examples/*.exe ができるので実行する。 iniファイルを操作するライブラリ ライブラリというかクレイトと言うらしい。 rust-ini https://crates.io/crates/rust-ini gitリポ https://github.com/zonyitoo/rust-ini 使い方 https://docs.rs/rust-ini/0.10.0/ini/ Windowsのレジストリを操作するライブラリ winreg https://crates.io/crates/winreg gitリポ https://github.com/gentoo90/winreg-rs 試したところちゃんと動きました。
2018年01月06日
Rust言語: xargo.exe, cargo-clone.exeをWindows上でインストールする方法 2018
はじまり Rust言語の「msvc版」の話。 Rust言語のソースをWindows上で「ARMマイコン等」にクロスコンパイルする場合、cargo-clone.exe xargo.exeのコンパイル、インストールが必要らしい。 と思ったが、 cargo-cloneはなくてもOK(gitで直接持ってくればOK)、 xargoはバイナリが入手できるので cargo-cloneもxargoも無理に自前でコンパイルする必要はない様だ。 以下は参考程度。 前提条件: (1) Rustは「nightly版」が必要。$ rustup default nightlyで切り替わる。 (2) cmakeがインストールされ、実行ファイルにPATHが通っていること。 (3) 「VS2017用 x86(またはx64) Native Tools」のコマンドライン上で作業を行うこと。 (VS2015用でもいいらしい。未確認) 手順cargo install cargo-clone cargo install xargoでコンパイル、インストールされる。 時間は結構かかる。 ポイント: 普段は「msys2のコンソール」か「PowerShell上」でRust言語のコンパイルをしているが、 上記ツールのインストール時は(3)のコマンドライン上で実行しないとだめだった。 cmakeがないと「libssh2-sys」のコンパイルで失敗するし、 (3)上じゃない場合、最後の最後にリンクで失敗する。 orz orz xargo.exe バイナリ: xargoについてはコンパイル済みのバイナリがここから入手可能です。 https://github.com/japaric/xargo/releases Rustのバージョン: このブログを書いた時点のバージョン nightly-i686-pc-windows-msvc - rustc 1.24.0-nightly (8e7a609e6 2018-01-04) stable-i686-pc-windows-msvc - rustc 1.23.0 (766bd11c8 2018-01-01) 結果: ARM STM32マイコンのコンパイルをやってみたが、 多重定義エラーで玉砕中 orz 引き続き調査中。 ただし、Linux上でやれば無問題の可能性も否定できない。error[E0152]: duplicate lang item found: `panic_fmt`. --> examples\panic.rs:32:1 | 32 | / unsafe extern "C" fn rust_begin_unwind( 33 | | args: core::fmt::Arguments, 34 | | file: &'static str, 35 | | line: u32, ... | 48 | | intrinsics::abort() 49 | | } | |_^ | = note: first defined in crate `cortex_m_rt`. error: aborting due to previous error error: Could not compile `cortex-m-quickstart`.サポートするクロスコンパイルターゲット:$ rustc --print target-listaarch64-linux-android aarch64-unknown-cloudabi aarch64-unknown-freebsd aarch64-unknown-fuchsia aarch64-unknown-linux-gnu aarch64-unknown-linux-musl arm-linux-androideabi arm-unknown-linux-gnueabi arm-unknown-linux-gnueabihf arm-unknown-linux-musleabi arm-unknown-linux-musleabihf armv4t-unknown-linux-gnueabi armv5te-unknown-linux-gnueabi armv7-linux-androideabi armv7-unknown-cloudabi-eabihf armv7-unknown-linux-gnueabihf armv7-unknown-linux-musleabihf asmjs-unknown-emscripten i586-pc-windows-msvc i586-unknown-linux-gnu i686-apple-darwin i686-linux-android i686-pc-windows-gnu i686-pc-windows-msvc i686-unknown-cloudabi i686-unknown-dragonfly i686-unknown-freebsd i686-unknown-haiku i686-unknown-linux-gnu i686-unknown-linux-musl i686-unknown-netbsd i686-unknown-openbsd mips-unknown-linux-gnu mips-unknown-linux-musl mips-unknown-linux-uclibc mips64-unknown-linux-gnuabi64 mips64el-unknown-linux-gnuabi64 mipsel-unknown-linux-gnu mipsel-unknown-linux-musl mipsel-unknown-linux-uclibc msp430-none-elf powerpc-unknown-linux-gnu powerpc64-unknown-linux-gnu powerpc64le-unknown-linux-gnu s390x-unknown-linux-gnu sparc64-unknown-linux-gnu sparc64-unknown-netbsd sparcv9-sun-solaris thumbv6m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv7m-none-eabi wasm32-experimental-emscripten wasm32-unknown-emscripten wasm32-unknown-unknown x86_64-apple-darwin x86_64-linux-android x86_64-pc-windows-gnu x86_64-pc-windows-msvc x86_64-rumprun-netbsd x86_64-sun-solaris x86_64-unknown-bitrig x86_64-unknown-cloudabi x86_64-unknown-dragonfly x86_64-unknown-freebsd x86_64-unknown-fuchsia x86_64-unknown-haiku x86_64-unknown-linux-gnu x86_64-unknown-linux-gnux32 x86_64-unknown-linux-musl x86_64-unknown-netbsd x86_64-unknown-openbsd x86_64-unknown-redox
Rust言語でSTM32マイコンメモ 2018
はじまり (1) 2018年初頭。素晴らしいページを発見したのでひとまず。メモ STM32F4Discoveryボード用 ARM Cortex-M 32ビットマイコンでベアメタル "Safe" Rust https://qiita.com/tatsuya6502/items/7d8aaf3792bdb5b66f93 上のページの方の解説が丁寧で感激しました。 発見したばかりなのとLinux用なので、Windows上でも可能かどうか試してみようと 思います。 オリジナルの英語記事はSTM32F3Discoveryボードのようです。 https://japaric.github.io/discovery/02-requirements/README.html ちなみに、 レジスタ直設定型の LEDチカチカ + 簡易プリエンプティブ型マルチタスク で、コンパイル後の FLASHサイズ1440バイト、SRAM 4バイト だそうです。 これは試したい。 (2) Rustで組み込みプログラム(Cortex-M) http://park11.wakwak.com/~nkon/homepc/rust_embedded/ このページはNucleoでSTM32Cubeを使っている。 そのうちためそう。
2017年12月31日
Rust言語をWindows上でインストールした時のメモ 2018
はじまり msvc版とgnu版の違い 「Build Tools for Visual Studio 2017」(C++) インストールサイズ比較 gnu版がおすすめでない理由 結論 ただし (オイ Rustのバイナリを小さくする方法 gnu版 Rustのインストール方法 nightly版とstable版を入れ替える方法 はじまり C++/Cの牙城に迫る次世代言語 Rust。 実行速度比較 Rust vs C言語 https://benchmarksgame.alioth.debian.org/u64q/rust.html Rust vs C++言語 https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=rust&lang2=gpp Rust vs Swift言語 https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=rust&lang2=swift Rust vs Go言語 https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=rust&lang2=go Rust vs Java言語 https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=rust&lang2=java Go言語をインストールしてみて、検索中に引っかかって来た言語 Rust。 (オイ Go言語よりも実行速度が速く、単独のバイナリサイズも小さい様だ。 ていうか、Go言語の単独バイナリが少し大きめか。(注1) Rust言語を検索中に引っかかってきた言語 Swift。 RustとSwiftは似てる感じがする。 Swiftは未調査だけど、単独バイナリが小さいならRustに並ぶか、 スマホ系サポートで一気にRustを抜いてしまう可能性もある。 ということで、 Rust言語をWindows上でインストールしてみたメモ。 インストール方法 https://www.rust-lang.org/ja-JP/install.html msvc版とgnu版の違い おすすめは「msvc版」。 上記トップにあるrustup-init.exeを実行するとmsvc版になる。 「Build Tools for Visual Studio 2017」(C++) ただし、 rustup-init.exeを実行する前に、 「Build Tools for Visual Studio 2017」(C++) (2013以降なら可) をインストールしておく必要がある。 これのサイズが約5.5GBもあってorz orz orz orz なのは確か。 orz https://www.visualstudio.com/ja/downloads/?rr=https%3A%2F%2Fwww.rust-lang.org%2Fja-JP%2Finstall.html 上のページの、一番下から2番めあたりにある。 直リンク https://www.visualstudio.com/ja/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15 インストールサイズ比較 msvc版のインストールサイズ 約7GB 5.5GB : 「Build Tools for Visual Studio 2017」(C++) 1.4GB : stable版 + nightly版 gnu版のインストールサイズ 約1.4GB 1.4GB : stable版 + nightly版 インストール方法 https://www.rust-lang.org/ja-JP/other-installers.html gnu版がおすすめでない理由 インストールサイズが小さいので、はじめはこれを試しました。 しばらくして、以下のことがわかったので即座に使うのをやめました。 (1) Rustで書いたソース・ファイルをコンパイルした*.exeの実行速度が劇的に遅い。 簡単な比較でpythonスクリプトよりも30倍以上低速だった。 orz orz orz ありえない 遅さ。 テキストファイル処理(ファイルI/O)が、mingw系なので遅いと推測。 (BufReader, BufRead を使った上で) 追記: よくあるフィボナッチ数列のベンチマークだと、 gnu版は1/3強の速度しか出ていなかった。 (2) コンパイルされた*.exeのファイルサイズがデカい。 Hello world プログラム($cargo build --release)で、 gnu版 約700KB msvc版 約100KB (単独バイナリで700KBならGo言語に比べればマシなほうかもしれないが) ちなみに、main関数空っぽの場合、msvc版は数キロバイトの差しかないので、 オーバヘッドが100KBくらいあることになる。 結論 よほどの理由がない限り、msvc版をインストールするべき。 ただし (オイ ARMマイコンなのどのクロスコンパイルをするなどに特化した場合は、 gnu版でもmsvc版でも差がない可能性を否定できない。 というか試してない。 追記: 試したところ、ARMマイコン用のRustソースコードのコンパイル速度に違いはなかった。 なので、クロスコンパイル用途が主体なら軽量なgnu版でもいいかもしれない。 Rustのバイナリを小さくする方法 Windows上だと、Hello Worldで100KBくらい。 これを 151byteから2KBまで小さくする方法が以下の最後のほうのリンク先にある。 https://lifthrasiir.github.io/rustlog/why-is-a-rust-executable-large.html 151byte になるらしい。 邪道か。 未確認 http://mainisusuallyafunction.blogspot.jp/2015/01/151-byte-static-linux-binary-in-rust.html 以下を実際に試したら2KBくらいだった。 https://github.com/retep998/hello-rs/blob/master/windows/src/main.rs 以下をgitで持ってくればできる。 https://github.com/retep998/hello-rs ベアメタルの組み込み用だとこういう使い方になるのだろう。 gnu版 Rustのインストール方法 最初はこれをインストールしたので、メモしておきます。(Windows10上) インターネット接続が必要です。 (1) これをダウンロード。 保存先は多分どこでも可。 https://static.rust-lang.org/rustup/dist/i686-pc-windows-gnu/rustup-init.exe (2) 実行するとこうなるので 2) Customize installation を選択。 (キーボードで2 を入力し、エンターを押す。) (3) Default host triple? の質問に対して以下を入力してエンターする。 (以下をコピペでもOK) 32bitのパソコンなら i686-pc-windows-gnu 64bitのパソコンなら x86_64-pc-windows-gnu
(4) 続いて Default toolchain? (stable/beta/nightly/none) には nightly と入力してエンター。 (インストール後に、stableやbetaに切り替え可能) (5) Modify PATH variable? (y/n) は y でエンター。 (6) 画面上に入力した内容が表示されるので、良ければ、 1を 入力してエンターで、インストールが開始される。 インストールには数分かかります。 (7) 以下のメッセージがでるのでウィンドウを閉じる。
(8) 環境変数 PATHにはRustの実行パスが追加されたので、 MS-DOSコマンドプロンプトか PowerShell上 でコンパイルが可能になっているはず。 Rustツール群は C:/Users/[User name]/.cargo/bin に格納されているのでうまくいかない時は、PATH変数に上記が追加されているかを 確認する。 (9) 動作確認 適当なフォルダでコマンドラインを開いて
cargo new hello --bin cargo runと打ち込んで、 Hello World が表示されればOK。 nightly版とstable版を入れ替える方法 コマンドラインで、 stable版にしたいなら、rustup default stablenightly版にしたいなら、rustup default nightly現在の状態を確認したいなら、rustup showとする。Default host: i686-pc-windows-gnu installed toolchains -------------------- stable-i686-pc-windows-gnu nightly-i686-pc-windows-gnu (default) active toolchain ---------------- nightly-i686-pc-windows-gnu (default) (timeout reading rustc version)上は nightlyとstableがインストールされていて、 今は nightlyがアクティブになっているという状態。 ちなみに、msvc版の時はこうなるDefault host: i686-pc-windows-msvc installed toolchains -------------------- stable-i686-pc-windows-msvc nightly-2017-12-20-i686-pc-windows-msvc nightly-i686-pc-windows-msvc (default) active toolchain ---------------- nightly-i686-pc-windows-msvc (default) rustc 1.25.0-nightly (6828cf901 2018-01-06)なんかnightly版が2種類入ってる。 (注1) pythonやRubyをEXE化したものよりは断然小さいと思う。