ホーム » Windows (ページ 5)

Windows」カテゴリーアーカイブ

2025年7月
 12345
6789101112
13141516171819
20212223242526
2728293031  

カテゴリー

アーカイブ

ブログ統計情報

  • 117,988 アクセス




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.

高 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.

ShowWindow SW_HIDE SW_SHOW

ダイアログに「ピクチャーコントロール」を追加して,それの再描画.


以前よくやっていた方法.

void CFOutLineDlg::OnHeight() 
{
	if (m_CountSpin.m_hWnd == NULL)	{	return ;	}
	UpdateData(TRUE) ;
	InvalidateRect(NULL) ;
	}

これだと描画対象以外のコントロールも再描画するのでちらついてしまう.
ShowWindow SW_HIDE SW_SHOW


一度 ShowWindow で SW_HIDE して SW_SHOW することで,対象がコントロールだけになる.

void CFOutLineDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);
	if (m_CountSpin.m_hWnd == NULL)	{	return ;	}
	::FitWindow(this,&m_Image,5,TRUE,FALSE) ;
	m_Image.ShowWindow(SW_HIDE) ;
	m_Image.ShowWindow(SW_SHOW) ;
	}

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

GetGlyphOutline ポリゴン化

まだまだだが…

文字ごとのポリラインを取得できる様になったので,穴の処理と組み合わせてポリゴン化.
文字によっては,穴の処理でクロスしてしまうことがある.
https://itl.mish.work/Iwao/Doc/algo/div_cnvx/div_23_4.html
https://itl.mish.work/Iwao/Doc/algo/div_cnvx/div_23_5.html

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

GetGlyphOutline ポリラインの配列に

「MS ゴシック」と「MS Pゴシック」などの幅が,思っていたものと違った.
「MS ゴシック」と「MS Pゴシック」

v_PLF	TTPOLYGON_to	(LPTTPOLYGONHEADER buf,const DWORD rSize)
{
	vv_LQC	vv_lqc = ::to_LQC(buf,rSize) ;		//	buf を座標の配列に
	v_PLF	v_plf  = ::LQC_to(vv_lqc) ;		//	ポリラインに変換
	return	v_plf ;
	}

v_PLF	GetTTOutline	(HDC hDC,const UINT chr,GLYPHMETRICS* gm,const UINT format=GGO_NATIVE)
{
	v_PLF	v_plf ;
	{
		MAT2		mat2 = { {0, 1}, {0, 0}, {0, 0}, {0, 1} } ;
		DWORD	dwSize = ::GetGlyphOutline(hDC,chr, format, gm, 0, NULL, &mat2 ) ;
		if (dwSize != GDI_ERROR) {
			v_char	buffer(dwSize) ;
			GLYPHMETRICS gm2 = { 0 } ;
			::GetGlyphOutline(hDC, chr, format, &gm2, buffer.size(), &buffer[0], &mat2) ;
			v_plf = TTPOLYGON_to((LPTTPOLYGONHEADER)&buffer[0],dwSize) ;
			}
		}
	return	v_plf ;
	}

