2024年11月
 12
3456789
10111213141516
17181920212223
24252627282930

カテゴリー

アーカイブ

ブログ統計情報

  • 99,463 アクセス


MFC ウィンドウ位置の保存

以前から,実装しようとしていつも見返してしまうので…


単純にウィンドウ位置を保存するタイミングは OnDestroy が良さそう.
ウィンドウ位置を保存するために ClassWizard で OnDestroy を追加
他には,ダイアログで「OK」を押された場合( OnOK )などもある.


ウィンドウ位置を保存するコードは次の様な感じ.

	if (!wnd->IsIconic())	{
		CRect	wRect ;
		wnd->GetWindowRect(&wRect) ;
	//	SaveRect(SecDialog,entry,wRect) ;
		}

起動時は

	CRect	rect ;	rect.SetRectEmpty() ;
	//	rect = GetRect(SecDialog,entry,rect) ;
	if (!rect.IsRectNull()) {
	//	::SystemParametersInfo(SPI_GETWORKAREA,0,&workArea,0) ;
	//	範囲の補正
		wnd->MoveWindow(rect) ;
		}

CMainFrame を持つ AP では CMainFrame::OnCreate で,ダイアログの場合は OnInitDialog で MoveWindow する.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

CSpinButtonCtrl Set buddy integer

引継いだプロジェクトを変更していて,CSpinButtonCtrl が意図した動作にならない.
元は「整数」だったものを,0.25 のステップに変更.


デバッガで追いかけると,0.25 で増減はできている.
が,対応する「エディット ボックス」の表示は「整数」で 1 のステップで増減してしまう.


影響しているコードを見たが,特に問題になりそうな部分は見当たらない.
こうなると,どこかの設定と思い見直すと,あった.
「Spin プロパティ」-「数値の自動表示」
「Set buddy integer」にチェックが入っていた.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

CComboBox::SetItemHeight (-1,…)

高 DPI 対応で修正していて,コンボボックス(特に,オーナードロー?)の高さが他に比べて不自然.
コンボボックスの高さの変更


ドキュメントを見ると,CB_SETITEMHEIGHT と思うが,指定方法がよくわからない.
コンボボックス 高さ 変更」で 検索する と「できない」と記述されている所もある.


CB_SETITEMHEIGHT で検索していると,-1 を指定しているものがある.
さらに,CB_GETITEMHEIGHT のドキュメントを見ると,次の様にある.

選択フィールドの高さを取得するには、このパラメーターは -1 である必要があります

どうも CB_SETITEMHEIGHT の表現がうまくないものと思う.


次の様なコードで対応.

{
	CRect	rect ;
	m_CtrlStrText.GetClientRect(&rect) ;
	FontFace.SendMessage(CB_SETITEMHEIGHT,-1,rect.Height()) ;
	FontFace.SendMessage(CB_SETITEMHEIGHT, 0,rect.Height()*15/10) ;
	}

CComboBox::SetItemHeight (-1,…)


2023/05/16
ドロップダウンの幅がうまくなかったが,共通コードを見るといろいろ考慮しなければならない部分が多い.
そのため,次の様なコードで対応.

{
	new_w = now_w ;
//	new_w = now_w * 15 / 10 ;
	new_w = int(new_w * ::GetDPI_scale(this->GetSafeHwnd())) ;  // new_w*(::GetDpiForWindow()/96.)
	FontFace.SendMessage(CB_SETDROPPEDWIDTH,new_w) ;
	}

SendMessage(CB_SETDROPPEDWIDTH,...)


間違っているかもしれないが,CB_SETITEMHEIGHT を簡単にテストしたことのまとめ.

通常のコンボボックスの場合 -1 で,全ての項目の高さを設定できる
オーナードロー 固定 -1 で,エディットボックス部分の高さを指定
0 で,ドロップ部分の項目の高さを指定
オーナードロー 可変 -1 で,エディットボックス部分の高さを指定
0 以上で,ドロップ部分のそれぞれの高さを指定
Is this 投稿 useful? Useful Useless 1 of 1 people say this 投稿 is useful.

VirtualBox PXE-E06

Win11 上の仮想マシン Win10 の Windows Update での再起動で,
PXE-E06: Option ROM requires DDIM support.
PXE-E06: Option ROM requires DDIM support.
検索してみた が,あまりいい情報に引っ掛からない.


