ホーム » MFC

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

2024年12月
1234567
891011121314
15161718192021
22232425262728
293031  

カテゴリー

アーカイブ

ブログ統計情報

  • 100,324 アクセス


コンパイル時の #define 値の表示

次の様なコードをコンパイル時に表示したくなった.

#ifdef	  _MSC_VER
str = _T("_MSC_VER ") + ::utot(_MSC_VER,10) ;
#endif
std::tout << str ;

以前一度使用しているが,それをもう少しいろいろと...


次の様に _CRT_STRINGIZE とすれば _MSC_VER 1941 と表示される.

#ifdef		  _MSC_VER
#pragma	message	("_MSC_VER " _CRT_STRINGIZE(_MSC_VER) )
#endif

VC 14 以降は vcruntime.h で次の様になっている.

#define _CRT_STRINGIZE_(x) #x
#define _CRT_STRINGIZE(x) _CRT_STRINGIZE_(x)

文字列化演算子 (#)


まだ途中だが,CPP ソースのどこでインクルードしてもそれなりに動作する様にする予定.
コンパイル時の #define 値の表示

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

VC6 プロジェクトのコードの移行

以前,VC 6 プロジェクトを移行する時の,設定などについて書いた.
VC6 から 2005 , 2008
VC6 から 2010 – 2019
VC6 から 2022
Win11 24H2  VC 6
今回は C++ コードの変更などのまとめ.


アプリケーションクラス InitInstance の次の呼出しを削除
 #ifdef _AFXDLL
  Enable3dControls();
 #else
  Enable3dControlsStatic();
 #endif


文字や文字列を _T() で括る
‘A’ –> _T(‘A’)
"abc" –> _T("abc")


_MBCS では問題ないコードが _UNICODE で,CString 変数のポインタが値として解釈されることがある.
その場合は LPCTSTR() で括れば良い.
str –> LPCTSTR(str)
C スタイルの文字列に関連する CString の操作方法
CString⇒LPTSTR変換


文字列操作関数の _UNICODE 対応と _s 対応.
_t で始まる関数に置き換え.また gcc などでも通る様に _tdefine.hxx を用意.
_MSC_VER により,_s 版と以前のものを切替える関数群を用意


int を INT_PTR などに(x64 対応).
CArray::GetSize など,MFC の色々な所で int が INT_PTR に変更された.
int size = array.GetSize() ; –> INT_PTR size = array.GetSize() ;
ダイアログベースの時も同様に.


* まだ作成途中です.


Microsoft C/C++ 2003 – 2015 の変更履歴
Visual C++ 移植およびアップグレード ガイド

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

リリース版 exe のデバッグ

先日の Win11 24H2 でうまくなかった現象を更に調べたことのメモ.
結論としては,InitInstance に確保される dlg のメンバ変数で初期化がされていないものがあったため.


最初リモートデバッグも考えたが,VC 8 では少し面倒なので VS 2005 をインストールした.
https://learn.microsoft.com/ja-jp/visualstudio/debugger/remote-debugging-cpp?view=vs-2022
インストールした VC 8 でビルドしたデバッグ情報付きのリリース exe でも不具合の現象は確認できた.
が,デバッグしようとすると欲しい情報の所でうまく表示されない部分があった.
そのため VS 2008 もインストールすることに.
VC 9 ではうまくデバッグできる様になった.


デバッガで追いかけると,ダイアログのメンバ変数が意図しない値になっていて,初期化されていないことがわかった.
修正自体は簡単だが,なぜ今まで…


初期化されていないことによりゴミ(不定値)が入ることはわかる.
その変数は ‘1’ 以外だとうまく通る様になっていて,それが 24H2 でたまたま ‘1’ に?


Initinstance で確保される dlg はスタックに確保される.
デバッグ版 exe では,0 でないバイト値などで埋められることが多いが,リリース exe では 0 または不定値となる.
0 はまだ使われていない状態で,不定値は確保前に呼び出された関数で使用する変数やリターンアドレスなど.


一度実行して,次の所で設定されるポインタを求め,それをメモリダンプのアドレスに入力.
m_pMainWnd = &dlg;
再度実行して InitInstance で止めた時のメモリの状態.
dlg メモリ状態
今回の初期化されていない変数(赤くなっている次)が,’1′ になっていることを確認できた.

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

MFC ダイアログに描画

MFC ダイアログ exe で GDI などでの描画を行うときは,通常「Picture Control」を使用する.
メンバ変数として CStatic を割り当てて,その変数(ウィンドウ)に対して描画する.
CWnd::GetDlgItem::GetDlgItem でも良い.


単体テスト用など,それほど重要でないプロジェクトでダイアログに直接描画したい時がある.
ZipMF.exe
リサイズ可能なダイアログの場合,Picture Control のリサイズなども意外と面倒なため


VC 2022 で,MFC の「ダイアログ ベース」として作成.
CDlgDrwDlg
ダイアログの基本クラスは「CDialog」とした.


CDlgDrwDlg::OnPaint() の else 部分を次の様に変更.

	{
	//	CDialog::OnPaint();
		{
			CPaintDC dc(this);
			CRect	rect;
			GetClientRect(&rect);
			rect.DeflateRect(10, 10);
			dc.Rectangle(rect);
		}
	}

CDlgDrwDlg::OnPaint
ダイアログの「プロパティ」-「透明化」は「True」の方が良さそう.
DlgDrw.exe
https://itl.mish.work/i_Tools/Doc/blog/vc/DlgDrw.zip

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

DDX_CBIndex , DDX_CBString

デバッグ用のツールを作成していて,コンボボックスを使いたくなった.
使いたかったのは「ドロップダウン リスト」で,ドロップダウン部分を常に表示した「標準」の状態.
本当はリストボックスを使えば良かったか?


VC6 の「MFC ClassWizard」で変数を追加しようとすると変数のタイプが「CString」.欲しいのは「int」.
コンボボックスのタイプを「ドロップダウン リスト」に変更すると「int」が表示され,DDX_CBIndex が追加できた.

void CSwMLGDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CSwMLGDlg)
	DDX_CBIndex(pDX, IDC_LANG_UI, m_LangUI);
	DDX_CBIndex(pDX, IDC_LANG_PR, m_LangPR);
	//}}AFX_DATA_MAP
}