vv_PLF	GetTTOutline	(HDC hDC,LPCTSTR str,const bool tate,const UINT format=GGO_NATIVE)
{
	vv_PLF	vv_plf ;
	double	lastX = 0 ;		//	left
	double	lastY = 0 ;		//	top	tate
	int	ch = 0 ;
	int	cw = 0 ;
	{	//	chracter size
		TEXTMETRIC	tm = { 0 } ;
		::GetTextMetrics(hDC,&tm) ;
		ch = tm.tmHeight ;
		cw = tm.tmAveCharWidth ;
		}
	#ifdef	_UNICODE
	LPCTSTR		strP = str ;
	#else
	unsigned char*	strP = (unsigned char*)str ;
	#endif
	for (size_t mbCount=0 ; mbCount<_tcsclen(str) && *strP!='\0' ; mbCount++) {
		UINT	chr = 0 ;
		#ifdef	_UNICODE
		{
			chr = UINT(*strP) ;
			strP++ ;
			}
		#else
		{
			chr = _mbsnextc(strP) ;
			strP= _mbsinc(strP) ;
			}
		#endif
		if (chr == _T('\r'))	{	lastX = 0 ;	continue ;	}
		if (chr == _T('\n'))	{	lastY-= ch ;	continue ;	}
		if (chr == _T('\t'))	{	lastX+= cw ;	continue ;	}
		{
			GLYPHMETRICS	gm = { 0 } ;
			v_PLF	v_plf = ::GetTTOutline(hDC,chr,&gm,format) ;
			if (tate)	{	lastY -= (double(gm.gmBlackBoxY)+gm.gmCellIncX)/2 ;	}
			else		{								}
			Vd2		last(lastX,lastY) ;
			for (size_t index=0 ; index<v_plf.size() ; index++) {
				PLF	plf = v_plf[index] ;
				Vd2A	v2a = ::V2_Translate(::ToVd2A(::ToVd3A(plf)),last) ;
				v_plf[index] = PLF(PLF::line,::ToVd4A(::ToVd3A(v2a))) ;
				}
			vv_plf.push_back(v_plf) ;
			if (tate)	{					}
			else		{	lastX += gm.gmCellIncX ;	}
			}
		}
	return	vv_plf ;
	}

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

Q243285 の動作の確認

先日からやっている GetGlyphOutline .その Q243285 の動作を確認方法.
Q243285: HOWTO: Draw TrueType Glyph Outlines


その中の ::DrawT2Outline の動作を確認しようとコンソール AP でやってみたが,うまく表示されない.
コードを見ればわかるが,::PolyBezier に与えられている pt の y がマイナスの範囲になっている.


以前書いたコードで emf に出力するものがある.また,それの HWND への再生も.
それで,HDC に対して直接出力するのではなく,一度 emf に出力して,それを表示することに.


#include	<clocale>
#include	<iostream>
#include	<fstream>

#include	<Windows.h>

#include	"Q243285.hxx"

#include	"con_wnd.hxx"
#include	"E_MF.hxx"

LOGFONT	GetLogFont(
	LPCTSTR			faceName
,	const	bool	tate
,	const	int	ch
,	const	int	cw	=	0
,	const	double	rx	=	0
,	const	double	ry	=	0
,	const	int	weight	=	FW_DONTCARE
	)
{
	LOGFONT		lf =	{	0	} ;
	::GetObject(::GetStockObject(SYSTEM_FONT),sizeof(lf),&lf) ;
	if (tate)	{	lf.lfHeight	= (cw!=0)?cw:ch ;	lf.lfWidth	= ch/2 ;		}
	else		{	lf.lfHeight	= ch ;			lf.lfWidth	= cw ;			}
	if (tate)	{	lf.lfEscapement	= int((rx+ry-90)*10) ;	lf.lfOrientation= int((ry-90)*10) ;	}
	else		{	lf.lfEscapement	= int(rx*10) ;		lf.lfOrientation= int(ry*10) ;		}
	lf.lfWeight		= weight ;
	::TcsCpy(lf.lfFaceName,LF_FACESIZE,tstring(faceName).substr(0,LF_FACESIZE-1).c_str()) ;
	return	lf ;
	}

tstring	Get_TMP_path	(void)
{
	tstring	tmp_path ;
	size_t	size = MAX_PATH ;
	tmp_path.resize(size,0) ;
	::GetTempPath(DWORD(size),&tmp_path[0]) ;
	tmp_path = tstring(tmp_path.c_str()) ;
	return	tmp_path ;
	}

