http://suzulang.com/%25E8%25A6%2596%25E9%2587%258E%25E3%2581%258C%25E7%258B%25AD%25E3%2581%2584%25E3%2581%25A8%25E3%2581%25A9%25E3%2581%2586%25E3%2581%2584%25E3%2581%2586%25E6%2599%2582%25E3%2581%25AB%25E8%258B%25A6%25E5%258A%25B4%25E3%2581%2599%25E3%2582%258B%25E3%2581%258B/
このページは元々しないか、URLが変更されたか、または削除されています。
wxWidgetsで.xrcファイルからデザインを読み込んで適用(4)独自のタグを読み込む [ Updated]
.xrcファイルはxml形式なので、独自のタグを入れられる。ただしそれを解析する機能がデフォルトではないので、ハンドラを用意する必要がある。
.xrcファイルにはコントロールwx_my_Buttonという識別子でボタンを配置する。このボタンはC++では標準のボタン(wxButton)として生成する。wxButtonのハンドラを書き換えられないので、wx_my_Buttonのハンドラを作成し、中でwxButtonを作成する。
<?xml version="1.0" ?> <resource version="2.3.0.1"> <!-- トップレベルはコントロールである必要がある。パネルを作成。 --> <object class="wxPanel" name="myContainerPanel"> <bg>#00FF00</bg> <!-- 名前 myButton を追加 --> <object class="wx_my_Button" name="myButton"> <myoption attr="5">ユーザー定義オプション</myoption> <label>ボタン</label> </object> </object> </resource>
// wxXmlNode を使うために必要 #include <wx/xml/xml.h>
SetClientDataで値のインスタンス(ここではmyoption_dataの変数)へのポインタをvoid*で指定する。
struct myoption_data { int attr; wxString str; };
GetParamNodeの使用にはwx/xml/xml.hが必要。
// .xrcから独自タグを読み込むには、自作ウィジェットをwxXmlResourceが読み込むための // ハンドラを作成して登録する必要がある class MyButtonXmlHandler : public wxXmlResourceHandler { public: MyButtonXmlHandler() : wxXmlResourceHandler() { AddWindowStyles(); } virtual wxObject* DoCreateResource() override { XRC_MAKE_INSTANCE(mybutton, wxButton); // 普通のボタンを作成 // プロパティの設定 mybutton->Create( m_parentAsWindow, GetID(), GetText("label"), GetPosition(), GetSize(), GetStyle(), wxDefaultValidator, GetName() );
// タグ名 wxString tagname = "myoption"; // データを格納する構造体のインスタンスを作成 // あとで解放しなければいけない myoption_data *pdata = new myoption_data; // 値を取得 // GetTextでも取得できるが、GetTextは\nや$を勝手にエスケープしたり置換したりするので // 内容をそのまま取得できるGetParamValueを使う wxString myopt = GetParamValue(tagname); if (!myopt.IsEmpty()) { pdata->str = myopt; } // 属性を取得 wxXmlNode* node = GetParamNode(tagname); if (node) { wxString attr = node->GetAttribute("attr"/*属性名*/, "0"/*初期値*/); pdata->attr = wxAtoi(attr); } mybutton->SetClientData(pdata);// データをコントロールに指定
SetupWindow(mybutton); return mybutton; } // このハンドラが、xrc内に定義された"MyControl"というウィジェットを作成できることを示すために必要 virtual bool CanHandle(wxXmlNode* node) override { // 生成するのはただのボタンだが、wxButtonのハンドラを置換はできないので // 別のクラス名を識別子にする。 return IsOfClass(node, "wx_my_Button"); } // wxCreateObject() ,GetClassInfo() ,ms_classInfo,wxCreateObject()が定義される wxDECLARE_DYNAMIC_CLASS(MyButtonXmlHandler); }; // 自作ウィジェットのハンドラを登録 IMPLEMENT_DYNAMIC_CLASS(MyButtonXmlHandler, wxXmlResourceHandler)
生成されるのは普通のwxButtonなので、生成時にAddHandlerしておくこと以外には特別なことはしない。ただしハンドラ内でnewしたmyoption_dataのポインタは自分で削除しなければいけないので、wxEVT_DESTROYに後始末用関数をバインドする。
// ウィンドウ作成 class MyFrame : public wxFrame { public: void PostCreate() { wxXmlResource::Get()->InitAllHandlers();// 初期化 // カスタムコントロールのハンドラを登録 wxXmlResource::Get()->AddHandler(new MyButtonXmlHandler); wxXmlResource::Get()->Load(R"(C:\test\myctrl.xrc)"); // ファイル読み込み wxXmlResource::Get()->LoadPanel(this, "myContainerPanel"); // GUIの生成 this->Layout(); // レイアウトの更新 wxButton* btn = (wxButton*)FindWindowByName("myButton"); btn->Bind(wxEVT_BUTTON, &MyFrame::OnClick, this); // ボタンのクリックイベント btn->Bind(wxEVT_DESTROY, &MyFrame::OnBtnDestroy, this); // ユーザー定義のデータを破棄するための処理を追加 } MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { // CallAfter : 現在処理中のイベントが終わったらPostCreateを実行 // コンストラクタはウィンドウ生成イベント扱い CallAfter(&MyFrame::PostCreate); }
// ボタンのクリックイベント void OnClick(wxCommandEvent& event) { wxButton* btn = (wxButton*)event.GetEventObject(); myoption_data* data = (myoption_data*)btn->GetClientData(); wxString text = wxString::Format("%s %d", data->str, data->attr); wxMessageBox(text); }
// ユーザー定義のデータを持つボタンの破棄イベント void OnBtnDestroy(wxWindowDestroyEvent& event) { wxButton* btn = (wxButton*)event.GetEventObject(); myoption_data* data = (myoption_data*)btn->GetClientData(); delete data; }
};
wxWidgetsで.xrcファイルからデザインを読み込んで適用(3)カスタムコントロールを読み込み [ Updated]
wxWidgetsでは、wxWindowなどを継承してカスタムコントロールを作れる。それを.xrcファイルに定義した場合、.xrcを読み込む wxXmlResource がカスタムコントロールを知らないため、専用のハンドラを定義しなければいけない。
以下のようなカスタムコントロール CMyControl を定義する
// ボタンとテキストを持つコントロールをパネルで作成 class CMyControl : public wxWindow { public: // 今回はMyControlXmlHandler側でXRC_MAKE_INSTANCEでインスタンス生成をする // MyControlXmlHandlerはデフォルトコンストラクタを呼び出すので定義する CMyControl() :wxWindow() { } // デフォルトコンストラクタでは最小限の初期化しか行わないので // 初期化用のCreate関数を定義する必要が出てくる bool Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name) { if (!wxWindow::Create(parent, id, pos, size, style, name)) { return false; } my_create(); return true; } // parentを指定するコンストラクタ CMyControl(wxWindow* parent) :wxWindow(parent, wxID_ANY) { my_create(); } // ウィジェットの初期化関数 void my_create() { // ボタンの作成 wxButton* myButton = new wxButton(this, wxID_ANY, "ボタン", wxPoint(10, 10), wxSize(150, 50)); // テキストの作成 wxTextCtrl* myText = new wxTextCtrl(this, wxID_ANY, "テキスト", wxPoint(10, 70), wxSize(150, 50)); this->SetBackgroundColour(wxColour(255, 0, 0)); } };
以下のように.xrcファイルを定義する
<?xml version="1.0" ?> <resource version="2.3.0.1"> <!-- トップレベルはコントロールである必要がある。パネルを作成。 --> <object class="wxPanel" name="myContainerPanel"> <bg>#00FF00</bg> <!-- レイアウト用のサイザーを作成 --> <object class="wxBoxSizer" name="myBoxSizer"> <orient>wxVERTICAL</orient> <!-- レイアウト方法の指定 --> <!-- コントロールは sizeritem に入れる --> <object class="sizeritem"> <!-- 周囲に15pxの余白を入れる --> <flag>wxALL | wxEXPAND</flag> <border>15</border> <!-- このコントロールはサイザーのサイズ変更で大きさが変わる --> <option>1</option> <!-- カスタムコントロールを追加 --> <object class="MyControl" name="nameMyControl" /> </object> </object> </object> </resource>
// .xrcから読み込むには、自作ウィジェットをwxXmlResourceが読み込むための // ハンドラを作成して登録する必要がある class MyControlXmlHandler : public wxXmlResourceHandler { public: MyControlXmlHandler() : wxXmlResourceHandler() { XRC_ADD_STYLE(wxTAB_TRAVERSAL); XRC_ADD_STYLE(wxNO_BORDER); XRC_ADD_STYLE(wxDOUBLE_BORDER); AddWindowStyles(); }
// これが必要 // wxXmlResource::LoadObject() が呼び出されたときに呼び出される関数 virtual wxObject* DoCreateResource() override { // 概ねやっていることは以下と同じ: // MyControl* control = new MyControl; // 注意として、このマクロはMyControlのデフォルトコンストラクタを呼び出すので // 引数なしのコンストラクタが必要 // 別にXRC_MAKE_INSTANCEを使わなくても、普通にnewしてもいい。 XRC_MAKE_INSTANCE(control, CMyControl); // デフォルトコンストラクタでは最小限の初期化しかされないので // Create()を呼び出して、実際の初期化を行う // 従ってMyControl::Create()を定義しておく control->Create( m_parentAsWindow, // 親ウィンドウ GetID(), GetPosition(), GetSize(), GetStyle(), GetName() ); SetupWindow(control); return control; }
// このハンドラが、xrc内に定義された"MyControl"というウィジェットを作成できることを示すために必要 virtual bool CanHandle(wxXmlNode* node) override { return IsOfClass(node, "MyControl"); }
// wxCreateObject() ,GetClassInfo() ,ms_classInfo,wxCreateObject()が定義される wxDECLARE_DYNAMIC_CLASS(MyControlXmlHandler);
}; // 自作ウィジェットのハンドラを登録 IMPLEMENT_DYNAMIC_CLASS(MyControlXmlHandler, wxXmlResourceHandler)
読み込むときは、AddHandlerで、作成したハンドラのインスタンスをwxXmlResourceに渡す。
// ウィンドウ作成 class MyFrame : public wxFrame { public: void PostCreate() { wxXmlResource::Get()->InitAllHandlers();// 初期化 // カスタムコントロールのハンドラを登録 wxXmlResource::Get()->AddHandler(new MyControlXmlHandler); wxXmlResource::Get()->Load(R"(C:\test\myctrl.xrc)"); // ファイル読み込み wxXmlResource::Get()->LoadPanel(this, "myContainerPanel"); // GUIの生成 this->Layout(); // レイアウトの更新 } MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { // CallAfter : 現在処理中のイベントが終わったらPostCreateを実行 // コンストラクタはウィンドウ生成イベント扱い CallAfter(&MyFrame::PostCreate); } };
wxWidgetsで.xrcファイルからデザインを読み込んで適用(2) イベントのBindと値の取得 [ Updated]
<?xml version="1.0" ?> <resource version="2.3.0.1"> <!-- トップレベルはコントロールである必要がある。パネルを作成。 --> <object class="wxPanel" name="myMainPanel"> <!-- レイアウト用のサイザーを作成 --> <object class="wxBoxSizer" name="myBoxSizer"> <orient>wxVERTICAL</orient> <!-- レイアウト方法の指定 --> <!-- コントロールは sizeritem に入れる --> <object class="sizeritem"> <!-- 左側と上側に15pxの余白を入れる --> <flag>wxLEFT|wxTOP</flag> <border>15</border> <!-- このコントロールはサイザーのサイズ変更で大きさが変わらない --> <option>0</option> <!-- 名前 myButton を追加 --> <object class="wxButton" name="myButton"> <label>ボタン</label> <size>100,30</size> </object> </object> <!-- コントロールは sizeritem に入れる --> <object class="sizeritem"> <!-- 上下左右の余白は15px --> <flag>wxALL|wxEXPAND</flag> <border>15</border> <!-- このコントロールはサイザーのサイズ変更で大きさが変わる --> <option>1</option> <object class="wxTextCtrl" name="myText"> <value>テキスト</value> </object> </object> </object> </object> </resource>
// https://docs.wxwidgets.org/3.0/overview_helloworld.html // プリプロセッサに以下二つを追加 // __WXMSW__ // WXUSINGDLL // サブシステムをWindowsに設定(WinMainで呼び出すので) // Windows (/SUBSYSTEM:WINDOWS) #ifndef WX_PRECOMP #include <wx/wx.h> #endif #include <wx/gdicmn.h> // wxPointに必要 #include <wx/frame.h> // wxFrameに必要 #pragma comment(lib,"wxbase32u.lib") #pragma comment(lib,"wxbase32u_net.lib") #pragma comment(lib,"wxbase32u_xml.lib") #pragma comment(lib,"wxmsw32u_adv.lib") #pragma comment(lib,"wxmsw32u_aui.lib") #pragma comment(lib,"wxmsw32u_core.lib") #pragma comment(lib,"wxmsw32u_gl.lib") #pragma comment(lib,"wxmsw32u_html.lib") #pragma comment(lib,"wxmsw32u_media.lib") #pragma comment(lib,"wxmsw32u_propgrid.lib") #pragma comment(lib,"wxmsw32u_qa.lib") #pragma comment(lib,"wxmsw32u_ribbon.lib") #pragma comment(lib,"wxmsw32u_richtext.lib") #pragma comment(lib,"wxmsw32u_stc.lib") #pragma comment(lib,"wxmsw32u_webview.lib") #pragma comment(lib,"wxmsw32u_xrc.lib") ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// #include <wx/xrc/xmlres.h> #include <string> // ウィンドウ作成 class MyFrame : public wxFrame { public:
void PostCreate() { wxXmlResource::Get()->InitAllHandlers();// 初期化 wxXmlResource::Get()->Load(R"(C:\test\layout.xrc)"); // ファイル読み込み wxXmlResource::Get()->LoadPanel(this, "myMainPanel"); // GUIの生成 this->Layout(); // レイアウトの更新 // ボタンの取得 wxButton* myButton = XRCCTRL(*this, "myButton", wxButton); // ボタンのクリックイベントに対するイベントハンドラを接続 myButton->Bind(wxEVT_BUTTON, &MyFrame::OnMyButtonClick, this); }
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { // CallAfter : 現在処理中のイベントが終わったらPostCreateを実行 // コンストラクタはウィンドウ生成イベント扱い CallAfter(&MyFrame::PostCreate); }
// ボタンがクリックされたときのイベントハンドラ void OnMyButtonClick(wxCommandEvent& event) { // テキストボックスの取得 wxTextCtrl* textctrl = XRCCTRL(*this, "myText", wxTextCtrl); // テキストボックスの内容を取得 wxString str = textctrl->GetValue(); // ボタンがクリックされたときの処理 wxMessageBox(str); }
private: }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // wxWidgetsのアプリケーション作成 class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340)); frame->Show(true); return true; } }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // WinMainをマクロで定義 wxIMPLEMENT_APP(MyApp);
XRCCTRLの実体はFindWindowをdynamic_castしたもので、実際はもっと複雑だがざっくりいうと以下のようなことをやっている。
wxButton* myButton = dynamic_cast<wxButton*>(this->FindWindow("myButton"));
wxWidgetsで.xrcファイルからデザインを読み込んで適用(1) xrcファイルからGUI作成 [ Updated]
wxWidgetsで画面デザインを定義する.xrcファイルを読み込んでGUIを作成する。
<?xml version="1.0" ?> <resource version="2.3.0.1"> <!-- トップレベルはコントロールである必要がある。パネルを作成。 --> <object class="wxPanel" name="myMainPanel">
<!-- レイアウト用のサイザーを作成 --> <object class="wxBoxSizer" name="myBoxSizer"> <orient>wxVERTICAL</orient> <!-- レイアウト方法の指定 -->
<!-- コントロールは sizeritem に入れる --> <object class="sizeritem"> <!-- 左側と上側に15pxの余白を入れる --> <flag>wxLEFT|wxTOP</flag> <border>15</border> <!-- このコントロールはサイザーのサイズ変更で大きさが変わらない --> <option>0</option>
<!-- 名前 myButton を追加 --> <object class="wxButton" name="myButton"> <label>ボタン</label> <size>100,30</size> </object>
</object>
<!-- コントロールは sizeritem に入れる --> <object class="sizeritem"> <!-- 上下左右の余白は15px --> <flag>wxALL|wxEXPAND</flag> <border>15</border> <!-- このコントロールはサイザーのサイズ変更で大きさが変わる --> <option>1</option>
<object class="wxTextCtrl" name="mytext1"> <label>ボタン</label> <size>100,30</size> <!-- サイザーが有効なのでサイズは無視される --> </object>
</object>
</object>
</object> </resource>
// https://docs.wxwidgets.org/3.0/overview_helloworld.html // プリプロセッサに以下二つを追加 // __WXMSW__ // WXUSINGDLL // サブシステムをWindowsに設定(WinMainで呼び出すので) // Windows (/SUBSYSTEM:WINDOWS) #ifndef WX_PRECOMP #include <wx/wx.h> #endif #include <wx/gdicmn.h> // wxPointに必要 #include <wx/frame.h> // wxFrameに必要 #pragma comment(lib,"wxbase32u.lib") #pragma comment(lib,"wxbase32u_net.lib") #pragma comment(lib,"wxbase32u_xml.lib") #pragma comment(lib,"wxmsw32u_adv.lib") #pragma comment(lib,"wxmsw32u_aui.lib") #pragma comment(lib,"wxmsw32u_core.lib") #pragma comment(lib,"wxmsw32u_gl.lib") #pragma comment(lib,"wxmsw32u_html.lib") #pragma comment(lib,"wxmsw32u_media.lib") #pragma comment(lib,"wxmsw32u_propgrid.lib") #pragma comment(lib,"wxmsw32u_qa.lib") #pragma comment(lib,"wxmsw32u_ribbon.lib") #pragma comment(lib,"wxmsw32u_richtext.lib") #pragma comment(lib,"wxmsw32u_stc.lib") #pragma comment(lib,"wxmsw32u_webview.lib") #pragma comment(lib,"wxmsw32u_xrc.lib") ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// #include <wx/xrc/xmlres.h> // ウィンドウ作成 class MyFrame : public wxFrame { public:
void PostCreate() { wxXmlResource::Get()->InitAllHandlers();// 初期化 wxXmlResource::Get()->Load(R"(C:\test\layout.xrc)"); // ファイル読み込み wxXmlResource::Get()->LoadPanel(this, "myMainPanel"); // GUIの作成 this->Layout(); // レイアウトの更新 }
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { // CallAfter : 現在処理中のイベントが終わったらPostCreateを実行 // コンストラクタはウィンドウ生成イベント扱い CallAfter(&MyFrame::PostCreate); } private: }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // wxWidgetsのアプリケーション作成 class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340)); frame->Show(true); return true; } }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // WinMainをマクロで定義 wxIMPLEMENT_APP(MyApp);
パネルにはLoadPanelがあるが、すべてのコントロールにLoad***が用意されているわけではない。LoadObject関数を使って、部品名とその部品のクラスを指定して読み込む。
<?xml version="1.0" ?> <resource version="2.3.0.1"> <!-- 名前 myButton を追加 --> <object class="wxButton" name="myButton"> <label>ボタン</label> <size>300,30</size> </object> </resource>
void PostCreate() { wxXmlResource::Get()->InitAllHandlers();// 初期化 wxXmlResource::Get()->Load(R"(C:\test\button.xrc)"); // ファイル読み込み wxWindow* btn = (wxWindow*)wxXmlResource::Get()->LoadObject(this, "myButton"/*識別子*/, "wxButton"/*クラス*/); // boxsizerの追加 wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); this->SetSizer(sizer); sizer->Add(btn, 0, wxALL, 10); this->Layout(); // レイアウトの更新 }
原則として、メモリ上のテキストを読み込む方法はない。しかし、wxWidgetsにはメモリ上に仮想的なファイルを作成する機能があるので、これを使って仮想的な.xrcファイルを作れば実現できる。
仮想ファイルを作るために、fs_mem.h が必要。
#include <wx/fs_mem.h>
void PostCreate() { wxXmlResource::Get()->InitAllHandlers(); wxString layout_xrc =
R"(<?xml version="1.0" ?> <resource version="2.3.0.1"> <object class="wxPanel" name="myPanel"> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <object class="wxTextCtrl" name="text"/> <option>0</option> <size>100,30</size> <flag>wxALL</flag> <border>10</border> </object> </object> </object> </resource> )"
; wxFileSystem::AddHandler(new wxMemoryFSHandler); wxMemoryFSHandler::AddFile("myxrc", layout_xrc.GetData().AsWChar(), layout_xrc.size()*2); wxXmlResource::Get()->Load("memory:myxrc"); wxWindow* mysizer = wxXmlResource::Get()->LoadPanel(this, "myPanel"); this->Layout(); // レイアウトの更新 }
VC++で生成した.exeファイル内のタイムスタンプ部分を確認して無理やり書き換えてみた。 [ Updated]
諸事情により簡易的でよいので.exeファイルの解析をしたくなった。.exeファイルをバイナリエディタで見てみて、全く同じプロジェクトを二回以上ビルドした結果が完全一致しない。理由の一つがタイムスタンプなので、これをいじってみる。
VC++でコンソールアプリケーションを作成する。この時、余計なものが埋め込まれるとそれだけビルド時の変化が大きくなる可能性があるので、わかる範囲で不要なオプションを取り除く。
・.pdbファイルを出力しない
プロジェクトのプロパティ → リンカー → デバッグ → デバッグ情報の生成 → いいえ
・マニフェストを埋め込まない
プロジェクトのプロパティ → リンカー → マニフェスト ファイル → マニフェストの生成 → いいえ
・ASLRをしない(Address Space Layout Randomization)
ASLRはexe内のデータの位置をランダムにするクラッキング対策のオプションで、多分悪影響を与えるので切っておく。/DYNAMICBASE:NOを設定。
プロジェクトのプロパティ → リンカー → 詳細設定 → ランダム化されたベースアドレス → いいえ
まずビルドし、上書きされないように.exeファイルの名前を変える。それからもう一度ビルドする。
右クリック→プロパティ→詳細 で更新日時を確認。
実際にはここの表示を変えるわけではないのだが、バイナリ中の値を解析してこの日付とおおむね同じものが出てくれば正解だとわかるので参考にする。
WinMergeで二つの.exeをバイナリ比較する。手元のバージョンでは、CompareボタンのプルダウンにBinary比較がある。
一部違う場所が出てくるので、その右4バイトに着目する。時間を置かずにビルドすると、数秒しか違わないはずなので、違いはせいぜい下1バイトになる可能性が高い。intelのCPUはリトルエンディアンなので、バイトの並び順が逆になっている。従って変化している場所を含めて右に4バイトがタイムスタンプとなる。
上記で得られた値 0x65abe167 が実際にビルド時刻であることを確認するため、以下のプログラムを書いて確認する。
#include <ctime> #include <string> #include <iostream> #pragma warning(disable:4996) // タイムスタンプから時刻表示を作成 std::string TimestampToDate(time_t timestamp) { struct tm* tm = localtime(×tamp);// 整数値 timestamp を tm 構造体に変換 char str[50]; strftime(str, sizeof(str), "%Y/%m/%d %H:%M:%S", tm);// tmを文字列化 return std::string(str); } int main() { // タイムスタンプ(16進数指定) // バイナリに埋め込まれている値はリトルエンディアンなので // バイナリエディタ上の表示とバイト単位で逆順にして入力する time_t timestamp = 0x65abe167; std::cout << TimestampToDate(timestamp) << std::endl; return 0; }
結果
確かにファイルのプロパティ上の表示と一致する内容を得られたので、この数値がタイムスタンプであることは理解できた。今度はこれを書き換えてみる。
まず、適当な日付をタイムスタンプに変換するため、以下のプログラムを書いて走らせる。
#include <ctime> #include <string> #include <iostream> #pragma warning(disable:4996) // 時刻からタイムスタンプを作成 time_t DateToTimestamp(const std::string date) { struct tm tm = {}; int year, month, day; int hour, minute, second; sscanf(date.c_str(), "%d/%d/%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second ); tm.tm_year = year - 1900; tm.tm_mon = month - 1; tm.tm_mday = day; tm.tm_hour = hour; tm.tm_min = minute; tm.tm_sec = second; return mktime(&tm); } int main() { std::string date_str = "2022/01/01 5:25:30"; // 適当な日付 unsigned int timestamp = DateToTimestamp(date_str); printf("%x \n", timestamp); }
結果
こうして得られたタイムスタンプを、バイナリエディタで書き込む。書き込みにはStirlingを使っている。入力時、リトルエンディアンなのでバイト単位で逆順に指定する。
タイムスタンプはビルド時の色々なステップで入れられるらしいので、同じ値を見つけたらすべて書き換える。
先ほどはファイルのプロパティから確認したが、この日付はファイルのプロパティには実は表示されないので、PEヘッダを読むツールで確認する。探したところPEviewが適している。
以下からPEview version 0.9.9 ( .zip 31KB )をダウンロードする。
http://wjradburn.com/software/