変数追加後,コンボボックスのタイプを「標準」に変更.


ビルドして動作を確認すると,特に問題なさそう.
「標準」コンボボックスで DDX_CBIndex


デバッガで追いかけてコードを見ても特に怪しい所はなさそう?
VC2015  DDX_CBIndex


動作を試してはないが,VC 2015 などの変数の追加では,手動で型を指定できそう?
VC 2022 コントロール変数の追加

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

VC6 から VC2022 への移行

VC 6 から 2022 へのアップグレードがなくなったので,手動での移行方法を試してみた.
VC6 から 2005 , 2008
VC6 から 2010 – 2019


「新しいプロジェクトの作成」で「空のプロジェクト」を選択して「次へ」
「新しいプロジェクトの作成」で「空のプロジェクト」を選択して「次へ」
適当なプロジェクト名を付けて「作成」.
プロジェクト名を入力して「作成」
必要に応じて,VC 6 プロジェクトのファイルをコピー.
VC 6 プロジェクトのファイルをコピー


「ソリューション エクスプローラー」のプロジェクトを「右クリック」-「追加」-「既存の項目」.
cpp,h,rc を追加
cpp,h,rc を選択して「追加」.


必要に応じて「出力ディレクトリ」などの指定.
「出力ディレクトリ」などの指定
「共有 DLL で MFC を使う」に.
「共有 DLL で MFC を使う」を選択
「_CONSOLE」を「_WINDOWS」に.
「_CONSOLE」を「_WINDOWS」に
「Windows(/SUBSYSTEM:WINDOWS)」に.
「Windows(/SUBSYSTEM:WINDOWS)」を選択


ヘッダーファイルを追加していないと「クラス ウィザード」がうまく機能しない.


以下は,正しく設定されていない場合のエラー.

C:\...\afx.h(24,1): error C1189: #error:  Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]

「スタティック ライブラリで MFC を使用する」または「共有 DLL で MFC を使う」に.