bool	DrawOutline(HDC hDC,int xStart,int yStart,LPCTSTR str)
{
	#ifdef	_UNICODE
	LPCTSTR			strP = str ;
	#else
	unsigned char*	strP = (unsigned char*)str ;
	#endif
//	tstring		tmp_path = ::Get_i_Tools_tmp_date() ;
	tstring		tmp_path = ::Get_TMP_path() ;
	tstring		emf_name ;
	for (size_t mbCount=0 ; mbCount<_tcsclen(str) && *strP!='\0' ; mbCount++) {
		UINT	chr = 0 ;
		#ifdef	_UNICODE
		{
			chr	= UINT(*strP) ;
			strP++ ;
			}
		#else
		{
			chr	= _mbsnextc(strP) ;
			strP	= _mbsinc(strP) ;
			}
		#endif
		{
			tstring	tcs ;
			{
				if (chr < 0xff) {
					tcs += TCHAR(chr) ;
					}
				else {
					tstring	buf ;	buf.resize(255,0) ;
					::_itot(chr,&buf[0],16)  ;
					tcs = buf.c_str() ;
					}
				std::tout << tcs << std::endl ;
				}
			{
				emf_name = tmp_path + tcs + _T(".emf") ;
				}
			}
		{
			E_MetaF	em(emf_name.c_str()) ;
			HDC	eDC = em.Get_HDC() ;
			{
				MAT2		mat2 = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
				GLYPHMETRICS	gm = { 0 };
				DWORD	dwSize = ::GetGlyphOutline(hDC,chr, GGO_NATIVE, &gm, 0, NULL, &mat2);
				if (dwSize != GDI_ERROR) {
					std::vector<char> buffer(dwSize);
					GLYPHMETRICS gm2 = { 0 };
					::GetGlyphOutline(hDC, chr, GGO_NATIVE, &gm2, buffer.size(), &buffer[0], &mat2);
					::DrawT2Outline  (eDC,(LPTTPOLYGONHEADER)&buffer[0],dwSize) ;
					}
				}
			}
		{
			E_MetaF::Play(::GetConsoleHwnd(),emf_name.c_str()) ;
			}
		}
	::TextOut(hDC,xStart,yStart+150,str,_tcslen(str)) ;
	return	true ;
	}

bool	test	(c_tstring& str)
{
	std::terr << str << std::endl ;
	{
		HWND	hWnd = ::GetConsoleHwnd  () ;
		{
			HDC	hDC  = ::GetDC(hWnd) ;
			{
				#define	face_A	_T("Arial")
				#define	face_M	_T("Meiryo UI")
				#define	face_W	_T("Wingdings")
				LOGFONT	lf    = ::GetLogFont(face_M,false,100) ;
				HFONT	hFont = ::CreateFontIndirect(&lf) ;
				HFONT	oFont = (HFONT)::SelectObject(hDC,hFont) ;
				::DrawOutline(hDC,200,200,str.c_str()) ;
				::SelectObject(hDC,oFont) ;
				::DeleteObject(hFont) ;
				}
			::ReleaseDC(hWnd,hDC) ;
			}
		}
	return	true ;
	}

Q243285 の動作の確認

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

GetGlyphOutline TTPOLYCURVE

TTPOLYCURVE の TT_PRIM_LINE と TT_PRIM_QSPLINE は昨日までのコードでできそう.
TT_PRIM_CSPLINE についてもコードはわかりそうだが,実際のデータがちょっとわからない.
Q243285 の ::DrawT2Outline では,処理はしていないみたい.
::MakeBezierFromQBSpline では Quadratic から Cubic にしている.
12: 2次ベジェ曲線を3次に変換する方法
2次ベジェ曲線から3次ベジェ曲線への変換
今まで使っていたコードの TT_PRIM_CSPLINE 部分も同様で,特に問題はなかったようにも思う.


曲線の種類と Vd2A(2D の double の配列)を持つ「LQC クラス」を用意するか.
その配列 v_LQC が 1つの TTPOLYGONHEADER となる?
‘1’,’2′,’3′ などは 1つの TTPOLYGONHEADER .’A’ や ‘b’ は 2つ,’B’ や ‘8’ は 3つとなる.
MS ゴシック   あいうえお ...
1つの文字を表現するために v_LQC の配列の vv_LQC を用意.
ここまでで ::GetGlyphOutline の出力を vv_LQC として変換できる.
この vv_LQC をポリラインに変換して,v_PLF(複数のポリラインなどを保持可能)に登録する.
これで文字列を vv_PLF(そのままでは輪郭,先日の穴の処理をしてポリゴンに)として保持できる.