Windows Update での再起動だったので心配だったが,仮想マシンを一度 OFF して,再起動.
特に何もなかったかの様に起動した.
何だったのだろう.


2024/04/05
その後頻繁にこの現象が発生する.VirtualBox と Windows との相性か?

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

高 DPI VC 「高い DPI 認識」

引き続きいろいろとやっているが…
異なる DPI での対応は簡単ではなさそう.
VC のプロパティで「モニターごと高い DPI 認識」としてビルドしていたが,モニタ間を移動するとうまくない.
ちゃんと対応すれば良いのだろうが,簡単ではない.
そのため exe のプロパティで「システム(拡張)」で良いと思っていたが,幾つかのバグ?(未対応)がある.


VC のプロパティで「高い DPI 認識」にしてビルドしたものの方がうまく機能している様な気がする.
「DPI 認識」設定 VC 10 と VC 14 でビルドしたもの
左から VC 10 ,14 ,10 ,14 としたもの.
タスクマネージャで見ると,VC 10 exe は「システム」として表示される.


左側のモニタの範囲は次の様になる.

-1920  130  0  1210	100%   1920  1080	「非対応」や「モニタごと」の場合
-3840  260  0  2420	200%   3840  2160	「システム」とした exe の場合

右側は ( 0 , 0 ) – ( 3840 , 2160 ) .


GDI スケーリングの動作として,次の記述があった.

アプリケーションが 100% (96 DPI) の倍数ではないディスプレイで実行されている場合、ベクター グラフィックスとテキストは、ディスプレイの倍率より 100% 高い最初の整数倍にレンダリングされます。たとえば、アプリケーションが 225% の縮尺のディスプレイ上にある場合、ベクター グラフィックスとビットマップは 300% でレンダリングされます。その後、DWM はレンダリングされたコンテンツを 225% のスケールに縮小します。この場合、スケールダウンによりアプリケーションのあいまいさが目立ちますが、100%レンダリングされたコンテンツを単純にスケールアップするよりも見栄えが良くなります。

Improving the high-DPI experience in GDI based Desktop Apps



How to build high DPI aware native Windows desktop applications


2023/05/12
「システム(拡張)」で幾つか変な動作があったが,「高い DPI 認識」でビルドしたものであれば良さそう.
「高い DPI 認識」

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

CWinApp::m_pszRegistryKey

VC で MFC プロジェクトを作成すると,CXxxApp::InitInstance が次の様になる.
SetRegistryKey(_T(“アプリケーション ウィザードで生成されたローカル アプリケーション”));
ドキュメントにある様に,会社名などを指定する.
The registry key is usually the name of a company.


あまりやってはいけないことだろうと思うが,ドキュメントを見ていると,その設定した値 CWinApp::m_pszRegistryKey を直接変更できる.
そこのサンプルコードが… 何年も前から変わっていない.
CWinApp::m_pszRegistryKey


CWinApp::SetRegistryKey の動作は,新しいキーに変更して m_pszPforileName も変更している.
CWinApp::SetRegistryKey


MFC を使用するコンソール AP での SetRegistryKey の使用は次の所.
https://dev.mish.work/wordpress/2021/07/21/console-ap-setregistrykey/

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

[MyDNS.JP] IPアドレスの通知が …

MyDNS.JP から次の様なメールが …
[MyDNS.JP] IPアドレスの通知が8日間確認できません。
「コントロールパネル」-「外部アクセス」-「DDNS」を見ると,前回の更新が 2023/04/19 のまま.
「今すぐアップデート」を押しても変わらず.
対象のものを選択して「テスト接続」しても,エラーになってしまう.


ログを確認すると,先日 DSM の更新があり,その後うまく機能していない?
もう一つの NAS はうまく動作しているので,対象の NAS を「再起動」.
通知はされた.「今すぐアップデート」も効いている.
あとは,定期的に更新されるか …


2023/05/10
その後うまく更新(通知)できている.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

OpenMP Fatal User Error 1002

OpenMP が有効な時でも動作する様にテストしていると…
Fatal User Error 1002: A ‘#pragma omp critical’ is illegally nested in one of the same name
Fatal User Error 1002: A '#pragma omp critical' is illegally nested in one of the same name
元々あった次のコードに #pragma omp critical としたことによるもの.