libcmtd.lib(exe_main.obj) : error LNK2019: 未解決の外部シンボル _main が関数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) で参照されました

「Windows (/SUBSYSTEM:WINDOWS)」に.


クラス ウィザードで CAboutDlg のみ.
クラス ウィザード  CAboutDlg
ソリューションに *.h を追加する.


* 他の動作はまだ確認中です.

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

「バージョン情報」ダイアログ

バージョンリソースを読み込み「バージョン情報」ダイアログの表示で使用するコード.
バージョンリソースを読み込み「バージョン情報」ダイアログに設定
IDD_ABOUTBOX の IDC_STATIC を IDC_FV_DESCRIPTION_VERSION と IDC_FV_LEGAL_COPYRIGHT に変更.
???Dlg.cpp で次をインクルード.
  #include  "FVerDlg.hxx"
  #include  "i_trace.hxx"
次の様に OnInitDialog に ::SetAboutFileVer を追加.
  BOOL CAboutDlg::OnInitDialog()
  {
     CDialog::OnInitDialog();
     ::SetAboutFileVer(this->GetSafeHwnd()) ;
     return TRUE;
     }

https://itl.mish.work/i_Tools/Doc/blog/vc/AboutB.zip

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

::ShellExecute

「インデックスのオプション」を開くために ::ShellExecute などから開けないかと…
検索するとコマンドプロンプトなどで「control.exe /name Microsoft.IndexingOptions」とすれば良いことがわかった.


この動作の cpp のコード.

CString	Error_FormatMessage(const DWORD error)
{
	CString	message ;
	LPVOID	lpMessageBuffer = NULL ;
	if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
			NULL,error,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
			(LPTSTR)&lpMessageBuffer,0,NULL)) {
		message = LPTSTR(lpMessageBuffer) ;
		::LocalFree(lpMessageBuffer) ;
		}
	return	message ;
	}
void CShellEDlg::OnExecute() 
{
	UpdateData(TRUE) ;
	HINSTANCE hInst = ::ShellExecute(this->GetSafeHwnd(),m_StrOper,m_StrFile,m_StrPara,NULL,SW_SHOW) ;
	if (UINT64(hInst) > 32)	{	return ;	}
	DWORD	error = ::GetLastError() ;
	CString	str ;
	{
		str.Format(_T("%d\r\n%d"),DWORD(hInst),error) ;
		str += _T("    ") + ::Error_FormatMessage(error) ;
		str += _T("\r\n") + m_StrOper ;
		str += _T("\r\n") + m_StrFile ;
		str += _T("\r\n") + m_StrPara ;
		}
	AfxMessageBox(str) ;
	}

CShellEDlg::OnExecute()
ShellE  メンバ変数
ShellE.exe
https://itl.mish.work/i_Tools/Doc/blog/vc/ShellE.zip

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

CXxxxDlg::OnCreate が 2 回

「ある操作を行ったとき exe が 2 つ起動する」と報告があった.
言い訳になるが,通常この動作は年に 2 回程度しか通らないもの.また,他の操作により通らないこともある.
その条件になる様に環境を設定して試すと,確かに…


その部分のコードは,何年も変更はしていない.
いろいろと動作を確認していると,VC 10 以前では問題ないが,11 以降で 2 つ起動することがわかった.


その動作の部分のみを抜き出して動作を試した.

int CT_DlG_1Dlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;
	// TODO:  ここに特定な作成コードを追加してください。
	{
		HWND	HWnd = NULL ;
		{
			CWnd*	mainWnd = AfxGetMainWnd() ;
			if (mainWnd != NULL) {
				HWnd = mainWnd->GetSafeHwnd() ;
				}
			}
		HINSTANCE  hInst = ::ShellExecute(HWnd,NULL,_T("NotePad.exe"),NULL,NULL,SW_SHOWNORMAL) ;
		return	-1 ;
		}
	return 0;
	}

CXxxxDlg::OnCreate が 2 回呼ばれる?
MFC の動作が変わったのか,CXxxxDlg::OnCreate が 2 回呼ばれるようになったみたい.
https://itl.mish.work/i_Tools/Doc/blog/vc/TDlg0614.zip