2023/03/17
TT_PRIM_CSPLINE に関して
GetGlyphOutline で uFormat に GGO_NATIVE ではなく GGO_BEZIER を指定.
すると,制御点が 2 つのデータが返される.
ポリラインに変換するコードは次の様なもの?

Vd2A	LQC_3_to	(const LQC& lqc)
{
	Vd2A	pts ;
	if (lqc.size() > 0)	{
		Vd2	q0(lqc[0]) ;
		Vd2	q1(lqc[0]) ;
		Vd2	q2(lqc[0]) ;
		Vd2	q3(lqc[0]) ;
		for (size_t index=0 ; index+3<lqc.size() ; index++) {
			if (index == 0)	{	q0 = lqc[index+0] ;	}
						q1 = lqc[index+1] ;
						q2 = lqc[index+2] ;
						q3 = lqc[index+3] ;
			Vd2A	va = ::bezier(q0,q1,q2,q3) ;
			pts.insert(pts.end(),va.begin(),va.end()) ;
			q0 = q3 ;
			}
		}
	return	pts ;
	}
Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

GetGlyphOutline の続き

TTPOLYCURVE は,ポリラインはそのまま扱えるが,ベジェ曲線の場合はそれなりの処理が必要.
TT_PRIM_LINE , TT_PRIM_QSPLINE , TT_PRIM_CSPLINE
それで ChatGPT に Bezier と問合わせると,
ChatGPT  Bezier
2次ベジェ曲線
B(t) = (1-t)^2 * P0 + 2t(1-t) * P1 + t^2 * P2
3次ベジェ曲線
B(t) = (1-t)^3 * P0 + 3t(1-t)^2 * P1 + 3t^2(1-t) * P2 + t^3 * P3


w0 から w3 を求める部分の挿入位置が違っていたが,ほぼそのままのコード.
ベジェ曲線の Python のコード
C++ でのコードは次の様なもの.5 年位前に作成した 3 次ベジェ曲線 に合わせたコード.

Vd3A	bezier	(const Vd3& q0,const Vd3& q1,const Vd3& q2,const long div_c)
{
	Vd3A	vd3a ;
	for (long index=0 ; index<=div_c ; index++) {
		double	t  = 1./div_c*index ;
		double	b0 = (1.-t)*(1.-t) ;			//	(1-t)^2
		double	b1 = 2.*t  *(1.-t) ;			//	2 * (1-t) * t
		double	b2 = t*t ;         			//	t^2
		double	px = (b0*q0.x) + (b1*q1.x) + (b2*q2.x) ;
		double	py = (b0*q0.y) + (b1*q1.y) + (b2*q2.y) ;
		double	pz = (b0*q0.z) + (b1*q1.z) + (b2*q2.z) ;
		vd3a.push_back(Vd3(px,py,pz)) ;
		}
	return	vd3a ;
	}

2023/03/14
最初,1 つの TT_PRIM_QSPLINE が次の様になっている場合の始点,終点と制御点の与え方がわからなかった.
(8,0) (5,0) (1,4) (1,8)    …   ‘O’ の左下,見やすい様に整数にしている.
::bezier を 2 回呼出す.それぞれの値は次の様に指定する.
(8,0) (5,0) (3,2)
(3,2) (1,4) (1,8)
(3,2) は (5,0) と (1,4) の中点.
TT_PRIM_QSPLINE  O
まだうまくない部分はあるが,何とか.
TT_PRIM_QSPLINE  月

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

GetGlyphOutline の再調査

今動作しているコードを見ると,20 年以上前に書き始めたもの.
UNICODE 対応などの変更はあるが,基本的な動作はほとんど変わっていない.
MFC や古い自前のコードに依存している部分があるので,書き直そうかと…


その当時,どこを参考にしたのかわからない.一番古い部分は 1998 になっている.
テスト用に作成したプロジェクトのスケルトンの作成も 1997/04 のものがある.
次の所を参考にしたものと思うが,内容がだいぶ変わっている.
Q243285: HOWTO: Draw TrueType Glyph Outlines