tstring	Get_Self_Original	(void)
{
	static	bool	Yet = true ;
	static	tstring	Self_original ;
	if (Yet) {
		tstring	self_name = ::Get_module_name() ;
		Self_original = Get_OriginalFilename(self_name.c_str()) ;
		if (Self_original.empty()) {
			Self_original = ::Path_GetName(self_name) ;
			}
		Yet = false ;
		}
	return	Self_original ;
	}

次の様に並列処理可能にすることで動作する様にはなるが …

tstring	Get_Self_Original	(void)
{
	#ifdef	_OPENMP
	//	#pragma	omp	critical	(_Get_Self_Original_)
	#endif
	{
	#ifdef	_OPENMP
			bool	Yet = true ;
			tstring	Self_original ;
	#else
		static	bool	Yet = true ;
		static	tstring	Self_original ;
	#endif
		if (Yet) {
			tstring	self_name = ::Get_module_name() ;
			Self_original = Get_OriginalFilename(self_name.c_str()) ;
			if (Self_original.empty()) {
				Self_original = ::Path_GetName(self_name) ;
				}
			Yet = false ;
			}
		return	Self_original ;
		}
	}

以前にも同じようなことをやっていた.
https://dev.mish.work/wordpress/2010/03/31/openmp-error-1002/


2023/04/27
この関数は exe の起動直後などに一度呼ばれることを意図しているので,critical をもっと局所的に.

tstring	Get_Self_Original	(void)
{
	static	bool	Yet = true ;
	static	tstring	Self_original ;
	if (Yet) {
		#ifdef	_OPENMP
			#pragma	omp	critical	(_Get_Self_Original_)
		#endif
		{
			tstring	self_name = ::Get_module_name() ;
			Self_original = Get_OriginalFilename(self_name.c_str()) ;
			if (Self_original.empty()) {
				Self_original = ::Path_GetName(self_name) ;
				}
			Yet = false ;
			}
		}
	return	Self_original ;
	}

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

C++ メンバ関数テンプレート

.ini に対してのアクセスは関数として用意した が,今度はレジストリ.


クラスとして実装して,基本的な動作は何とかできた.
さらに .ini と同様に,文字列としてアクセスする部分を呼出す関数をテンプレートに…
と思って書き始めたが,今まで使ってなかったのか書き方がわからない.
検索すると,次の所があり参考にさせてもらった.
メンバ関数テンプレート | Programming Place Plus C++編【言語解説】 第33章
メンバー関数テンプレート


特に通常の関数テンプレートと書き方は変わらない.

	template	<typename	T>	T   	get	(   LPCTSTR ent,const T& def)	{
		tstring	dst = ::To_tstring(def) ;
		tstring	str = this->get(ent,dst.c_str()) ;
		T   	val ;
		::string_to(str.c_str(),&val) ;
		return	val ;
		}

	template	<typename	T>	bool	set	(   LPCTSTR ent,const T& val)	{
		tstring	str = ::To_tstring(val) ;
		return	this->set(ent,str.c_str()) ;
		}

メンバ関数テンプレート

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

C++ 戻り値の異なる関数 template

先日からやっている .ini やレジストリにアクセスする関数.
MFC の CWinApp::GetProfileString , CWinApp::WriteProfileString にあたる部分は目途がついた.
それで,それらを呼出す部分.前に作成したものもそうだったが,型ごとにクラスの関数を定義していた.
レジストリにアクセスするクラス
これらをもう少し簡単にできないかと…


set の方は,特に難しい所はない(::To_tstring は,文字列に変換する関数として用意している).

template	<class T>	bool	INI_set	(LPCTSTR sec,LPCTSTR ent,const T& val)
{
	tstring	ini = ::INI_get_module_ini() ;
	tstring	str = ::To_tstring(val) ;
	return	::INI_set(ini.c_str(),sec,ent,str.c_str()) ;
	}

get の場合,文字列から変数に変換する方法をどうするか?
例えば,atoi や atof ,他にも 4 つの整数の文字列を RECT に変換するなど.
検索すると template で可能みたい だが…
よくわからなかったので,簡単な方法にした.