2 回目に呼ばれた時は,何もしないで return -1 とする様に変更予定.

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

高 DPI 環境の CToolBar

複数のツールバーに対応するために CBitmap を new で生成する様に.
そのために新たに作成しようかと思ったが,既存のままでも良さそうなのでそれを少し修正.
LateDelete


また,次の様に予めボタンの背景を変更してみたが,うまくいかなかった.

{
	CDWordArray	orgBits ;
	DWORD		orgBmpSize = bm.bmWidthBytes * bm.bmHeight ;
	orgBits.SetSize(orgBmpSize) ;
	DWORD		orgBitsSize = tb_img.GetBitmapBits(orgBmpSize,orgBits.GetData()) ;
	for (DWORD index=0 ; index<orgBitsSize ; index++) {
		if (orgBits[index] == 0xc0c0c0) {
			orgBits[index] = col3D ;
			}
		}
	tb_img.SetBitmapBits(orgBitsSize,orgBits.GetData()) ;
	}

何かの手順が違っているみたいで,環境により?うまくいっている様に見えることもある.


https://itl.mish.work/i_Tools/Doc/blog/migrate/Test0611.zip

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

CToolBar ボタン画像

先日の内容で残っているのが,ボタン画像の背景の色.
リソースエディタで 0xC0C0C0 を指定している所が,ボタンの色(::GetSysColor(COLOR_3DFACE))にならない.
Toolbar  IDR_MAINFRAME
何年も前に作成したコードを見ると,0xC0C0C0 を COLOR_3DFACE に置き換えている部分がある.
それでMFC のコード afxtoolbarimages.cpp を眺めていると CMFCToolBarImages::TransparentBlt があった.
その中で ::TransparentBlt を呼出している.
先日のコードの次の部分を ::TransparentBlt に変更してテストすると,
dstDC.StretchBlt(0,0,imageSize.cx,imageSize.cy,&srcDC,0,0,org_size.cx,org_size.cy,SRCCOPY) ;
::TransparentBlt(dstDC.GetSafeHdc(),0,0,imageSize.cx,imageSize.cy,
       srcDC.GetSafeHdc(),0,0,org_size.cx,org_size.cy,0xC0C0C0) ;
::TransparentBlt  (...,0xC0C0C0)
0xC0C0C0 の部分が描画されていない(透明になっている)ことが確認できたので,
dstDC.FillSolidRect(0,0,imageSize.cx,imageSize.cy,0xf0f0f0) ;
::TransparentBlt(dstDC.GetSafeHdc(),…,0xC0C0C0) ;
FillSolidRect
	::TransparentBlt
::SetStretchBltMode(…,HALFTONE) が効かない?
仮の DC を用意して ::TransparentBlt(そのまま) してそれを ::StretchBlt(リサイズ) の様にしてもダメだった.
TransparentBlt HALFTONE で検索したがあまり有用な情報は引っ掛からなかった.
リサイズして転送する(StretchBlt)前に CBitmap::GetBitmapBits で取り出し 0xC0C0C0 を書き換えるしかないか?


https://itl.mish.work/i_Tools/Doc/blog/migrate/Test0610.zip

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

CToolBar ボタンのリサイズ

リサイズ部分を組み込んでみたが
CToolBar SetBitmap
ボタン画像の位置がズレている,DDB に対する操作が何か違っている.


試しに,新しいボタン画像サイズを次の様に求めるとそれなりの高さになった.
newImgSize.cy = newBtnSize.cy – 7 ;
newImgSize.cy = newBtnSize.cy - 7 ;
newImgSize.cx = newBtnSize.cx – 7 ;
newImgSize.cy = newBtnSize.cy – 6 ;
これでサイズは良さそう.
newImgSize.cx =(newBtnSize.cx - 7) * btnCount ;