::GetGlyphOutline の呼び出し方はそれほど難しくないが,返された TTPOLYGONHEADER などが難解.
当時はあまり理解できず,単純にポリラインに変換(QSpline2Polyline)していた.
今回検索すると,TTPOLYGONHEADER と TTPOLYCURVE などが詳しく書かれている所があった.
GetGlyphOutlineからアウトラインデータをもらおう
文字アウトラインの取得
Q87115: HOWTO: GetGlyphOutline() Native Buffer Format


2023/03/13
ここ のコードの結果を,2D データとしてダンプ.

	{
		tstring	tmp_path ;
		{
			size_t	size = MAX_PATH ;
			tmp_path.resize(size,0) ;
			::GetTempPath(DWORD(size),&tmp_path[0]) ;
			tmp_path = tstring(tmp_path.c_str()) ;
			}
		tstring	out_ipl = tmp_path ;
		{
		//	UINT	chr = character ;
			if (chr < 0xff) {
				out_ipl += TCHAR(chr) ;
				}
			else {
				tstring	buf ;	buf.resize(255,0) ;
				::_itot(chr,&buf[0],16)  ;
				out_ipl += buf.c_str() ;
				}
			out_ipl += _T(".ipl") ;
			}
		std::tout << out_ipl << std::endl ;
		std::ofstream	ipl_file(out_ipl.c_str()) ;
		for (size_t r_index=0 ; r_index<result.size() ; r_index++) {
			std::vector <LINE> vd = result[r_index] ;
			for (size_t v_index=0 ; v_index<vd.size() ; v_index++) {
				LINE	d = vd[v_index] ;
				ipl_file << _T("L") << std::endl ;
				for (size_t p_index=0 ; p_index<d.points.size() ; p_index++) {
					Vec2	p = d.points[p_index] ;
					ipl_file << p.x << _T(",") << p.y << std::endl ;
					}
				ipl_file  << std::endl ;
				}
			}
		ipl_file.close() ;
		}

%TEMP%\A.ipl は次の様になる.


L
36.5313,22
26.3125,50.2344
16.125,22

L
44.4219,0
38.6875,16
13.9375,16
8.20313,0
1,0
22.0469,57
30.9844,57
52,0


GetGlyphOutline  A
ipl の形式 f_ipl.hxx
個人的に作成した次のツールで表示可能.
https://jml.mish.work/index.php/i-tools/i3dx.html

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

コンソール AP で DC の使用

ChatGPT で「Windows コンソールアプリで DC を使用する方法」と入力してみた.
ChatGPT  Windows コンソールアプリで DC を使用する方法
すると,使えそうなコードが表示された.

#include	<Windows.h>
#include	"i_define.hxx"
#include	"con_wnd.hxx"

int main() {
    // 1. コンソールウィンドウのハンドルを取得する
    HWND consoleWindow = ::GetConsoleWindow();
    // 2. コンソールウィンドウのDCを取得する
    HDC consoleDC = GetDC(consoleWindow);
    // 3. DCを使用して描画する
    TextOut(consoleDC, 10, 100, _T("Hello, World!"), _tcslen(_T("Hello, World!")));
    // 4. DCを解放する
    ReleaseDC(consoleWindow, consoleDC);
    return 0;
}

そのままではエラーになる部分があったので,少し修正している.
コンソール AP のウィンドウに TextOut (dc,...)
コンソール AP のウィンドウで GDI が使えるのは知らなかった.


BMP を表示するコード.

{
//	...
	tstring	dib_name = file_name ;
	if (::File_IsNothing(dib_name))	{	return	false ;		}
	i_DIB	dib = ::DIB_Load(dib_name.c_str()) ;
	{
		HWND	hWnd = ::GetConsoleWindow() ;
		{
			RECT	rect =	{	0	} ;
			::GetWindowRect(hWnd,&rect) ;
			HDC	hDC  = ::GetDC(hWnd) ;
			::DrawDIB(hDC,rect,dib) ;
			::ReleaseDC(hWnd,hDC) ;
			}
		}
//	...
	}

コンソール AP で BMP の表示
::AlphaBlend
更に自前のコードを利用して,サムネイルの表示.

	{
		HWND	hWnd = ::GetConsoleHwnd  () ;
		D_I_E	die ;
		die.SetDocPath(dib_name.c_str()) ;
		die.Draw(hWnd) ;
		}
Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