inline	RECT	To_RECT		(LPCTSTR str)
{
	RECT	rect	=	{	0	} ;
	{
		v_tstring	str_ary = ::String_SplitSpace(str,_T(" ,\t\r\n")) ;
		if (0 < str_ary.size())	{	rect.left	= ::ttoi4(str_ary[0]) ;	}
		if (1 < str_ary.size())	{	rect.top	= ::ttoi4(str_ary[1]) ;	}
		if (2 < str_ary.size())	{	rect.right	= ::ttoi4(str_ary[2]) ;	}
		if (3 < str_ary.size())	{	rect.bottom	= ::ttoi4(str_ary[3]) ;	}
		}
	return	rect ;
	}
inline	bool	string_to	(LPCTSTR str,RECT*  rect_)	{	*rect_ = ::To_RECT (str) ;	return	true ;	}
inline	bool	string_to	(LPCTSTR str,POINT* point)	{	*point = ::To_POINT(str) ;	return	true ;	}
inline	bool	string_to	(LPCTSTR str,SIZE*  size_)	{	*size_ = ::To_SIZE (str) ;	return	true ;	}

それぞれの型に合わせた関数を呼べるようになったので template に.

template	<class T>	T	INI_get	(LPCTSTR sec,LPCTSTR ent,const T& def)
{
	tstring	ini = ::INI_get_module_ini() ;
	tstring	dst = ::To_tstring(def) ;
	tstring	str = ::INI_get(ini.c_str(),sec,ent,dst.c_str()) ;
	T	val ;
	::string_to(str.c_str(),&val) ;
	return	val ;
	}

これで,次の様な使い方ができる様になる.

{
	POINT	point = ::POINT_set(   10,   20) ;
	SIZE	size_ = :: SIZE_set( 1111,  525) ;
	RECT	rect_ = :: RECT_set(point,size_) ;
	{
		::INI_set(_T("test"),_T("rect_"),rect_) ;
		::INI_set(_T("test"),_T("point"),point) ;
		::INI_set(_T("test"),_T("size_"),size_) ;
		std::tout << ::To_tstring(::INI_get(_T("test"),_T("rect_"),rect_)) << std::endl ;
		std::tout << ::To_tstring(::INI_get(_T("test"),_T("point"),point)) << std::endl ;
		std::tout << ::To_tstring(::INI_get(_T("test"),_T("size_"),size_)) << std::endl ;
		}
	}

::INI_set ,::INI_get の動作テスト

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

C++ NonCopyable

MFC を使用しないコードに書き直していて,代入できない構造体が欲しくなった.
オリジナルのコードは 20 年以上前のもので,CRegKey が簡単には使えなかった?頃.


C++ クラス 代入できなくする」で検索.
コピー禁止を徹底させるNoncopyableクラス
More C++ Idioms/コピー禁止ミックスイン(Non-copyable Mixin)
明示的に既定された関数および削除された関数
MFC の CObject も同様と思いソースを見ると,やはり private になっている.
MFC CObject 代入の禁止
C++11 以降では =delete も使える.
関数のdefault/delete宣言
wiki C++11


これらを調べていて,次の所を見つけた.
旧時代のC言語を使うのはそろそろやめよう。
2016年、C言語はどう書くべきか (前編)
2016年、C言語はどう書くべきか (後編)
幾つかは既に意識しているが,Windows に依存する部分はなかなかできてない.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

RegOpenKeyEx REGSAM

レジストリアクセスのコードを書き直していて,::RegOpenKeyExsamDesired を調べてみた.

KEY_READ              (0x20019)	0010 0000 0000 0001 1001
KEY_WRITE             (0x20006)	0010 0000 0000 0000 0110
KEY_EXECUTE           (0x20019) 0010 0000 0000 0001 1001

KEY_QUERY_VALUE        (0x0001)	     0000 0000 0000 0001
KEY_SET_VALUE          (0x0002)	     0000 0000 0000 0010
KEY_CREATE_SUB_KEY     (0x0004)	     0000 0000 0000 0100
KEY_ENUMERATE_SUB_KEYS (0x0008)	     0000 0000 0000 1000
KEY_NOTIFY             (0x0010)	     0000 0000 0001 0000

KEY_CREATE_LINK        (0x0020)	     0000 0000 0010 0000
KEY_WOW64_64KEY        (0x0100)	     0000 0001 0000 0000
KEY_WOW64_32KEY        (0x0200)	     0000 0010 0000 0000

KEY_ALL_ACCESS        (0xF003F)	1111 0000 0000 0011 1111