{
	CSize	imageSize    = newImgSize ;
		imageSize.cx*= btnCount ;
	static	CBitmap	newImg ;	//  CBitmap* newImg = new CBitmap ; 
	{
		CBitmap	tb_img ;
		tb_img.LoadBitmap(idr) ;
		{
			BITMAP	bm = {0} ;  tb_img.GetBitmap(&bm) ;
			CSize	org_size = CSize(bm.bmWidth,bm.bmHeight) ;
			CDC*	wndDC = toolBar->GetDC() ;
			newImg.CreateCompatibleBitmap(wndDC,imageSize.cx,imageSize.cy) ;
			CDC	srcDC ;     srcDC.CreateCompatibleDC(wndDC) ;
			CDC	dstDC ;     dstDC.CreateCompatibleDC(wndDC) ;
			CBitmap*oldSrcBmp = srcDC.SelectObject(&tb_img) ;
			CBitmap*oldDstBmp = dstDC.SelectObject(&newImg) ;
			::SetStretchBltMode(dstDC.GetSafeHdc(),HALFTONE) ;
			dstDC.StretchBlt(0,0,imageSize.cx,imageSize.cy,
				&srcDC,0,0,org_size.cx,org_size.cy,SRCCOPY) ;
			srcDC.SelectObject(oldSrcBmp) ;
			dstDC.SelectObject(oldDstBmp) ;
			}
		}
	toolBar->SetBitmap(newImg) ;
	}

static CBitmap newImg としているため,複数のツールバーには対応していません.
CBitmap* newImg = new CBitmap の様にして終了時開放する必要があります.


https://itl.mish.work/i_Tools/Doc/blog/migrate/Test0607.zip

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

CBitmap のコピー

次の所を参考に CBitmap のリサイズ …
How do you scale a CBitmap object?
CBitmap のリサイズでうまくない
1 回はリサイズできているが,コピー動作の部分が違っているみたいで正しく表示できない.
検索してみたがあまりわかりやすいコードに引っ掛からなかった.
Copilot で問合わせると

// 元のビットマップ
CBitmap originalBitmap;

// ... (originalBitmap を適切に初期化)

// コピーするビットマップ
CBitmap copiedBitmap;

// 元のビットマップの情報を取得
BITMAP bitmapInfo;
originalBitmap.GetBitmap(&bitmapInfo);

// コピーするビットマップを作成
copiedBitmap.CreateBitmap(bitmapInfo.bmWidth, bitmapInfo.bmHeight, bitmapInfo.bmPlanes, bitmapInfo.bmBitsPixel, NULL);

// 元のビットマップのビットを取得
BYTE* pBits = new BYTE[bitmapInfo.bmWidthBytes * bitmapInfo.bmHeight];
originalBitmap.GetBitmapBits(bitmapInfo.bmWidthBytes * bitmapInfo.bmHeight, pBits);

// コピーするビットマップにビットを設定
copiedBitmap.SetBitmapBits(bitmapInfo.bmWidthBytes * bitmapInfo.bmHeight, pBits);

// メモリを解放
delete [] pBits;

関数として書き直し.

CBitmap*	Copy_CBitmap	(CBitmap* src)
{
	CBitmap*	dst = new CBitmap ;
	BITMAP	bm ;
	src->GetBitmap(&bm) ;
	dst->CreateBitmap(bm.bmWidth,bm.bmHeight,bm.bmPlanes,bm.bmBitsPixel,NULL) ;
	BYTE*	pBits = new	BYTE[bm.bmWidthBytes*bm.bmHeight] ;
	src->GetBitmapBits(bm.bmWidthBytes*bm.bmHeight,pBits) ;
	dst->SetBitmapBits(bm.bmWidthBytes*bm.bmHeight,pBits) ;
	delete[]	pBits ;
	return	dst ;
	}

何とかコピーを表示できた.
CBitmap のコピー
https://itl.mish.work/i_Tools/Doc/blog/migrate/T_CB0606.zip

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

CBitmap の表示

ツールバーのビットマップをリサイズするために CBitmap を調べ始めた.
Inside VC++ Version 5 を参考に次の様に書いてみた.
プログラミング Visual C++ .NET では省かれている?