error C2678: 二項演算子 ‘=’ :

ある処理を関数にしてコンパイルすると,

--------------------構成: VFDiv_1 - Win32 Debug--------------------
コンパイル中...
VFDiv_1V.cpp
c:\program files (x86)\microsoft visual studio\vc98\include\algorithm(232) : error C2678: 二項演算子 '=' : 型 'const struct Vector2<double>' の左オペランドを扱う演算子は定義されていません。(または変換できません)(新しい動作; ヘルプを参照)
        c:\program files (x86)\microsoft visual studio\vc98\include\algorithm(228) : コンパイルされたクラスのテンプレートのインスタンス化 'void __cdecl std::_Iter_swap(const struct Vector2<double> *,const struct Vector2<double> *,struct Vector2<double> *)' の参照を確認してください
c:\program files (x86)\microsoft visual studio\vc98\include\algorithm(232) : error C2678: 二項演算子 '=' : 型 'const struct Vector2<double>' の左オペランドを扱う演算子は定義されていません。(または変換できません)(新しい動作; ヘルプを参照)
        c:\program files (x86)\microsoft visual studio\vc98\include\algorithm(228) : コンパイルされたクラスのテンプレートのインスタンス化 'void __cdecl std::_Iter_swap(const struct Vector2<double> *,const struct Vector2<double> *,struct Vector2<double> *)' の参照を確認してください
cl.exe の実行エラー

VFDiv_1.exe - エラー 2、警告 0

対象が ‘const struct Vector2<double>’ となっているので,わかり辛かった.
次の関数の,’const Vd2A& v2a’ を std::reverse(v2a.begin(),v2a.end()) として使用しているのが原因.

PLF_face_l	PLF_triangulation	(const Vd2A& v2a)
{
//	...
	std::reverse(v2a.begin(),v2a.end()) ;
//	...
	}

一度関数内の変数に置く必要がある.
error C2678

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

Win7 Windows Update で 80072EFE

先日仮想マシンにセットアップした Win7 環境の Windows Update でエラー 80072EFE .
.NET Framework を使用しているものを実行すると,.NET … を要求され,そのセットアップに失敗してしまう.
Win7 Windows Update 80072EFE」で検索すると…
Windows7 をインストール後、Windows Update が 80072EFE エラーでできない場合の対処方法
Windows Updateのエラー 8007000Eの対処はKB3138612で解決(Windows7)
2021年版:Windows 7 を久しぶりに更新する時の注意
KB3138612 を手動でインストールする必要があるみたい.
https://www.catalog.update.microsoft.com/Search.aspx?q=KB3138612
環境は x64 なので「Windows 7 for x64-Based Systems … (KB3138612)」をダウンロードしてインストール.
仮想マシンの再起動後 Windows Update に入ると,167 個の更新があった.
Win7  KB3138612 インストール後の更新プログラム

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

VirtualBox 7.0 に更新

Win10 と Win11 の ViurtalBox を 6.1.40 から 7.0.4 に更新した.
4K 環境になってから,いろいろと表示でうまくない部分があった.


Win10 環境は,Win11 の仮想マシンを除いては問題なさそう.
Win10  VirtualBox 7.0.4
一度 Win11 仮想マシンを「除去」して,作成し直してみたが,うまく動作しない.
起動中の「お待ちください」の表示で止まってしまう.
仮想マシンの「設定」-「ディスプレイ」の「3Dアクセラレーションを有効化」にチェックして止まらなくなった.
「設定」-「ディスプレイ」-「スクリーン」-「3Dアクセラレーションを有効化」
どこかに設定があるものと思うが,OpenGL での表示がうまくされない.
VirtualBox 7  OpenGL 表示ができない?


Win11 環境は,LAN 関係のエラーでうまく起動しない.
6.1.40 に戻したがうまく起動しなくなってしまった.
Win11 VirtualBox 7  VERR_SUPDRV_COMPONENT_NOT_FOUND
「ネットワークアダプターを有効化」のチェックを外せば起動するが,これだとあまり使い物にならない.
ASUSTOR NAS でも同様のエラー になったことがあるので,設定ではないのか?