ソースを見た方が早かったか?
RegOpenKeyEx REGSAM


読み込み時,KEY_READ の方が速いなどはあるのか?それともファイルアクセスなどと同じ?

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

GetMonitorInfo

2002/08 に,マルチディスプレイ対応のコードを書いている.
今回,高 DPI 対応やディスプレイ位置が変わった時などのためもう一度…


ChatGPT で.
ChatGPT  GetMonitorInfo 使い方サンプル
そのままでは VC 6 ではうまくビルドできなかったので,VC 8 で.
printf を使用しているので #include <cstdio> が必要.
そのまま実行すると 1920×1080 となる.
GetMonitorInfo
高 DPI スケール設定を「アプリケーション」とすると,3840×2160 .


2023/04/14
以前のコードを見ると,プライマリのみの情報は ::SystemParametersInfo などを使用している.
これで求められる SPI_GETWORKAREA は,::GetMonitorInfo で戻されるものと同じ?

システム     0  61 1920 1080
アプリケーション 0 122 3840 2160

::GetSystemMetrics(SM_?VIRTUALSCREEN) は,-1920 0 .
::GetSystemMetrics(SM_C?VIRTUALSCREEN) は,上をずらしているので少し異なる.

システム     3840 1210
アプリケーション 5760 2160

Z170S0  ディスプレイの配置
https://learn.microsoft.com/ja-jp/windows/win32/gdi/the-virtual-screen

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

MFC タイトルバーの変更

ダイアログベースであれば C…Dlg::OnInitDialog() に次の様なコードを追加.

	{
		tstring	str_title = ::GetWindowText(this->GetSafeHwnd()) ;
		       	str_title+= _T(" ") + ::Get_ModuleVersion() + ::Get_BuildStrMSC() ;
		SetWindowText(str_title.c_str()) ;
		}

SDI や MDI の場合は,
MainFrm.h に OnUpdateFrameTitle を追加.

	virtual void OnUpdateFrameTitle (BOOL bAddToTitle);

MainFrm.cpp に次の様な OnUpdateFrameTitle を追加.

//	SDI
void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
	CFrameWnd::OnUpdateFrameTitle(bAddToTitle) ;
	{
		tstring	str_title = ::GetWindowText(this->GetSafeHwnd()) ;
		       	str_title+= _T(" ") + ::Get_ModuleVersion() + ::Get_BuildStrMSC() ;
		SetWindowText(str_title.c_str()) ;
		}
	}
//	MDI
void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
	CMDIFrameWnd::OnUpdateFrameTitle(bAddToTitle) ;
	{
		tstring	str_title = ::GetWindowText(this->GetSafeHwnd()) ;
		       	str_title = ::MDI_Add_VerBuildStr(str_title.c_str()) ;
		SetWindowText(str_title.c_str()) ;
		}
	}

S_asZ のタイトルバーにバージョンなどの付加

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

高 DPI CToolBar のリサイズ

CToolBar を使用した 自前のコード
CDialogBar や CStatusBar はスケーリングしてくれるのに,CToolBar は対応しない?
以前は設定などで変更可能なコードにしていたが,DPI を求める方法に.

	if (newExtendSize == CSize(0,0)) {
		double	dpi_s = ::GetDPI_scale(toolBar->GetSafeHwnd()) ;  // ::GetDpiForWindow()/96.
		if (dpi_s > 1) {
			CToolBarCtrl&	tbCtrl = toolBar->GetToolBarCtrl() ;
			CSize	orgSize = tbCtrl.GetButtonSize() ;
			CSize	newSize = orgSize ;
			newSize.cx = int(orgSize.cx*dpi_s) ;
			newSize.cy = int(orgSize.cy*dpi_s) ;
			newExtendSize.cx = newSize.cx - orgSize.cx ;
			newExtendSize.cy = newSize.cy - orgSize.cy ;
			resizeType = 'R' ;
			}
		}

あとは既存コードの,ビットマップのリサイズと CToolBar::SetSizes を呼出せば良さそう.


CMFCToolBar は DPI を正しく処理しているみたいで,その部分のコード.
…\VC\…\atlmfc\src\mfc\afxtoolbar.cpp の CMFCToolBar::LoadToolBarEx .
CMFCToolBar::LoadToolBarEx  SetSizes


