ホーム » Windows (ページ 3)
「Windows」カテゴリーアーカイブ
::EnumFont…
幾つかの所で使用している ::EnumFont … と フォント 選択 .
最近追加したフォントでうまく列挙されないものがある.
先日試したコード では列挙されているので,コールバック関数の部分がうまくない.
フォントを列挙する部分は 20 年以上前に書いたコード.
間違ってはなさそうだが,MFC に依存しているので見直すことに.
プログラミング Windows 第5版 を見たが,1 ページ程度.
::EnumFonts , ::EnumFontFamilies , ::EnumFontFamiliesEx の違いなどが簡単に書かれている.
当時参考にしたのは,MFC による Windows 95 プログラミング だったみたい.ソースにコメントが残っていた.
コールバック関数の EnumFontFamExProc が呼ばれるのは,::EnumFontFamiliesEx が呼ばれた直後.
AfxGetInstanceHandle
コンソール AP を変更していて「MFC を使用」にすると AfxGetInstanceHandle で ASSERT .
---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!
Program: c:\Temp\TOutline\tolmba\Debug.060\tolmba.exe
File: afxwin1.inl
Line: 19
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)
---------------------------
この単体テスト用プロジェクトは,最初 MFC を使用しないでコードを書いていた.
が,幾つかの機能を付けていくと MFC を使用した既存のコードが必要になった.
その中で AfxGetInstanceHandle() を呼出している所があり,そこで ASSERT .
次の様に MFC の初期化 ::AfxWinInit を追加して対応.
int _tmain (int argc,TCHAR* argv[])
{
#ifdef _MFC_VER
if (!::AfxWinInit(::GetModuleHandle(NULL),NULL,::GetCommandLine(),0)) {
return 1 ;
}
#endif
_tsetlocale(LC_ALL,_T("")) ;
// ...
return 0 ;
}
::EnumFontFamilies…
フォントを列挙する方法を「ChatGPT」と「Bingチャット」で問合わせてみた.
ChatGPT
#include <windows.h>
#include <iostream>
int main() {
HDC hdc = GetDC(NULL);
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
lf.lfCharSet = DEFAULT_CHARSET;
std::cout << "Available Fonts:" << std::endl;
EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)EnumFontFamiliesCallback, 0, 0);
ReleaseDC(NULL, hdc);
return 0;
}
int CALLBACK EnumFontFamiliesCallback(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, DWORD FontType, LPARAM lParam) {
std::cout << lpelfe->elfFullName << std::endl;
return 1;
}
Bingチャット
#include <windows.h>
#include <iostream>
#include <string>
int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW* lpntme, DWORD FontType, LPARAM lParam)
{
std::wcout << lpelfe->elfFullName << std::endl;
return 1;
}
int main()
{
HDC hdc = GetDC(NULL);
LOGFONTW lf = { 0 };
lf.lfCharSet = DEFAULT_CHARSET;
EnumFontFamiliesExW(hdc, &lf, (FONTENUMPROCW)EnumFontFamExProc, 0, 0);
ReleaseDC(NULL, hdc);
return 0;
}
WebGL での 3D データ表示
さらに,以前作成した Web サーバ を利用して WebGL での表示に.
bool test (void)
{
Vd2A pts ;
{
pts.push_back(Vd2( 0, 0)) ;
pts.push_back(Vd2( 70, 0)) ;
pts.push_back(Vd2( 90, 50)) ;
pts.push_back(Vd2(100,100)) ;
pts.push_back(Vd2( 50,100)) ;
pts.push_back(Vd2( 30, 70)) ;
pts.push_back(Vd2( 40, 30)) ;
pts.push_back(Vd2( 0, 0)) ;
}
vv_PLF vvplf ;
{
Vd3A v3a = ::ToVd3A(pts) ;
Vd4A v4a = ::ToVd4A(v3a) ;
PLF plf_l(PLF::line,v4a) ;
PLF plf_f(PLF::face,v4a) ;
v_PLF v_plf ;
v_plf.push_back(plf_l) ;
v_plf.push_back(plf_f) ;
vvplf.push_back(v_plf) ;
}
{
tstring tmp_path = ::Get_i_Tools_tmp_date() ;
tstring out_name = ::Path_AddLastSP(tmp_path) + ::Now_Format(_T("%H%M%S")) + _T("__.htm") ;
tstring outtname = ::Path_AddLastSP(tmp_path) + ::Now_Format(_T("%H%M%S")) + _T("_t.htm") ;
tstring outnname = ::Path_AddLastSP(tmp_path) + ::Now_Format(_T("%H%M%S")) + _T("_n.htm") ;
{
GonsA gnsa = ::PLF_ToGonsA(vvplf) ;
::GonsA_ToWGL(gnsa,out_name.c_str()) ;
gnsa = ::GonsA_Triangulation(gnsa) ;
::GonsA_ToWGL(gnsa,outtname.c_str()) ;
gnsa = ::GonsA_CalcNormal (gnsa) ;
::GonsA_ToWGL(gnsa,outnname.c_str()) ;
}
{
::start_web_server(tmp_path) ;
}
}
tstring g3_d_exe = ::get_g3_d_exe() ;
if (!g3_d_exe.empty()) {
tstring tmp_path = ::Get_i_Tools_tmp_date() ;
tstring ipl_name = ::Path_AddLastSP(tmp_path) + ::Now_Format(_T("%H%M%S")) + _T(".ipl") ;
::To_ipl (vvplf,ipl_name.c_str()) ;
::start_g3_d(ipl_name.c_str()) ;
}
return true ;
}
Linux での GLUT 3D データ表示
昨日のコードをもう少し汎用的に修正.そしてそれを他から呼出せるように変更.
次の様なコードで 3D データを生成して,GLUT で表示できる様にした.
bool test (void)
{
Vd2A pts ;
{
pts.push_back(Vd2( 0, 0)) ;
pts.push_back(Vd2( 70, 0)) ;
pts.push_back(Vd2( 90, 50)) ;
pts.push_back(Vd2(100,100)) ;
pts.push_back(Vd2( 50,100)) ;
pts.push_back(Vd2( 30, 70)) ;
pts.push_back(Vd2( 40, 30)) ;
pts.push_back(Vd2( 0, 0)) ;
}
vv_PLF vvplf ;
{
Vd3A v3a = ::ToVd3A(pts) ;
Vd4A v4a = ::ToVd4A(v3a) ;
PLF plf_l__ (PLF::line,v4a) ;
PLF plf_f__ (PLF::face,v4a) ;
v_PLF v_plf ;
v_plf.push_back(plf_l__) ;
v_plf.push_back(plf_f__) ;
vvplf.push_back(v_plf) ;
}
tstring txt_name = ::g3_d_get_txt_name() ;
{
tstring tmp_path = ::Get_i_Tools_tmp_date() ;
tstring ipl_name = ::Path_AddLastSP(tmp_path) + ::Now_Format(_T("%H%M%S")) + _T(".ipl") ;
::To_ipl (vvplf,ipl_name.c_str()) ;
::SaveText(txt_name.c_str(),ipl_name) ;
}
{
::exec_g3_d(txt_name.c_str()) ;
}
return true ;
}
GLUT を使用した 3D データの表示
個人的なメモです.
4 年位前に作成したコードで,凹多角形がうまく処理できていないものがあったのでその変更.
#include "glut_cg.hxx"
#include "gonsa_to.hxx"
#define TIMING_DN 1000
// int _tmain (int argc, _TCHAR* argv[])
int main (int argc, char* argv[])
{
{
GonsA gnsa ;
{
tstring buf ; buf.resize(1000) ;
while (std::terr << _T("file ? =") , std::tin.getline(&buf[0],buf.size()))
{
tstring str = buf.c_str() ;
if (str == _T("q")) { break ; }
else if (str == _T("Q")) { break ; }
str = ::QuotM_Del_All(str) ;
if (str.empty()) { continue ; }
if (::File_IsNothing(str)) { continue ; }
tstring in_file = str ;
gnsa = ::To_GonsA(in_file.c_str()) ;
gnsa = ::GonsA_Triangulation(gnsa) ; // 2023/06/27
gnsa = ::GonsA_CalcNormal (gnsa) ; // 2023/06/27
if (gnsa.size() > 0) { break ; }
}
if (gnsa.size() == 0) { return 0 ; }
}
::set_GonsA(gnsa) ;
::set_Extent(::GonsA_GetExtent(gnsa)) ;
}
::glutInitWindowPosition(200,200) ;
::glutInitWindowSize (600,400) ;
::glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH) ;
::glutInit (&argc,argv) ;
::glutCreateWindow (argv[0]) ;
::glutReshapeFunc (cv_resize) ;
::glutDisplayFunc (cg_display) ;
::glutKeyboardFunc (cv_keyboard) ;
::glutMouseFunc (cv_mouse) ;
::glutMotionFunc (cv_motion) ;
::glutTimerFunc (TIMING_DN,cv_timer,TIMING_DN) ;
::cv_init () ;
{
::glEnable(GL_LIGHTING) ;
::glEnable(GL_LIGHT0) ;
}
::glutMainLoop () ;
return 0 ;
}
#include "messbar.cxx"
warning C4305:
先日次の様なコードを書いていた.塗りつぶして表示する時の色の補正.
ColorRGB colRGB = ::ColorRefToRGB(pgs1.GetColor()) ;
{
float rgbcol = colRGB.R + colRGB.G + colRGB.B ;
if (rgbcol < 0.20*3) {
if (colRGB.R < 0.20) { colRGB.R = 0.20f ; }
if (colRGB.G < 0.20) { colRGB.G = 0.20f ; }
if (colRGB.B < 0.20) { colRGB.B = 0.20f ; }
}
if (0.80*3 < rgbcol) {
if (0.80 < colRGB.R) { colRGB.R = 0.80f ; }
if (0.80 < colRGB.G) { colRGB.G = 0.80f ; }
if (0.80 < colRGB.B) { colRGB.B = 0.80f ; }
}
}
ColorRGB.R などは float で,RGB のそれぞれを 0.0 ~ 1.0 で表現したもの.
最初 if (colRGB.R < 0.25) { colRGB.R = 0.25 ; } の様にしていたが,0.2 に変更した.
すると C4305 の warning .0.2f の様にすれば良いのはわかっているが,他の値で調べてみた.
0.0 , 1.0 , 7.0 などは大丈夫だが,0.2 や 7.1 は C4305 になってしまう.
コンパイラやオプションの指定にもよると思うが,float で表現できない場合のみ warning となるのか?
SetForegroundWindow
他 AP から,HWND を指定して前面に移動する方法.
bool Window_Foreground (HWND hWnd)
{
if (hWnd == NULL) { return false ; }
if (!::IsWindow(hWnd)) { return false ; }
{
if (::IsIconic(hWnd)) {
WINDOWPLACEMENT wndpl = { 0 } ;
::GetWindowPlacement(hWnd,&wndpl) ;
wndpl.showCmd = SW_RESTORE ;
::SetWindowPlacement(hWnd,&wndpl) ;
}
SetForegroundWindow(hWnd) ;
}
return true ;
}
VC 2022 17.6.?
先日 VS 2022 の更新版 があったのでアップデート.
個人的なツールの 3D ビューア をビルドすると,
ALYac Gen:Variant.Tedy.373496
Arcabit Trojan.Tedy.D5B2F8
BitDefender Gen:Variant.Tedy.373496
Cylance Unsafe
DeepInstinct MALICIOUS
Emsisoft Gen:Variant.Tedy.373496 (B)
eScan Gen:Variant.Tedy.373496
GData Gen:Variant.Tedy.373496
MAX Malware (ai Score=81)
McAfee Artemis!AE3A9CE560AE
McAfee-GW-Edition Artemis
Trellix (FireEye) Gen:Variant.Tedy.373496
TrendMicro-HouseCall TROJ_GEN.R002H09EQ23
VIPRE Gen:Variant.Tedy.373496
VC 2019 などでビルドしたものは問題ない.また VC 2022 更新前のものも問題なかった.
今まで VS の更新版が出てすぐにそれでビルドすることは少なかった.
テストが不十分なこともあり,リリース用は主に VC 2017 を使用している.
更新版によっては,この様なことがあるのかもしれない.
落ち着くまでしばらく時間がかかるのか?
error during ReadSymbolTable
5 年位前に作成したプロジェクトをビルドしていると,
--------------------Configuration: phpup_mb - Win32 Debug--------------------
Compiling...
ComPrj01.cpp
phpup_mb.cpp
...
Linking...
c:\Temp\HTM\phpup\phpup_mb\Debug.060\ComPrj01.obj : error : Internal error during ReadSymbolTable
ExceptionCode = C0000005
ExceptionFlags = 00000000
ExceptionAddress = 004623F2
NumberParameters = 00000002
ExceptionInformation[ 0] = 00000000
ExceptionInformation[ 1] = 0090B470
CONTEXT:
Eax = 3FFF1E64 Esp = 0019F050
Ebx = FFFF8000 Ebp = 01B834C7
Ecx = 3FFF1E64 Esi = 401F1EC0
Edx = 0094B478 Edi = 401F1EC0
Eip = 004623F2 EFlags = 00010246
SegCs = 00000023 SegDs = 0000002B
SegSs = 0000002B SegEs = 0000002B
SegFs = 00000053 SegGs = 0000002B
Dr0 = 0019F050 Dr3 = FFFF8000
Dr1 = 01B834C7 Dr6 = 3FFF1E64
Dr2 = 00000000 Dr7 = 00000000
Error executing link.exe.
Tool execution canceled by user.
exe は存在するが正しくできていないので,exe のみ削除して再度ビルド.
--------------------Configuration: phpup_mb - Win32 Debug--------------------
Linking...
LINK : LNK6004: c:\Temp\HTM\phpup\phpup_mb\Debug.060/phpup_mb.exe not found or not built by the last incremental link; performing full link
ComPrj01.obj : fatal error LNK1143: invalid or corrupt file: no symbol for comdat section 0xffff8000
Error executing link.exe.
phpup_mb.exe - 1 error(s), 0 warning(s)
obj のサイズを見ると,20 MB 位になっている.
それで思い出したのが,前にも同じ様な現象が…
LNK1143 : ファイルが無効であるか…
ソースを分割して対応.
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) ;
}
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) ;
}
間違っているかもしれないが,CB_SETITEMHEIGHT を簡単にテストしたことのまとめ.
通常のコンボボックスの場合 | -1 で,全ての項目の高さを設定できる |
オーナードロー 固定 | -1 で,エディットボックス部分の高さを指定 0 で,ドロップ部分の項目の高さを指定 |
オーナードロー 可変 | -1 で,エディットボックス部分の高さを指定 0 以上で,ドロップ部分のそれぞれの高さを指定 |
VirtualBox PXE-E06
Win11 上の仮想マシン Win10 の Windows Update での再起動で,
PXE-E06: Option ROM requires DDIM support.
検索してみた が,あまりいい情報に引っ掛からない.
Windows Update での再起動だったので心配だったが,仮想マシンを一度 OFF して,再起動.
特に何もなかったかの様に起動した.
何だったのだろう.
2024/04/05
その後頻繁にこの現象が発生する.VirtualBox と Windows との相性か?
高 DPI VC 「高い DPI 認識」
引き続きいろいろとやっているが…
異なる DPI での対応は簡単ではなさそう.
VC のプロパティで「モニターごと高い DPI 認識」としてビルドしていたが,モニタ間を移動するとうまくない.
ちゃんと対応すれば良いのだろうが,簡単ではない.
そのため exe のプロパティで「システム(拡張)」で良いと思っていたが,幾つかのバグ?(未対応)がある.
VC のプロパティで「高い DPI 認識」にしてビルドしたものの方がうまく機能している様な気がする.
左から 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 認識」でビルドしたものであれば良さそう.
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 ;
}
}
RegOpenKeyEx REGSAM
レジストリアクセスのコードを書き直していて,::RegOpenKeyEx の samDesired を調べてみた.
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
読み込み時,KEY_READ の方が速いなどはあるのか?それともファイルアクセスなどと同じ?
GetMonitorInfo
2002/08 に,マルチディスプレイ対応のコードを書いている.
今回,高 DPI 対応やディスプレイ位置が変わった時などのためもう一度…
ChatGPT で.
そのままでは VC 6 ではうまくビルドできなかったので,VC 8 で.
printf を使用しているので #include <cstdio> が必要.
そのまま実行すると 1920×1080 となる.
高 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
https://learn.microsoft.com/ja-jp/windows/win32/gdi/the-virtual-screen
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()) ;
}
}
高 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 .
まだ幾つか問題はあるが,今回の対応部分としてはこれで良さそう.
更にツールバー上のコンボボックスのスケーリングは次の様にした.
{
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.")) ;
}
高 DPI テスト exe
先日の 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 スケール設定」が引き継がれる.
これらの設定は,次の所に持っている?
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
A ~ HIGHDPIAWARE
S ~ DPIUNAWARE
E ~ GDIDPISCALING DPIUNAWARE
それぞれを実行すると表示が異なることはわかるが…
左から,「システム」,「システム(拡張)」,「アプリケーション」.
「システム」と「システム(拡張)」を区別する方法がわからない.
また「システム(拡張)」.exe で,何かの情報の取得が違っていて 表示が正しくない ものと思う.
::GetDeviceCaps の情報の表示は dc.DrawText(str,rect,DT_LEFT) としている.
この時,表示するフォントを指定していないため,「アプリケーション」では小さくなってしまう.
CFont::CreatePointFont などを呼ぶことで対応可能.