もう一度 7.0.4 にしてみたが,変わらず.
VM Name: Win10-VS6
Failed to open/create the internal network ‘HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter’ (VERR_SUPDRV_COMPONENT_NOT_FOUND).
Failed to attach the network LUN (VERR_SUPDRV_COMPONENT_NOT_FOUND).
Result Code:
E_FAIL (0X80004005)
Component:
ConsoleWrap
Interface:
IConsole {6ac83d89-6ee7-4e33-8ae6-b257b2e81be8}
Failed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter' (VERR_SUPDRV_COMPONENT_NOT_FOUND).


アンインストールやデバイスの削除を行って,再度インストールしたら少し動作する様になった.
デバイスマネージャーで VirtualBox Host-Only Ethernet Adapter がうまくなかったので,そこが原因だったか?
まだうまく動作しない仮想マシンもあるが,あとは個別の設定なので何とかなるかな?


2023/06/05
Win11 環境で 7.0.8 にあげて,LAN 関係で同じ様な現象.
PC を再起動して,うまく動作する様になった.

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

VirusTotal Cylance Unsafe

1 年位前から,exe をビルドしてデバッグが終わると VirusTotal でチェックしている.
それで,誤検知されやすいと思われる VC のバージョンなどのメモ.


VC6.exe では,ほとんどが何らかのものに引っ掛かってしまう.
SecureAge Malicious
VC8.exe や VC9.exe も何かに引っ掛かってしまうことが多い.
VC 10 ~ VC 12 では,あまり規則性はわからない.コードによる?


VC 14 以降は,普通の MFC のコードであればほぼ問題なさそう.
但し最初のうちは,ほとんど Cylance Unsafe となってしまう.
VirusTotal Cylance Unsafe
が,数日経過すると警告は消えることが多い.

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

error C2668: ‘abs’

1>------ ビルド開始: プロジェクト: ClCpy, 構成: Debug Win32 ------
1>コンパイルしています...
1>ClCpyDlg.cpp
1>l:\document\develop\tools\_free\tiny\clcpy\clcpydlg.cpp(396) : error C2668: 'abs' : オーバーロード関数の呼び出しを解決することができません。(新機能 ; ヘルプを参照)
1>        c:\program files (x86)\microsoft visual studio 8\vc\include\math.h(539): 'long double abs(long double)' の可能性があります。
1>        c:\program files (x86)\microsoft visual studio 8\vc\include\math.h(491): または 'float abs(float)'
1>        c:\program files (x86)\microsoft visual studio 8\vc\include\math.h(487): または 'double abs(double)'
1>        c:\program files (x86)\microsoft visual studio 8\vc\include\math.h(485): または 'long abs(long)'
1>        c:\program files (x86)\microsoft visual studio 8\vc\include\stdlib.h(415): または 'int abs(int)'
1>        引数リスト '(size_t)' を一致させようとしているとき
1>ビルド時間 0:07
1>ClCpy - エラー 1、警告 0
========== ビルド: 0 正常終了、1 失敗、0 更新、0 スキップ ==========

error C2668: 'abs' : オーバーロード関数の呼び出しを解決することができません。
次の様に long にキャストすることで対応.
size_t len_ = ::abs(long(lenS-lenD)) ;

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

Win11 MFC80u.dll などの場所

VC 2005 で作成した exe がうまく起動しないと連絡が入った.
すぐに dll などがないためとわかり,VC 2005 SP1 vcredist_x86.exe を入れて対応してもらった.
https://jml.mish.work/index.php/cpp/ref-vcredist-xxx-exe.html


それで,Win11 環境の c:\Windows\WinSxS\ の MFC80*.dll を見ると,それらしいものが見当たらない.
Win10 では …\WinSxS\ に存在する.
Win10 WinSxS x86 vc80 mfc
explorer で検索すると Win11 では ..\WinSxS\Fusion\ 以下になっている.
Win11 WinSxS\Fusion\ x86 vc80 mfc


WinSxS 以下のサイズ.
Win10 WinSxS
Win11 WinSxS


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