ホーム » VC

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

2024年11月
 12
3456789
10111213141516
17181920212223
24252627282930

カテゴリー

アーカイブ

ブログ統計情報

  • 99,327 アクセス


argv envp

以前 Linux 環境で動作する .out で,コマンドラインを取得したくなり作成したコード.
Windows でもそのまま動作する様に作成したもので,予め main でグローバルな変数に argv を登録している.

#include	"cmd_line.hxx"

int	_tmain	(int argc,TCHAR* argv[],TCHAR* envp[])
{
	{
		::reg_argv(argc,argv,envp) ;
		}
	{
		::dmp_arg() ;
		}
	return	0 ;
	}

DS220  argv envp


Windows の場合は __argc と __argv が利用できるのであまり必要ない.
::GetCommandLine使用することも可能


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

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

コンパイル時の #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.

VS 2022 の更新で「問題が…」

VS の更新があったので更新すると…
「申し訳ございません。問題が発生しました」.
VS 2022 の更新で「問題が発生しました」
どうも VC ランタイムのパッケージがインストールされなかったみたい.
VC Redist MSVC
デバッグや通常の実行も問題はなさそう.


前回とは違い「修復」で対応しようと思ったが…
VS の修復
どこまでがリセットされるかわからないので「変更」で対応.

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.

コンソール AP でバージョン情報

::GetFileVersionInfo を使った FVersion.hxx が,他のコードに依存していたので整理.
次の様なコードで,コンソール AP のバージョン情報を表示できる.

#include	"FVer_dmp.hxx"

int _tmain(int argc, TCHAR* argv[])
{
	_tsetlocale(LC_ALL,_T("")) ;
	::reg_argv(argc,argv) ;
	::dmp_self_version() ;
	::pause() ;
	return 0 ;
	}

FVer_dmp.hxx に分離

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

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.

warning C4786

VC 6 でビルドしているとよく出力される C4786

--------------------Configuration: T_prm_c - Win32 Debug--------------------
Compiling...
T_prm_c.cpp
c:\program files (x86)\microsoft visual studio\vc98\include\utility(21) : warning C4786: 'std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const *,std::basic_string<char,std::char_traits<char>,std::allocator<char> > con
st *>::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const *,std::basic_string<char,std::char_traits<char>,std::allocator<char> > const *>' : identifier was truncated to '255' characters in the debug information
Linking...
T_prm_c.exe - 0 error(s), 1 warning(s)

warning C4786
最初の頃は場所が限定てきていたので #pragma warning (… : 4786 ) で切り替えていた.
がそのうち,プロジェクトによっては StdAfx.h で対応する様になった.


古くからのプロジェクトで,直接はこれらの対応を行っていない(共通のヘッダでの対応)プロジェクトが幾つもある.
コンパイル単位ではほとんど C4786 は出力されないが,一部のソースで出力され,また限定できたのでそのメモ.

--------------------Configuration: BlockIn - Win32 Debug--------------------
Compiling...
SMastSel.cpp
c:\program files (x86)\microsoft visual studio\vc98\mfc\include\afxtempl.h(63) : warning C4786: 'std::vector<std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char
>,std::allocator<char> > > >,std::allocator<std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > > >' : identifier was truncated to '
255' characters in the debug information
SMastSel.obj - 0 error(s), 1 warning(s)

ソースに #pragma warning (disable : 4786 ) を追加して,更にそのヘッダがインクルードしているものをソースに追加.
warning C4786  AfxTempl.h
これで AfxTempl.h をインクルードしているヘッダファイルが限定できた.


iostream を使用している場合も,その前に disable : C4786 が必要みたいだが,その場合は簡単には見つけられない?
warning C4786  iostream


他には fstream ,string .

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.

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.

error C2272

次の様なコードで static にしようとすると,

class	RegPatNo	:	public	iDocCSV	{
//	...
public:
/*	static	*/	tstring		GetPathRPC	(void)	const ;
	} ;

inline	tstring	RegPatNo::GetPathRPC	(void)	const
{

	tstring	tmp_path = ::Get_i_Tools_tmp_date() ;
	::Folder_Create(tmp_path) ;
	tstring	rpc_name = ::Path_AddLastSP(tmp_path) + FN_RP_csv ;
	return	rpc_name ;
	}
--------------------Configuration: T_CSV_ - Win32 Debug--------------------
Compiling...
T_CSV_.cpp
t:\develop\_.src\test\regpatno.hpp(101) : error C2272: 'GetPathRPC' : modifiers not allowed on static member functions
Error executing cl.exe.

T_CSV_.exe - 1 error(s), 0 warning(s)

error C2272  : modifiers not allowed on static member functions
次の様に const の指定を外さなければならない.
static tstring GetPathRPC (void) ;
const の指定を外す

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

DirectoryNotFoundException

以前作成した .NET の ZipFile クラス使用した exe
この iZIP.exe で System.IO.DirectoryNotFoundException .


原因は,ある環境でユーザ名に半角スペースが含まれていた.
ユーザ名に半角スペースを含む環境を作成して ZipFold.exe で同じ様な操作を行ったが,再現できない.
いろいろと調べていると,iZIP.exe に渡す時の入力のフォルダ名に半角スペースが含まれていると現象が発生する.