まだ幾つか問題はあるが,今回の対応部分としてはこれで良さそう.
ToolBar::Resize のコードを変更


更にツールバー上のコンボボックスのスケーリングは次の様にした.

	{
		int		width = 50 ;
		{
			double	dpi_s = 1. ;
			    	dpi_s = ::GetDPI_scale(AfxGetMainWnd()->GetSafeHwnd()) ;
			    	dpi_s = ::GetDPI_scale(    m_wndToolBar.GetSafeHwnd()) ;
			    	dpi_s = ::GetDPI_scale(           this->GetSafeHwnd()) ;
			if (dpi_s > 1.) {
				width = int(width*dpi_s) ;
				}
			}
		m_wndToolBar.SetButtonInfo  (19,ID_COMBO_ANGLE,TBBS_SEPARATOR,width) ;
		CRect	rectCombo ;
		m_wndToolBar.GetItemRect    (19,&rectCombo) ;
		rectCombo.top = 1 ;
		rectCombo.bottom = rectCombo.top + 300 ;
		if (!m_ComboAngle.Create(CBS_DROPDOWN | WS_VSCROLL | WS_VISIBLE,rectCombo,&m_wndToolBar,ID_COMBO_ANGLE)) {
			TRACE0("Failed to ComboBox\n");
			return -1;
			}
		m_ComboAngle.SetFont(m_wndToolBar.GetFont()) ;
		m_ComboAngle.AddString(_T(" 0.")) ;
		m_ComboAngle.AddString(_T("10.")) ;
	//	...
		m_ComboAngle.AddString(_T("90.")) ;
		}
Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

drawlog が更新されない?

Web サーバ管理用の,アクセスログの表示が更新されなくなった.
DS220  Web サーバへのアクセスログ
/tmp/ がいっぱいになったかと思い,解放したが変わらず.
それならと思い NAS を再起動したが,それでも変わらない.


不正なアクセスにより,ログにゴミが入ったみたいで,そこで表示データの生成が止まっていた.
ログに "\0" が入っている

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

高 DPI テスト exe

先日の exe をテストしていると…
TToPA.exe を「システム(拡張)」で実行


高 DPI をテストするために,次の様なコードの exe を作成.

void CT_aesDlg::OnDropFiles(HDROP hDropInfo) 
{
	v_tstring	drop_files = ::DropFilesTo(hDropInfo) ;
	for (size_t index=0 ; index<drop_files.size() ; index++) {
		tstring	drop_file = drop_files[index] ;
		tstring	ext = ::Path_GetExtLow(drop_file) ;
		if (ext != _T("exe"))	{	continue ;	}
		{
			S_Exec	se ;
			se.SetFile(drop_file.c_str()) ;
			se.Execute() ;
			}
		}
	CDialog::OnDropFiles(hDropInfo);
	}

この exe に,他の exe をドロップして起動すると,「高 DPI スケール設定」が引き継がれる.
「高 DPI スケール設定」
これらの設定は,次の所に持っている?

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
   A	~ HIGHDPIAWARE	
   S	~ DPIUNAWARE	
   E	~ GDIDPISCALING DPIUNAWARE	

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers


それぞれを実行すると表示が異なることはわかるが…
HiDPI テスト exe
左から,「システム」,「システム(拡張)」,「アプリケーション」.


「システム」と「システム(拡張)」を区別する方法がわからない.
また「システム(拡張)」.exe で,何かの情報の取得が違っていて 表示が正しくない ものと思う.


::GetDeviceCaps の情報の表示は dc.DrawText(str,rect,DT_LEFT) としている.
この時,表示するフォントを指定していないため,「アプリケーション」では小さくなってしまう.
CFont::CreatePointFontIndirect
CFont::CreatePointFont などを呼ぶことで対応可能.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

tcsncpy_s Buffer is too small