void CT_CBmpView::OnDraw(CDC* pDC)
{
//	CT_CBmpDoc* pDoc = GetDocument();
//	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	{
		CDC 	dc_mem ;	dc_mem.CreateCompatibleDC(pDC) ;
		CBitmap	bitmap ;	bitmap.LoadBitmap(IDR_MAINFRAME) ;
		BITMAP	bm = {0} ;	bitmap.GetBitmap(&bm) ;
		{
			CRect	rect(0,0,0,0) ;
			GetClientRect(&rect) ;
			rect.DeflateRect(100,100,200,200) ;
			::SetStretchBltMode(pDC->GetSafeHdc(),HALFTONE) ;
			dc_mem.SelectObject(&bitmap) ;
		//	pDC->BitBlt    (rect.left,rect.top,rect.right,rect.bottom,&dc_mem,0,0,SRCCOPY) ;
			pDC->StretchBlt(rect.left,rect.top,rect.right,rect.bottom,
				&dc_mem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY) ;
			}
		}
	}

そのまま貼り付けてテスト可能な様に View の OnDraw に書いています.
これを参考に実装する場合,リソースの読込み部分などは OnInitialUpdate などで行ってください.
CBitmap によるビットマップリソースの表示
https://itl.mish.work/i_Tools/Doc/blog/migrate/T_CB0604.zip


欲しかった CBitmap のリサイズのコードは次の所にあった.
How do you scale a CBitmap object?

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

高 DPI 環境での CToolBar

vC 6 MFC プロジェクトを VC 2010 以降に更新すると,高 DPI 環境でツールバーがうまくない.
VC 10 以降でビルドした exe で,ツールバーが大きくならない
CMFCToolBar であれば OK .


個人的には 2005/06 に作成したコードを改良したものを使用している.
どこを参考にしたのかはちょっとわからない.
MFCによるWindows95プログラミング」や「INSIDE VISUAL C++ 5TH ED」などと思う.
それを簡単に利用できる様にできないかと…


コードは次の様な感じ.

BOOL	ToolBar__Resize	(CToolBar* toolBar,UINT idr)
{
	double	dpi_s = 1. ;
	{
		dpi_s = ::GetDPI_scale(toolBar->GetSafeHwnd()) ;	//  ::GetDpiForWindow() / 96.
		}
	if (dpi_s == 1.) {
		return	TRUE ;
		}
	CToolBarCtrl&	tbCtrl = toolBar->GetToolBarCtrl() ;
	CSize	btnSize(0,0) ;
	CRect	bdrRect(0,0,0,0) ;
	{	//  ボタンなどのサイズを取得
		DWORD	dwSize = tbCtrl.GetButtonSize() ;
		{
			btnSize.cx = LOWORD(dwSize) ;
			btnSize.cy = HIWORD(dwSize) ;
			}
		bdrRect        = toolBar->GetBorders() ;
		}
	CSize	newBtnSize = btnSize ;
	CRect	newBdrRect = bdrRect ;
	{	//  サイズを調整
		newBtnSize.cx    = int(btnSize.cx    *dpi_s) ;
		newBtnSize.cy    = int(btnSize.cy    *dpi_s) ;
		newBdrRect.left  = int(bdrRect.left  *dpi_s) ;
		newBdrRect.top   = int(bdrRect.top   *dpi_s) ;
		newBdrRect.right = int(bdrRect.right *dpi_s) ;
		newBdrRect.bottom= int(bdrRect.bottom*dpi_s) ;
		}
	{	//  サイズを指定
		tbCtrl.SetButtonSize(newBtnSize) ;
		toolBar->SetBorders(newBdrRect) ;
		}
	return	TRUE ;
	}

CToolBarCtrl  SetButtonSize
ツールバーボタンのビットマップのリサイズはまだ書換えができていない.
https://itl.mish.work/i_Tools/Doc/blog/migrate/Test0603.zip

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

VC6 から VC2019 への移行

今回は VC 6 ds? の VC 2019 への更新.
VS 2022 では,VC 6 からのアップグレードがなくなった


