Local by Flywheel(WordPressの仮想環境。現 Local )で仮想環境を作ろうとすると、最終段階で以下のエラーが発生する。
Uh-oh! Could not update hosts file
Local ran into a problem when trying to update the hosts file.
Please ensure that the hosts file is not locked by anti-virus.
意訳:
調べるといろいろとやり方が出てくるが、このエラー、環境を作成/削除するときに出るだけで、作った環境を動かすときには出てこない。
したがって、その瞬間だけセキュリティソフトを止めるのが一番手っ取り早い。
普段使用しているセキュリティソフトを無効化し、Windows Defenderも一瞬だけ止める。
これで回避可能。Wordpress環境ができたらすぐに元に戻す。

#include <iostream> #include <vector> #include <ft2build.h> #include FT_FREETYPE_H #pragma warning(disable:4996) #pragma comment(lib,"freetype.lib") void pnmP2_Write( const char* const fname, const int width, const int height, const unsigned char* const p);
void draw( const int width, const int height, unsigned char* p, const int charw, const int charh, const int ox, const int oy, const unsigned char* charp );
int main() { FT_Library library; // handle to library FT_Error error; error = FT_Init_FreeType(&library); if (error) return -1; FT_Face face; // handle to face object // フォントファイル読み込み error = FT_New_Face( library, "C:\\Windows\\Fonts\\meiryo.ttc", 0, &face ); //文字コード指定 error = FT_Select_Charmap( face, // target face object FT_ENCODING_UNICODE // エンコード指定 ); if (error == FT_Err_Unknown_File_Format) return -1; else if (error) return -1; //この二つの値でフォントサイズ調整 FT_F26Dot6 fontsize = 16 * 64*2; FT_UInt CHAR_RESOLUTION = 300; error = FT_Set_Char_Size( face, // handle to face object 0, // char_width in 1/64th of points fontsize, // char_height in 1/64th of points CHAR_RESOLUTION, // horizontal device resolution CHAR_RESOLUTION); // vertical device resolution
// 回転の指定 double theta = -65.0 * 3.1415 / 180.0; // matrix.xxの型はFT_Fixedだが、これは typedef signed long FT_Fixed FT_Matrix matrix; matrix.xx = (FT_Fixed)(cos(theta) * 0x10000L); matrix.xy = (FT_Fixed)(-sin(theta) * 0x10000L); matrix.yx = (FT_Fixed)(sin(theta) * 0x10000L); matrix.yy = (FT_Fixed)(cos(theta) * 0x10000L); FT_Set_Transform(face, &matrix, 0);
// 出力画像のメモリ確保 const int iw = 1000; const int ih = 1000; std::vector<unsigned char> image(iw*ih,0); // 描画位置 int posx = 500; int posy = 500; for (size_t i = 0; i < 3; i++) { // 文字の取得 FT_ULong character = U"あいう"[i]; FT_UInt char_index = FT_Get_Char_Index(face, character); // グリフ(字の形状)読込 error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER); if (error) return -1; // ignore errors // 文字を画像化 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
// 出力画像に文字を書き込み draw( //出力先データ iw, ih, image.data(), // 文字の画像 face->glyph->bitmap.width, face->glyph->bitmap.rows, posx + face->glyph->bitmap_left, posy - face->glyph->bitmap_top, face->glyph->bitmap.buffer );
posx += (face->glyph->advance.x >> 6);
posy -= (face->glyph->advance.y >> 6);
}
pnmP2_Write(// ファイル保存
"C:\\MyData\\freetypetest.pgm",
iw,
ih,
image.data()
);
// FreeType2の解放
FT_Done_Face(face);
FT_Done_FreeType(library);
}
//! @brief Portable Gray map
//! @param [in] fname ファイル名
//! @param [in] width 画像の幅
//! @param [in] height 画像の高さ
//! @param [in] p 画像のメモリへのアドレス
//! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
void pnmP2_Write(
const char* const fname,
const int width,
const int height,
const unsigned char* const p) { // PPM ASCII
FILE* fp = fopen(fname, "wb");
fprintf(fp, "P2\n%d %d\n%d\n", width, height, 255);
size_t k = 0;
for (size_t i = 0; i < (size_t)height; i++) {
for (size_t j = 0; j < (size_t)width; j++) {
fprintf(fp, "%d ", p[k]);
k++;
}
fprintf(fp, "\n");
}
fclose(fp);
}
//! @brief 出力画像へ文字を書き込む //! @param [in] width 出力先のサイズ //! @param [in] height 出力先のサイズ //! @param [out] p 出力先 //! @param [in] charw 文字画像のサイズ //! @param [in] charh 文字画像のサイズ //! @param [in] ox 描画始点 //! @param [in] oy 描画始点 //! @param [in] charp 文字画像 void draw( const int width, const int height, unsigned char* p, const int charw, const int charh, const int ox, const int oy, const unsigned char* charp ) { for (int cx = 0; cx < charw; cx++) { for (int cy = 0; cy < charh; cy++) { int x = ox + cx; int y = oy + cy; if (x < 0 || x >= width)continue; if (y < 0 || y >= height)continue; int ipos = y * width + x; int cpos = cy * charw + cx; int c = (int)(p[ipos]) + (int)(charp[cpos]); c = std::min(c, 255); p[ipos] = c; } } }
FT_Set_Transform , FT_Load_Glyph , FT_Render_Glyph の順で呼び出すと文字を回転させられる。
注意点としてはFT_Set_Transformに与えるFT_Matrixの要素はfloat型ではなく、FT_Fixedという整数型。
#include <iostream> #include <vector> #include <ft2build.h> #include FT_FREETYPE_H #pragma warning(disable:4996) #pragma comment(lib,"freetype.lib") void pnmP2_Write( const char* const fname, const int width, const int height, const unsigned char* const p); #pragma warning(disable:4996) int main() { FT_Library library; // handle to library FT_Error error; error = FT_Init_FreeType(&library); if (error) return -1; FT_Face face; // handle to face object // フォントファイル読み込み error = FT_New_Face( library, "C:\\Windows\\Fonts\\meiryo.ttc", 0, &face ); //文字コード指定 error = FT_Select_Charmap( face, // target face object FT_ENCODING_UNICODE // エンコード指定 ); if (error == FT_Err_Unknown_File_Format) return -1; else if (error) return -1; //この二つの値でフォントサイズ調整 FT_F26Dot6 fontsize = 16 * 64; FT_UInt CHAR_RESOLUTION = 300; error = FT_Set_Char_Size( face, // handle to face object 0, // char_width in 1/64th of points fontsize, // char_height in 1/64th of points CHAR_RESOLUTION, // horizontal device resolution CHAR_RESOLUTION); // vertical device resolution // 文字の取得 FT_ULong character = wchar_t(L'あ'); FT_UInt char_index = FT_Get_Char_Index(face, character);
double theta = 45.0 * 3.1415 / 180.0; // matrix.xxの型はFT_Fixedだが、これは typedef signed long FT_Fixed FT_Matrix matrix; matrix.xx = (FT_Fixed)(cos(theta) * 0x10000L); matrix.xy = (FT_Fixed)(-sin(theta) * 0x10000L); matrix.yx = (FT_Fixed)(sin(theta) * 0x10000L); matrix.yy = (FT_Fixed)(cos(theta) * 0x10000L); FT_Set_Transform(face, &matrix, 0);
// グリフ(字の形状)読込 error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER); if (error) return -1; // ignore errors // 文字を画像化 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); int Width = face->glyph->bitmap.width; int Height = face->glyph->bitmap.rows; pnmP2_Write(// ファイル保存 "C:\\MyData\\freetypetest.pgm", Width, Height, face->glyph->bitmap.buffer ); // FreeType2の解放 FT_Done_Face(face); FT_Done_FreeType(library); } //! @brief Portable Gray map //! @param [in] fname ファイル名 //! @param [in] width 画像の幅 //! @param [in] height 画像の高さ //! @param [in] p 画像のメモリへのアドレス //! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む void pnmP2_Write( const char* const fname, const int width, const int height, const unsigned char* const p) { // PPM ASCII FILE* fp = fopen(fname, "wb"); fprintf(fp, "P2\n%d %d\n%d\n", width, height, 255); size_t k = 0; for (size_t i = 0; i < (size_t)height; i++) { for (size_t j = 0; j < (size_t)width; j++) { fprintf(fp, "%d ", p[k]); k++; } fprintf(fp, "\n"); } fclose(fp); }
元のプログラムは以下。しかし一部コピペでは動かなかった部分もあるので修正をしている。
https://github.com/microsoft/windows-samples-rs/blob/master/create_window/src/main.rs
以前作った自作WinMainを呼び出すmain関数。
main.rsと同じディレクトリに次のWinMain.rsが存在する。
use windows::Win32::System::LibraryLoader::GetModuleHandleA; use std::env; use windows::Win32::System::Threading::{GetStartupInfoW, STARTUPINFOW}; // mod ファイル名 mod winmain; // use 関数名(など) use winmain::WinMain; // Rustのwindows-rsからウィンドウズアプリケーションをビルドする時には、 // WinWain ではなくmainをエントリポイントとする。 fn main()-> windows::core::Result<()> { let hInstance:windows::Win32::Foundation::HINSTANCE; unsafe{ // https://github.com/microsoft/windows-samples-rs/blob/master/create_window/src/main.rs hInstance = windows::Win32::System::LibraryLoader::GetModuleHandleA(None).unwrap(); } // https://doc.rust-jp.rs/book-ja/ch12-01-accepting-command-line-arguments.html let args: Vec<String> = env::args().collect(); // https://stackoverflow.com/questions/68322072/how-to-get-args-from-winmain-or-wwinmain-in-rust let mut si = windows::Win32::System::Threading::STARTUPINFOW { cb: std::mem::size_of::<windows::Win32::System::Threading::STARTUPINFOW>() as u32, ..Default::default() }; unsafe { windows::Win32::System::Threading::GetStartupInfoW(&mut si) }; let cmd_show = si.wShowWindow as i32; //////////////////////////////////////////////////////////////////////////////////// // 自作WinMainを呼び出す WinMain( hInstance, windows::Win32::Foundation::HINSTANCE(0), args, cmd_show ); Ok(()) }
use windows::{ core::*, Win32::Foundation::*, Win32::Graphics::Gdi::ValidateRect, Win32::System::LibraryLoader::GetModuleHandleA, Win32::UI::WindowsAndMessaging::*, };
extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { unsafe { let rectnullptr: ::core::option::Option<*const windows::Win32::Foundation::RECT> = None; match message as u32 { WM_PAINT => { println!("WM_PAINT"); ValidateRect(window, rectnullptr); LRESULT(0) } WM_DESTROY => { println!("WM_DESTROY"); PostQuitMessage(0); LRESULT(0) } _ => DefWindowProcA(window, message, wparam, lparam), } } }
/// 自作 WinMain pub fn WinMain( hInstance : windows::Win32::Foundation::HINSTANCE, hPrevInstance : windows::Win32::Foundation::HINSTANCE, lpCmdLine:Vec<String>, nCmdShow:i32 )->i32{ unsafe{ let _hCursor = LoadCursorW(None,IDC_ARROW).unwrap(); let _hInstance = hInstance; let _lpszClassName = PCSTR::from_raw("MY_NEW_WINDOW\0".as_ptr()); let _style = CS_HREDRAW | CS_VREDRAW; // https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/UI/WindowsAndMessaging/struct.WNDCLASSA.html let wc=windows::Win32::UI::WindowsAndMessaging::WNDCLASSA{ hCursor :_hCursor, hInstance: _hInstance, lpszClassName: _lpszClassName, style: _style, lpfnWndProc: Some(wndproc), ..Default::default() }; let atom = RegisterClassA(&wc); debug_assert!(atom != 0); let nullptr: ::core::option::Option<*const ::core::ffi::c_void> = None; CreateWindowExA( Default::default(), _lpszClassName, PCSTR::from_raw("This is a sample window\0".as_ptr()), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, None, None, _hInstance, nullptr, ); let mut message = MSG::default(); while GetMessageA(&mut message, HWND(0), 0, 0).into() { DispatchMessageA(&mut message); } } return 0; }
[package]
name = "rs_win"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dependencies.windows]
version = "0.44.0"
# 最新版のバージョンは https://github.com/microsoft/windows-rs で確認
# ・バージョンによってfeaturesを変えなければいけないかもしれない
features = [
"Win32_Graphics_Gdi",
"Win32_Foundation",
"Win32_UI_WindowsAndMessaging",
"Win32_System_LibraryLoader",
"Win32_System_Threading",
]
例えば、WNDCLASSAが見つからずエラーになった場合、まず以下のURLへ飛ぶ。
Required features:
"Win32_UI_WindowsAndMessaging","Win32_Foundation","Win32_Graphics_Gdi"
これらが必要なので、Cargo.tomlに記述する。
features = [
"Win32_Graphics_Gdi",
"Win32_Foundation",
"Win32_UI_WindowsAndMessaging",
]
PCSTR::from_rawを使う。
PCSTR::from_raw("This is a sample window\0".as_ptr()),
Result<>をunwrap()する。
let _hCursor = LoadCursorW(None,IDC_ARROW).unwrap();
::core::option::OptionにNoneを代入
let nullptr: ::core::option::Option<*const ::core::ffi::c_void> = None;
問題はOptionのGeneric<>に何を渡すかで、これは関数定義を素直にコピペするのが一番楽。VSCode関数を右クリックなどして定義へ移動し、該当引数の型をそのまま持ってきてNone代入する。
RustでWin32APIを書くときはWinMainがエントリポイントにならないので、mainから始める。
各種関数を駆使すればWinMainの引数と同等のものを得ることができるが、コマンドライン引数だけはスペースで区切られた配列で得る方法しか見つからなかった。
use windows::Win32::System::LibraryLoader::GetModuleHandleA; use std::env; use windows::Win32::System::Threading::{GetStartupInfoW, STARTUPINFOW}; // Rustのwindows-rsからウィンドウズアプリケーションをビルドする時には、 // WinWain ではなくmainをエントリポイントとする。
fn main()-> windows::core::Result<()> { let hInstance:windows::Win32::Foundation::HINSTANCE; unsafe{ // https://github.com/microsoft/windows-samples-rs/blob/master/create_window/src/main.rs hInstance = windows::Win32::System::LibraryLoader::GetModuleHandleA(None).unwrap(); } // https://doc.rust-jp.rs/book-ja/ch12-01-accepting-command-line-arguments.html let args: Vec<String> = env::args().collect(); // https://stackoverflow.com/questions/68322072/how-to-get-args-from-winmain-or-wwinmain-in-rust let mut si = windows::Win32::System::Threading::STARTUPINFOW { cb: std::mem::size_of::<windows::Win32::System::Threading::STARTUPINFOW>() as u32, ..Default::default() }; unsafe { windows::Win32::System::Threading::GetStartupInfoW(&mut si) }; let cmd_show = si.wShowWindow as i32; //////////////////////////////////////////////////////////////////////////////////// // 自作WinMainを呼び出す WinMain( hInstance, windows::Win32::Foundation::HINSTANCE(0), args, cmd_show ); Ok(()) }
/// やっぱり WinMain から起動したほうが読みやすい人のために /// 自作 WinMain を作成 fn WinMain( hInstance : windows::Win32::Foundation::HINSTANCE, hPrevInstance : windows::Win32::Foundation::HINSTANCE, lpCmdLine:Vec<String>, nCmdShow:i32 )->i32{ println!("hInstance : {}",hInstance.0); println!("hPrevInstance : {}", hPrevInstance.0); println!("lpCmdLine : {:?}", lpCmdLine); println!("nCmdShow : {}", nCmdShow); return 0; }
BlenderでSaplingを使うと、なぜかはの付け根に白い四角形が生じる。これは何で、どうやったら消せるのか。
Saplingの葉は、実はオブジェクトの上に生成したinstanceである。
(実体化するためにはMake Instances Realしなければならないことから明らかだ。)
だから、葉を選択(実際にはその根元にある四角形が本体)し、Object Properties→Instancing→Facesを辿り、Show Instancerのチェックを外せば、非表示にできる。
・[ツール] → [新規 C++ クラス ...] を選択
・「親クラスを選択」で 「Blueprint Function Library」を選択し、次へ
[クラスを作成]をクリック。
・「プロジェクトにソースが含まれます。エディタを閉じてIDEからビルドしてください。」をOK
・「クラス 'MyBlueprintFunctionLibrary' の追加に成功しました。ただしコンテントブラウザに表示されるようにするには'MyProject'モジュールをコンパイルする必要があります。」を「はい」
VC++が自動で開くが、一度閉じる。
※ もう一度slnを開くために、このアイテムのフォルダーを開くからパスを確認しておくと便利。
さらにUnreal Engineも閉じる。
上で閉じたslnを手動で開き、MyBlueprintFunctionLibrary.h に以下のメンバ関数宣言を追加する。
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "MyBlueprintFunctionLibrary.generated.h" /** * */ UCLASS() class MYPROJECT_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary { GENERATED_BODY()
// 追加 UFUNCTION(BlueprintCallable, Category = "MyCategory") static FString MyFirstCppNode();
};
// Fill out your copyright notice in the Description page of Project Settings. #include "MyBlueprintFunctionLibrary.h" FString UMyBlueprintFunctionLibrary::MyFirstCppNode() { return FString("output from C++"); }
普通にビルドする。
閉じたUE5プロジェクトを再び開き、レベルブループリントなどに上記で追加した関数名と同じノードを使用する
[追加]→[ユーザーインタフェース]→[ウィジェットブループリント]を選択し、[User Widget]をクリック。名前を「MyUserWidget」へ変更しておく。
[パネル]→[Canvas Panel]を追加する。CanvasPanelを追加しないとボタンが全画面になる。
次に[一般]→[Button] を追加し、Buttonへ[Text]を追加。ボタンとテキストを親子関係にしてボタンに文字をつける。
On Clickイベントを追加し、Print textのブループリントを追加しておく。
レベルブループリントを開き、
を繋げて配置。Create Widgetで最初に追加したMyUserWidgetを設定する。
MessageBoxAにs!で文字列を渡すと日本語が文字化けするので、encoding_rsでShiftJISへ変換する。さらに0終端にするためにto_vec()でvecへ変換し0をpushする。
なおencoding_rsを使うための設定をCargo.tomlに加筆する。
※ このやり方が正攻法なのかよくわからない。
use windows::Win32::UI::WindowsAndMessaging::{MessageBoxA, MB_OK}; use encoding_rs::*; fn main( )->windows::core::Result<()>{ // windows::core::s! マクロ ... 文字列(utf8)をLPCSTR へ変換。 // MessageBoxWを使う場合はLPCWSTR へ変換するw!を使用。 unsafe { // windows::core::s!() にそのまま日本語を与えると文字化けする。 // Rustはu8が基本。 MessageBoxA はnull終端のマルチバイト(ShiftJIS)なので、変換が必要 let msg = SHIFT_JIS.encode("ハローワールド"); let ttl = SHIFT_JIS.encode("タイトル"); let mut msg0 = msg.0.to_vec(); let mut ttl0 = ttl.0.to_vec(); // null 終端にする msg0.push(0); ttl0.push(0); let smsg0 = windows::core::PCSTR(msg0.as_ptr()); let sttl0 = windows::core::PCSTR(ttl0.as_ptr()); MessageBoxA( None, smsg0, sttl0, MB_OK ); } Ok(()) }
[package]
name = "myproject"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies.windows]
version = "0.44.0"
# 最新版のバージョンは https://github.com/microsoft/windows-rs で確認
# ・バージョンによってfeaturesを変えなければいけないかもしれない
# ・バージョンによって何が使えるか(どこにあるか?)が変わる
# 例えば windows::Win32::Foundation::HINSTANCE やs!は0.32.0にはない
features = [
"Win32_Foundation",
"Win32_UI_WindowsAndMessaging",
]
[dependencies.encoding_rs]
version="0.8.31"
からもダウンロードできる。そこにMIT Licenseと書いてあるのでライセンスはかなり緩い。
ビルドしなくても使えるのでその点は良いが、インクルードがヘッダファイル一つでも関連ファイルが多いので追加のインクルードディレクトリを指定しなければいけない。
#include <iostream> //https://tclap.sourceforge.net/ #include <tclap/CmdLine.h> int main(int argc, char** argv) { int val_int; std::string val_string;
// Define the command line object TCLAP::CmdLine cmd( "test program" // アプリケーションの説明 , ' ' // コマンドライン引数の区切り文字 , "0.1" // ツールのバージョン , true // -hで表示されるヘルプを作成する );
TCLAP::ValueArg<int> arg_i( "n" // 引数指定方法 -n 123 のように記述 , "number" // 引数指定方法 --number のように記述 , "count of data" // ヘルプに表示する説明 , true // 必須項目であることを示す , 0 // 初期値 , "integer" // ヘルプに表示するこのオプションのデータ型 ); cmd.add(arg_i);
TCLAP::ValueArg<std::string> arg_s( "t" // 引数指定方法 -t abc のように記述 , "text" // 引数指定方法 --text のように記述 , "text data" // ヘルプに表示する説明 , false // 必須項目であることを示す , "void" // 初期値 , "text" // ヘルプに表示するこのオプションのデータ型 ); cmd.add(arg_s);
// コマンドライン引数を解釈する cmd.parse(argc, argv); // 解釈した値を取得する val_int = arg_i.getValue(); val_string = arg_s.getValue(); // 入力されたオプションを確認 std::cout << "input : " << val_int << std::endl; std::cout << "input : " << val_string << std::endl; return 0; }
実行例1 引数を指定して実行してみる。
実行例2 ヘルプを作成しているので、-hで使い方表示ができるようになっている。
app.exe -h
USAGE:
app [-h] [--version] [-t <text>] -n <integer>
Where:
-n <integer>, --number <integer>
(required) count of data
-t <text>, --text <text>
text data
--, --ignore_rest
Ignores the rest of the labeled arguments following this flag.
--version
Displays version information and exits.
-h, --help
Displays usage information and exits.
test program