C:\Users\Iwao\AppData\Local\Temp\i_Tools.tmp\test>Q:\C_Temp\i_Tools\ZIP\iZIP\Release.140\iZIP.exe a "C:\Users\Iwao\AppData\Local\Temp\Send.tmp\20240416\09 22 39\" abc.zip

ハンドルされていない例外: System.IO.DirectoryNotFoundException: パス 'C:\Users\Iwao\AppData\Local\Temp\i_Tools.tmp\zip_CLI\20240416\154459\a' の一部が見つかりませんでした。
   場所 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   場所 System.IO.FileSystemEnumerableIterator`1.CommonInit()
   場所 System.IO.FileSystemEnumerableIterator`1..ctor(String path, String originalUserPath, String searchPattern, SearchOption searchOption, SearchResultHandler`1 resultHandler, Boolean checkHost)
   場所 System.IO.DirectoryInfo.EnumerateFileSystemInfos(String searchPattern, SearchOption searchOption)
   場所 System.IO.Compression.ZipFile.DoCreateFromDirectory(String sourceDirectoryName, String destinationArchiveFileName, Nullable`1 compressionLevel, Boolean includeBaseDirectory, Encoding entryNameEncoding)
   場所 ZipFile_create(Char* fld_file, Char* zip_name) 場所 c:\program files (x86)\microsoft visual studio 14.0\vc\include\xstring:行 1017
   場所 zip_create(basic_string<wchar_t\,std::char_traits<wchar_t>\,std::allocator<wchar_t> >* , Char* zip_root) 場所 t:\develop\_.src\__mlt_\zip_func.hxx:行 47
   場所 zip_create(Char* fld_file, Char* zip_name) 場所 t:\develop\_.src\__mlt_\zip_func.hxx:行 143
   場所 call_func(Int32 argc, Char** argv) 場所 c:\program files (x86)\microsoft visual studio 14.0\vc\include\xstring:行 521
   場所 wmain(Int32 argc, Char** argv) 場所 l:\document\develop\tools\_free\ziptools\izip\izip.cpp:行 168
   場所 _wmainCRTStartup()

C:\Users\Iwao\AppData\Local\Temp\i_Tools.tmp\test>Q:\C_Temp\i_Tools\ZIP\iZIP\Release.140\iZIP.exe a "C:\Users\Iwao\AppData\Local\Temp\Send.tmp\20240416\09 22 39\" ".\20240416\1545\abc.zip"

ハンドルされていない例外: System.IO.DirectoryNotFoundException: パス 'C:\Users\Iwao\AppData\Local\Temp\i_Tools.tmp\zip_CLI\20240416\154602\a' の一部が見つかりませんでした。
   場所 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   場所 System.IO.FileSystemEnumerableIterator`1.CommonInit()
   場所 System.IO.FileSystemEnumerableIterator`1..ctor(String path, String originalUserPath, String searchPattern, SearchOption searchOption, SearchResultHandler`1 resultHandler, Boolean checkHost)
   場所 System.IO.DirectoryInfo.EnumerateFileSystemInfos(String searchPattern, SearchOption searchOption)
   場所 System.IO.Compression.ZipFile.DoCreateFromDirectory(String sourceDirectoryName, String destinationArchiveFileName, Nullable`1 compressionLevel, Boolean includeBaseDirectory, Encoding entryNameEncoding)
   場所 ZipFile_create(Char* fld_file, Char* zip_name) 場所 c:\program files (x86)\microsoft visual studio 14.0\vc\include\xstring:行 1017
   場所 zip_create(basic_string<wchar_t\,std::char_traits<wchar_t>\,std::allocator<wchar_t> >* , Char* zip_root) 場所 t:\develop\_.src\__mlt_\zip_func.hxx:行 47
   場所 zip_create(Char* fld_file, Char* zip_name) 場所 t:\develop\_.src\__mlt_\zip_func.hxx:行 143
   場所 call_func(Int32 argc, Char** argv) 場所 c:\program files (x86)\microsoft visual studio 14.0\vc\include\xstring:行 521
   場所 wmain(Int32 argc, Char** argv) 場所 l:\document\develop\tools\_free\ziptools\izip\izip.cpp:行 168
   場所 _wmainCRTStartup()

C:\Users\Iwao\AppData\Local\Temp\i_Tools.tmp\test>

iZIP.exe  System.IO.DirectoryNotFoundException
入力のフォルダ名の “…\20240416\09 22 39\” の “09 22 39” 直後の ‘\’ を削除するとうまくいく.


デバッガで iZIP.exe に渡されるコマンドラインを確認.
iZIP.exe コマンドライン引数
デバッグ時,ダンプする様にコードを書換え.
iZIP.exe コマンドライン引数のダンプ
やはり argv がうまく解釈されていない.
argv[2]が「…\17 53 06″ c:\…」となってしまっている.
“…\17 53 06\\” の様にすれば通ることは確認できた.
perse_commandline では ‘\”‘ がダブルクォーテーションと解釈され,’\\’ はバックスラッシュ?


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.