VS 2019 で dsw を開き 2019 に更新.
設定は VC 8 の時の手順とほとんど変わらない(設定値が微妙に異なる部分あり).
出力ディレクトリなどを「c:\Temp\…\$(ProjectName)\$(Configuration).142\」に.
VC 2019 出力ファイル
「文字セット」を「Unicode 文字セットを使用する」に.
VC 2019 文字セット
「プリコンパイル済み…」を「$(IntDir)$(TargetName).pch」に.
VC 2019  プリコンパイル済みヘッダ
「C/C++」の「出力ファイル」を「$(IntDir)」に.
VC 2019 C/C++ 出力ファイル
「リンカ」の「出力ファイル」を「$(OutDir)$(ProjectName).exe」に.
VC 2019 リンカ 出力ファイル
「ブラウザ情報」の「出力ファイル」を「$(OutDir)$(ProjectName).bsc」に.
VC 2019 ブラウザ情報 出力ファイル


そのままビルドすると,デバッグ版では D8016 エラーになる.
「C/C++」-「すべてのオプション」の「関数レベルでリンクする」をブランクに.
「関数レベルでリンクする」をブランクに


https://itl.mish.work/i_Tools/Doc/blog/migrate/Test0526.zip


2024/07/30
VC 6 から VC 2022 への移行


2024/08/21
VC 2010 などでも同じように指定することで移行が可能なことを確認.

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

VC 6 プロジェクトの移行

今更の内容ではあるが,VC 6 プロジェクトを VC 8 などに移行する手順のまとめ.


私の場合,VC 6 からプロジェクトを作成して VC 2017 などでビルドした exe をリリースすることが多い.
他にも,コードの単体テストのためにコンソール AP を作成する時も VC 6 がお手軽.
Win11 でも MFC42*.dll などは入っているので,テストも exe をコピーすれば可能となる.
以前は VC 7 なども対象としていたが,関係するプロジェクトで必要がなくなり,今は使っていない.
また VC 7 形式を通すvcproj を直接編集しないといけない状態になることがある.
プロジェクトのバックアップをしやすい様に exe などの出力先は,別の所を指定している.


VC 6 で MDI プロジェクトとして作成.プロジェクト名はなるべく 5 文字以下にしている.
出力ディレクトリを変更.この時 VC のバージョンごとに出力先を分けている.
出力ディレクトリを変更

C:.
└─Test
    ├─Debug.060
    ├─Debug.080
    ├─Release.060
    └─Release.080

VC 8 で Test.dsw を開く.
文字セットを「Unicode 文字セットを使用する」に.
出力ディレクトリなどを「c:\Temp\…\$(ProjectName)\$(ConfigurationName).080」に.
VC 8 出力ディレクトリ
「プリコンパイル済み…」を「$(IntDir)/$(TargetName).pch」に.
プリコンパイル済みヘッダファイル
「C/C++」の「出力ファイル」を「$(IntDir)/」に.
C/C++  出力ファイル
「リンカ」の「出力ファイル」を「$(OutDir)/$(ProjectName).exe」に.
リンカ 出力ファイル
「プログラム データベース…」を「$(OutDir)/$(ProjectName).pdb」に.
プログラム データベース ファイルの生成
「ブラウザ情報」の「出力ファイル」を「$(OutDir)/$(ProjectName).bsc」に.
ブラウザ情報 出力ファイル
ツリーに「MIDL」が表示されている場合は「タイプライブラリ」を「$(IntDir)/$(ProjectName).tlb」に変更.
必要に応じて,それぞれの「コマンド ライン」で 060 のままの所がないか確認.


ビルドすると次のワーニングになる.

1>------ ビルド開始: プロジェクト: Test, 構成: Debug Win32 ------
1>コンパイルしています...
1>Test.cpp
1>o:\document\vc_test\migrate\test\test.cpp(61) : warning C4996: 'CWinApp::Enable3dControls': CWinApp::Enable3dControls is no longer needed. You should remove this call.
1>        c:\program files (x86)\microsoft visual studio 8\vc\atlmfc\include\afxwin.h(4477) : 'CWinApp::Enable3dControls' の宣言を確認してください。
1>リンクしています...
1>マニフェストを埋め込んでいます...
1>Test - エラー 0、警告 1
========== ビルド: 1 正常終了、0 失敗、0 更新、0 スキップ ==========

削除,または次の様に修正する.