先日更新した ツール をテストしていると,フォントによりアプリケーションエラー?となってしまう.
デバッガで追いかけると,
—————————
Microsoft Visual C++ Runtime Library
—————————
Debug Assertion Failed!
Program: c:\Temp\i_Tools\TToPA\Debug.120\TToPA.exe
File: f:\dd\vctools\crt\crtw32\h\tcsncpy_s.inl
Line: 62
Expression: (L"Buffer is too small" && 0)
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
—————————
中止(A) 再試行(R) 無視(I)
—————————
tcsncpy_s Buffer is too small
CRichEditCtrl を使用した CHARFORMATW の szFaceName の指定がうまくなかった.
::TcsNCpy(cf.szFaceName,LF_FACESIZE-1,faceName,LF_FACESIZE-1) ;
::TcsNCpy は,幾つかの環境でビルドできる様にしたもので,今回の場合は ::tcsncpy_s と同様もの.
faceName に与えたものが L"Bahnschrift Light SemiCondensed" で,コピー先のバッファが足りないため.
正しくは,
::TcsNCpy(cf.szFaceName,LF_FACESIZE-0,faceName,LF_FACESIZE-1) ;


これらの動作は,LOGFONT の時にもよく利用する.
既存のコードを検索してみると,LF_FACESIZE を正しく指定できていた.
::TcsCpy(lf.lfFaceName,LF_FACESIZE,tstring(faceName).substr(0,LF_FACESIZE-1).c_str()) ;
与えるデータは LF_FACESIZE-1 としている.

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

GetGlyphOutline ::PolyPolygon

求めたアウトラインをウィンドウに表示できる様な変換のコードを書いたので,その動作のテスト.

{
	HWND	hWnd = ::GetConsoleHwnd() ;
	RECT	rect = ::GetClientRect(hWnd) ;
	POINT	point= ::RECT_center(rect) ;
	int  	ch   = ::RECT_width(rect)/str.length()*10/7 ;
	{
		HDC  	hDC  = ::GetDC(hWnd) ;
		{
			#define	face_A	_T("Arial")
			#define	face_U	_T("Meiryo UI")
			#define	face_W	_T("Wingdings")
			{
				::ClearWindow(hWnd) ;
				int  	ry = -30 ;
				tstring	face_name = face_U ;
				vv_PLF	vv_plf= ::GetTTOutline(hDC,point,false,str.c_str(),face_name.c_str(),ch,0,0,ry,FW_DONTCARE) ;
				v_Vd2A	v_v2a = ::ToVd2A(vv_plf) ;
				::PolyPolygon(hDC,v_v2a) ;
				}
			}
		::ReleaseDC(hWnd,hDC) ;
		}
	}

::GetTTOutline の中では,文字の傾き,文字列の回転,Y の反転,表示位置の移動を行っている.
アウトラインデータを ::PolyPolygon で描画
更に三角形に分割.

		vv_PLF	vv_plf= ::GetTTOutline(hDC,point,false,str.c_str(),face_name.c_str(),ch,0,0,ry,FW_DONTCARE) ;
	//	v_Vd2A	v_v2a = ::ToVd2A(vv_plf) ;
		v_Vd2A	v_v2a = ::PLF_triangulation(vv_plf) ;

三角形に分割


文字列 DXF 変換 Ver. 1.72
poly_3d.hxx
poly_2d.hxx

Is this 投稿 useful? Useful Useless 2 of 2 people say this 投稿 is useful.

ダイアログバーのイベント処理

あまり使わないと,すぐ忘れてしまう…


1999/10 に作成したプロジェクトを変更していて,ダイアログバーにコントロールを追加.
ダイアログバーのイベント処理
ClassWizard で CMainFrame に対してイベント処理を追加すれば良い.
ダイアログバー CMainFrame にイベントの追加
今回の SDI.exe は,ビューでの処理のみなので「再描画」のコマンドメッセージを Post している.

void CMainFrame::OnUpdateRx() 
{
	PostMessage(WM_COMMAND,ID_REDRAW,0) ;
	}

ビューでは次の様にしてコントロールにアクセスしている.

	CMainFrame* pMain = (CMainFrame*)AfxGetApp()->m_pMainWnd ;
	CDialogBar* dlgBar= &pMain->m_wndMyDialogBar ;
	CComboBox*  font  = (CComboBox*) dlgBar->GetDlgItem(IDC_FONT_NAME) ;
	CEdit*      text  = (CEdit*)     dlgBar->GetDlgItem(IDC_STRING) ;
	CEdit*      e_rx  = (CEdit*)     dlgBar->GetDlgItem(IDC_RX) ;
	CEdit*      e_ry  = (CEdit*)     dlgBar->GetDlgItem(IDC_RY) ;

ダイアログバーの追加手順は次の所.
https://dev.mish.work/wordpress/2021/12/27/vc-6-dialog-bar/

Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.