引数が正しくありません

ツールチップの表示内容に幾つかの情報を追加してテストしていると…
—————————
xxxxxxxx
—————————
引数が正しくありません。
—————————
OK
—————————
引数が正しくありません
デバッガで追いかけると MAX_TIP_TEXT_LENGTH の制限を超えていた.
CToolTipCtrl::UpdateTipText
呼び元で超えない様にカットして対応.

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

フォルダの更新日時の設定

以前に作成した mtime を更新するツール
データファイルなどの更新日時を揃えるために作成したもの.
更新日時の設定は CFile::SetStatus で行っている.

	CString		file = UpdateFiles[index] ;
	CFileStatus	fs ;
	CFile::GetStatus(file,fs) ;
	fs.m_mtime = newTime ;
	CFile::SetStatus(file,fs) ;

このツールではフォルダの更新日時は変更できない.


その後 Linux 環境などでも動作する様なコードを作成
utime を使用したもの.
Linux 環境ではフォルダに対してもうまく動作するが,Windows 環境では相変わらず.
DS220  utime
ここまでは,以前調べたもの


2ヶ月ほど前だったと思うが,検索していて次のページを見つけた.
ファイル・フォルダーの更新日時を変更


改めて CFile::SetStatus や _utime の中身を見ると,動作は同じで ::CreateFile と ::SetFileTime を呼出している.
デバッガで追いかけていると ::CreateFile で失敗している.errno は 13 .
::CreateFile を次の様に指定して呼出すと,ファイルの場合は問題ないがフォルダは NG .

HANDLE  hFile = ::CreateFile(file_name,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,     NULL) ;

フォルダの場合 FILE_FLAG_BACKUP_SEMANTICS が指定されていなければならないみたい.

HANDLE  hFile = ::CreateFile(file_name,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL) ;

time_t から FILETIME への変換は次の所.
https://learn.microsoft.com/ja-jp/windows/win32/sysinfo/converting-a-time-t-value-to-a-file-time
SetFTime.hxx


2024/08/09
https://itl.mish.work/i_Tools/Doc/blog/vc/UpdateMT.zip

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

.INI に更新されない?

個人的なツールなどでレジストリを汚したくないために .ini を使用している.
今回個人的な ProtectT クラスを書き直してテストしているとうまく動作しない.
該当コードの単体テストではうまく通るが,ツールに組込んで動作させるとうまくいかないことがある.
コードの内容としては,共通の i_Tools.ini と AP.ini に同じ値を更新していて,それを読みだした時に値が異なっていた.


i_Tools.ini は他の AP からも読み書きしている.
タイミングによって,うまく更新できないことがある?
文字の立体化
ProtectT の i_Tools.ini へアクセスするコードを見直して,極力書き込みを減らすようにした.
また,読み込み時,値が意図したものと異なる場合は AP.ini の方を利用する様にした.
これで今回の部分は対応できていると思うが,他の既存部分ではまだ問題がありそう.


次の様なコードで確認すると,やはり書けないことがある様子.

	{
		#define	Sec_test  _T("_test_")
		#define	Ent_test  _T("_test_")
		RI_app	app ;
		RI_env	env ;
		for (long index=0 ; index<500 ; index++) {
			if (index%10 == 0)	{	std::tout << std::endl ;	}
			std::tout << index << _T("\t") ;
			std::tout << app.set(Sec_test,Ent_test,index) ;	std::tout << _T("  ") ;
			std::tout << env.set(Sec_test,Ent_test,index) ;	std::tout << _T("\t") ;
			long	val_a = app.get(Sec_test,Ent_test,-1) ;
			long	val_e = env.get(Sec_test,Ent_test,-2) ;
			if (val_a != val_e) {
				std::tout << std::endl ;
				std::tout << val_a << _T("\t") << val_e << std::endl ;
				::Sleep(1000) ;
				break ;
				}
			::Sleep(10) ;
			}
		std::tout << std::endl ;
		return	true ;
		}

env.set(…) は,内部的に ::WritePrivateProfileString を呼出していて 0 が返っている.
::WritePrivateProfileString


最初現象を簡単には再現できなかったが,エクスプローラのサムネイル表示を行っていると発生しやすい.
また,今回のテスト用 exe が止まってしまうこともあった.開いているエクスプローラをすべて閉じることで解消.
シェルエクステンションのコードの見直しが必要か?


ini への書き込み部分を次の様に変更.

//	return	(     ::WritePrivateProfileString(sec,ent,val,ini)==TRUE) ;
	BOOL	res = ::WritePrivateProfileString(sec,ent,val,ini) ;
	if (!res)	{
		std::terr << _T("::WritePrivateProfileString ")	<< sec << _T(" ") << ent << _T(" ") << ::GetLastError() << std::endl ;
		for (size_t index=0 ; index<10 ; index++) {
			res = ::WritePrivateProfileString(sec,ent,val,ini) ;
			if (res)	{	break ;		}
			::Sleep(10) ;
			}
		}
	return	(res==TRUE) ;

::GetLastError() では 32 ERROR_SHARING_VIOLATION が返ってくる.

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