#if(_MFC_VER >= 0x0700)
#else
#ifdef _AFXDLL
	Enable3dControls();		// 共有 DLL 内で MFC を使う場合はここをコールしてください。
#else
	Enable3dControlsStatic();	// MFC と静的にリンクする場合はここをコールしてください。
#endif
#endif

個人的によく変更する設定として
「C/C++」-「言語」-「OpenMP サポート」を「はい」に.
「リンカ」-「システム」-「大きい…アドレス」を「2GBを超える…サポートする」に.


Test.sln と Test.vcproj を Test_80.sln と Test_80.vcproj としてコピー.
Test_80.sln をエディタで開いて,Test_80.vcproj に.
sln ファイルを編集して ~_80.vcproj に


vC 9 以降に更新する場合は Test.sln を開く.
出力ディレクトリなどを「c:\Temp\…\$(ProjectName)\$(ConfigurationName).090」などに.
VC 9 出力ファイル
VC 8 の時と同様に
Test.sln と Test.vcproj を Test_90.sln と Test_90.vcproj としてコピー.
Test_90.sln をエディタで開いて,Test_90.vcproj に.


vcproj をエディタで開くと TypeLibraryName が c:\Temp\…\Test\Debug.060/Test.tlb として残っている.
そのままでも問題はなさそうだが,修正するとすれば $(IntDir)/$(ProjectName).tlb か.
https://itl.mish.work/i_Tools/Doc/blog/migrate/Test0520.zip


2024/07/26
VC 10 以降でビルドした MDI.exe で「引数が正しくありません。」となることがある.
対応方法は InitInstance に AfxOleInit() の呼出しを追加する.

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

「引数が正しくありません」

以前に書いた情報を整理.
Win10 21H1 でうまく動作しない exe
Win10 環境で,MDI exe にドキュメントをドロップすると「引数が正しくありません」となることがある.


原因は ::CoInitinalize が呼び出されていないため.
コードでの対応方法としては InitInstance の最初に以下を追加.

	// OLE ライブラリを初期化します。
	if (!AfxOleInit()) {
		AfxMessageBox(_T("OLE の初期化に失敗しました。")) ;
		return	FALSE ;
		}

また,一度「開く」ダイアログを表示すると,その後は問題ない.

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

AppName.ini

何年か前に作成したツールをビルドしていて,ちょっと気になったこと.
exe 名を変更した時,設定値がうまく引き継がれない.
レジストリを使用している時は AFX_IDS_APP_TITLE を追加すれば良いが ini では効果がない.
CWinApp::SetCurrentHandles()    m_pszProfileName


最近書いたコードからは,次の様に m_pszProfileName を変更する様にしている.

BOOL	RI_Set_ProfileName		(void)
{
	CWinApp*	app = AfxGetApp() ;
	if (app == NULL)    	{	return	FALSE ;		}
	CString		nowINI = app->m_pszProfileName ;
	CString		newINI = ::INI_get_module_ini().c_str() ;
	if (nowINI == newINI)	{	return	TRUE ;		}
	free((void*)app->m_pszProfileName) ;
	app->m_pszProfileName = _tcsdup(newINI) ;
	{
		std::tout << _T("org=") << LPCTSTR(nowINI) << std::endl ;
		std::tout << _T("new=") << LPCTSTR(newINI) << std::endl ;
		}
	return	TRUE ;
	}
Is this 投稿 useful? Useful Useless 0 of 0 people say this 投稿 is useful.

ダイアログベース コマンドライン

ファイルの関連付けを調べていて,3D データを表示するツールに関連付けるとうまく表示されない.
MFC ダイアログベースのスケルトンでは,コマンドラインの標準的な処理は入っていない.


それで OnInitDialog の最後の方で次の様にした.

{
	CStringArray	readFiles ;
	for (int a_index=1 ; a_index<__argc ; a_index++) {
		CString	av = __targv[a_index] ;
		readFiles.Add(av) ;
		}
	if (readFiles.GetSize() > 0) {
		ReadFiles(readFiles) ;
		}
	}

S_asZ  2024.01


更に,幾つかのツールでうまく開けないものがあった.
InitInstance での初期化手順がうまくなかった.
i3DV  App  InitInstance

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