杉山利幸の公開日誌 2019年3月分

2019年4月分

2019/03/30 Virus Mail Killer Ver. up to 1.995
2019/03/16 デバッグ用テンプレート
2019/03/09 ラベルコントロールのツールチップの表示
2019/03/02 Multi Function Alarm Ver. up to 2.00


2019/03/30 Virus Mail Killer Ver. up to 1.995

今日付けで Virus Mail Killer をバージョンアップしました。バージョンアップ内容は以下の通りです。

Ver.1.995 2019/03/30

今回の修正は全て不具合の修正です。やはり開発言語を変えるという大幅な修正をしたせいか不具合が多かったです。

Ver.1.995 という中途半端なバージョン番号になってしまって申し訳ないです。

シェアウエア関係はステップ数も多いこともあり、まだ更新できていません。また最近公開したいくつかのフリーウエアにバグも見つかっています。今回はその中で特に大きめの不具合がある Virus Mail Killer を最優先で修正しました。見つかっている他のフリーウエアのソフトのバグも順次直していきます。


2019/03/16 デバッグ用テンプレート

デバッグの際には、途中の変数の値を表示したいことが多くあります。

ここでは、最近開発したデバッグ用テンプレートをほぼ原文のまま公開します。
Debug.h
//---------------------------------------------------------------------------
#pragma message("Debug.h compiling")
//---------------------------------------------------------------------------
#pragma once
//---------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <typeinfo>
#include <sstream>
//---------------------------------------------------------------------------
#define TRACEFILENAME "C:\\Users\\<ログインユーザー名>\\Desktop\\trace.txt"
//---------------------------------------------------------------------------
#define DEBUG(...) DebugPair(#__VA_ARGS__, __VA_ARGS__)
#define TRACE(...) TracePair(#__VA_ARGS__, __VA_ARGS__)
//---------------------------------------------------------------------------
#include "CString.h"
#include "CFile.h"
//---------------------------------------------------------------------------
// 以下はクラスの中で定義できない、CDebug がコンパイルされない
template <typename THead, typename... TBody>
inline void Debug(THead head, TBody... body)
{
	CDebug dbg(", ");
	dbg.AddItem(head, body...);
	MessageBox(NULL, dbg.line.str().c_str(), "Debug", MB_ICONINFORMATION);
}
//---------------------------------------------------------------------------
template <typename THead, typename... TBody>
inline void Trace(THead head, TBody... body)
{
	CDebug dbg(", ");
	dbg.AddItem(head, body...);
	dbg.TraceOn();
	FILE* f;
	fopen_s(&f, TRACEFILENAME, "at");
	fputs(dbg.line.str().c_str(), f);
	fputs("\n", f);
	fclose(f);
}
//---------------------------------------------------------------------------
template <typename THead, typename... TBody>
inline void DebugPair(CString Args, THead head, TBody... body)
{
	CDebug dbg("\n");
	dbg.AddItem(head, body...);
	CString ret = dbg.PairEdit(Args, dbg.line.str().c_str(), "\t= ", "\n");
	MessageBox(NULL, ret.str(), "Debug", MB_ICONINFORMATION);
}
//---------------------------------------------------------------------------
template <typename THead, typename... TBody>
inline void TracePair(CString Args, THead head, TBody... body)
{
	CDebug dbg("\n");
	dbg.AddItem(head, body...);
	dbg.TraceOn();
	FILE* f;
	fopen_s(&f, TRACEFILENAME, "at");
	CString ret = dbg.PairEdit(Args, dbg.line.str().c_str(), "=", ", ");
	fputs(ret.str(), f);
	fputs("\n", f);
	fclose(f);
}
//---------------------------------------------------------------------------
//CDebug<head, body...> dbg; という宣言ができないので、以下のクラステンプレートはうまくいかない
//template <typename THead, typename... TBody>
class CDebug
{
public:
	template <typename THead, typename... TBody>
	friend inline void Debug(THead head, TBody... body);
	template <typename THead, typename... TBody>
	friend inline void Trace(THead head, TBody... body);
	template <typename THead, typename... TBody>
	friend inline void DebugPair(CString Args, THead head, TBody... body);
	template <typename THead, typename... TBody>
	friend inline void TracePair(CString Args, THead head, TBody... body);
private:
	CDebug(CString separator) : separator(separator){};
	CString separator;
	std::stringstream line;
//
	template <typename THead, typename... TBody>
	void AddItem(THead head, TBody... body)
	{
		ToString(head);
		if ( sizeof...(body) > 0 ) line << separator.str();
		AddItem(body...);
	}
//
	template <typename THead>
	void AddItem(THead head){ ToString(head);}
//
	template <typename THead>
	void ToString(THead head)
	{
		CString type = typeid(THead).name();
		if ( type.Find("*") ){
			if ( type.Find("char") )
				line << head;
			else
				line << type.str() << ":" << head;}
		else {
			if ( type.Find("char") )
				line << "'" << head << "'";
			else if ( type.Find("bool") )
				line << (head ? "true" : "false");
			else if ( type.Find("int") || type.Find("long") || type.Find("short") )
				line << head;
			else
				line << type.str() << ":" << head;}
	}
	//独自作成クラスは以下で"ToString"を定義
	void ToString(CString cstr){ line << cstr.str();}
	void ToString(CFile cfn){ line << cfn.FullPath().str();}
//
	static bool TraceFlg;
	inline void TraceOn(void)//プロセス毎にクリアする場合に必要
	{
		if ( CDebug::TraceFlg ) return;
		DeleteFile(TRACEFILENAME);
		CDebug::TraceFlg = true;
	}
//
	CString PairEdit(CString Args, CString Values, CString equal, CString newseparator)
	{
		CString ret("");
		CString args = Args;
		CString values = Values;
		while(true){
			int apos = args.Pos(",");
			int vpos = values.Pos(separator);
			if ( apos == -1 && vpos == -1 ){
				ret |= args.Trim()|equal|values;
				break;}
			else if ( apos == -1 || vpos == -1 ){
				ret |= "Error Arg = "|args|" Value = "|values;
				break;}
			else {
				ret |= args.Left(apos).Trim()|equal|values.Left(vpos)|newseparator;
				args = args.Sub(apos + 1);
				values = values.Sub(vpos + separator.Length());}}
		return ret;
	}
};
//---------------------------------------------------------------------------
*.cpp のどこか
bool CDebug::TraceFlg = false;

この中の CString というクラスは、作者独自の物なので、お好きな文字列処理クラスに変えてください。Visual Studio 2017 で作成していますが、思いっきり処理系に依存しているので、その辺は変更してください。

使い方は以下のような感じです。
	char c = 'a'; 
	char* str = "aaa";
	int i = 8;
	float f = 2.5f;
	double d = 4.3;
	DWORD dw = 54321;
	bool b = false;
	HWND Handle = (HWND)123456;
	CString cstr("abcdefg");
	CFile fn("C:\\");
	Debug(c, str, i, f, d, dw, b, cstr, Handle, fn);
	Trace(c, str, i, f, d, dw, b, cstr, Handle, fn);
	Debug(dw);//引数が1つの時のテスト
	Trace(dw);//引数が1つの時のテスト
	DEBUG(c, str, i, f, d, dw, b, cstr, Handle, fn);//変数名も出力されるかのテスト
	TRACE(c, str, i, f, d, dw, b, cstr, Handle, fn);
	DEBUG(cstr);
	TRACE(cstr);
	DEBUG(NULL);

可変個の引数が可能で、引数の型に関しても制限はありません。

DEBUG、TRACE のように大文字にした場合、変数名まで自動で出てきます。


2019/03/09 ラベルコントロールのツールチップの表示

以下のソースでラベルコントロールのツールチップを表示させようとしてうまく行きませんでした。
	HWND hwndTT = CreateWindow(TOOLTIPS_CLASS, NULL, TTS_ALWAYSTIP,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		Handle, (HMENU)NULL, hInstance, NULL);
//
	TOOLINFO ti;
	ti.cbSize = sizeof(TOOLINFO);
	ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;
	ti.hwnd = Handle;
	ti.hinst = hInstance;
	ti.uId = (UINT_PTR)GetDlgItem(Handle, <ラベルコントロールのID>);
	ti.lpszText = (LPTSTR)text.str();
	SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)&ti);
//
	HDC hdc = GetDC(hwndTT);
	CString txt = text;//CString は独自の文字列処理クラス
	int w = 0;
	while( true ){
		SIZE sz;
		int p = txt.Pos("\n");//'\n'が0から数えて何番目の文字か
		if ( p == -1 ){
			GetTextExtentPoint32(hdc, txt.str(), txt.Length(), &sz);
			w = max(w, sz.cx);
			break;}
		CString txttail = txt.Sub(p + 1);
		txt.SetAt(p, '\0');
		GetTextExtentPoint32(hdc, txt.str(), txt.Length(), &sz);
		w = max(w, sz.cx);
		txt = txttail;}
	SendMessage(hwndTT, TTM_SETMAXTIPWIDTH, 0, (LPARAM)w);
	SendMessage(hwndTT, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAKELPARAM(popuptime, 0));

9年前はその解決方法を見つけて対応していたのですが、ネットで再検索してしまいました。参考になることが見つからなかったのですが、9年前を思い出して解決しました。一応ネットでは見つけにくいので改めてここに書いておくことにしました。

ラベルコントロールの Notify を True にしてください

赤字の部分を赤字に修正 6/19


2019/03/02 Multi Function Alarm Ver. up to 2.00

今日付けで Multi Function Alarm をバージョンアップしました。バージョンアップ内容は以下の通りです。

Ver.2.00 2019/03/02

1番目から3番目までの修正はいつもの通りです。

4番目の修正は「伝言板」というスクリーンセーバーは既に無く、その代わりが「3Dテキスト」になっているからです。

5番目の修正は壁紙の表示形式が「スパン」とか「ページ幅に合わせる」とか色々増えたその対応です。

6番目と8番目の修正は文字通りです。

7番目の修正についてはDOSコマンドのアプリケーション側がサポートしていないといけません。具体的には、
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	:
	:
	ShowWindow(Handle, nCmdShow);
	:
	:
}

とコーディングしなければなりません。マイクロソフト系のアプリケーションは大体こうなっていると思います。ただ作者のソフトはこうなっていません。

またProcessx64.exe がアーカイブに添付されているのは、スクリーンセーバーは通常「c:\Windows\System32」の中にあるのでその指定ができるようにするために、ここの「@GetOpenFileName」を使っています。


2019年2月分

戻る