ホーム » VC
「VC」カテゴリーアーカイブ
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 ;
}
Windows の場合は __argc と __argv が利用できるのであまり必要ない.
::GetCommandLine を使用することも可能.
コンパイル時の #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)
VC6 プロジェクトのコードの移行
以前,VC 6 プロジェクトを移行する時の,設定などについて書いた.
VC6 から 2005 , 2008
VC6 から 2010 – 2019
VC6 から 2022
今回は 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++ 移植およびアップグレード ガイド
リリース版 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 で止めた時のメモリの状態.
今回の初期化されていない変数(赤くなっている次)が,’1′ になっていることを確認できた.
MFC ダイアログに描画
MFC ダイアログ exe で GDI などでの描画を行うときは,通常「Picture Control」を使用する.
メンバ変数として CStatic を割り当てて,その変数(ウィンドウ)に対して描画する.
CWnd::GetDlgItem や ::GetDlgItem でも良い.
単体テスト用など,それほど重要でないプロジェクトでダイアログに直接描画したい時がある.
リサイズ可能なダイアログの場合,Picture Control のリサイズなども意外と面倒なため.
VC 2022 で,MFC の「ダイアログ ベース」として作成.
ダイアログの基本クラスは「CDialog」とした.
CDlgDrwDlg::OnPaint() の else 部分を次の様に変更.
{
// CDialog::OnPaint();
{
CPaintDC dc(this);
CRect rect;
GetClientRect(&rect);
rect.DeflateRect(10, 10);
dc.Rectangle(rect);
}
}
ダイアログの「プロパティ」-「透明化」は「True」の方が良さそう.
https://itl.mish.work/i_Tools/Doc/blog/vc/DlgDrw.zip
VS 2022 の更新で「問題が…」
VS の更新があったので更新すると…
「申し訳ございません。問題が発生しました」.
どうも VC ランタイムのパッケージがインストールされなかったみたい.
デバッグや通常の実行も問題はなさそう.
前回とは違い「修復」で対応しようと思ったが…
どこまでがリセットされるかわからないので「変更」で対応.
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
}
変数追加後,コンボボックスのタイプを「標準」に変更.
コンソール 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 ;
}
VC6 から VC2022 への移行
VC 6 から 2022 へのアップグレードがなくなったので,手動での移行方法を試してみた.
VC6 から 2005 , 2008
VC6 から 2010 – 2019
「新しいプロジェクトの作成」で「空のプロジェクト」を選択して「次へ」
適当なプロジェクト名を付けて「作成」.
必要に応じて,VC 6 プロジェクトのファイルをコピー.
「ソリューション エクスプローラー」のプロジェクトを「右クリック」-「追加」-「既存の項目」.
cpp,h,rc を選択して「追加」.
必要に応じて「出力ディレクトリ」などの指定.
「共有 DLL で MFC を使う」に.
「_CONSOLE」を「_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 のみ.
ソリューションに *.h を追加する.
* 他の動作はまだ確認中です.
「バージョン情報」ダイアログ
バージョンリソースを読み込み「バージョン情報」ダイアログの表示で使用するコード.
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;
}
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)
最初の頃は場所が限定てきていたので #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 ) を追加して,更にそのヘッダがインクルードしているものをソースに追加.
これで AfxTempl.h をインクルードしているヘッダファイルが限定できた.
iostream を使用している場合も,その前に disable : C4786 が必要みたいだが,その場合は簡単には見つけられない?
他には fstream ,string .
::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) ;
}
VC6 から VC2019 への移行
今回は VC 6 ds? の VC 2019 への更新.
VS 2022 では,VC 6 からのアップグレードがなくなった.
VS 2019 で dsw を開き 2019 に更新.
設定は VC 8 の時の手順とほとんど変わらない(設定値が微妙に異なる部分あり).
出力ディレクトリなどを「c:\Temp\…\$(ProjectName)\$(Configuration).142\」に.
「文字セット」を「Unicode 文字セットを使用する」に.
「プリコンパイル済み…」を「$(IntDir)$(TargetName).pch」に.
「C/C++」の「出力ファイル」を「$(IntDir)」に.
「リンカ」の「出力ファイル」を「$(OutDir)$(ProjectName).exe」に.
「ブラウザ情報」の「出力ファイル」を「$(OutDir)$(ProjectName).bsc」に.
そのままビルドすると,デバッグ版では 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 などでも同じように指定することで移行が可能なことを確認.
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」に.
「プリコンパイル済み…」を「$(IntDir)/$(TargetName).pch」に.
「C/C++」の「出力ファイル」を「$(IntDir)/」に.
「リンカ」の「出力ファイル」を「$(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 に.
vC 9 以降に更新する場合は Test.sln を開く.
出力ディレクトリなどを「c:\Temp\…\$(ProjectName)\$(ConfigurationName).090」などに.
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() の呼出しを追加する.
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)
次の様に const の指定を外さなければならない.
static tstring GetPathRPC (void) ;
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>
入力のフォルダ名の “…\20240416\09 22 39\” の “09 22 39” 直後の ‘\’ を削除するとうまくいく.
デバッガで iZIP.exe に渡されるコマンドラインを確認.
デバッグ時,ダンプする様にコードを書換え.
やはり argv がうまく解釈されていない.
argv[2]が「…\17 53 06″ c:\…」となってしまっている.
“…\17 53 06\\” の様にすれば通ることは確認できた.
perse_commandline では ‘\”‘ がダブルクォーテーションと解釈され,’\\’ はバックスラッシュ?
「引数が正しくありません」
以前に書いた情報を整理.
Win10 環境で,MDI exe にドキュメントをドロップすると「引数が正しくありません」となることがある.
原因は ::CoInitinalize が呼び出されていないため.
コードでの対応方法としては InitInstance の最初に以下を追加.
// OLE ライブラリを初期化します。
if (!AfxOleInit()) {
AfxMessageBox(_T("OLE の初期化に失敗しました。")) ;
return FALSE ;
}
また,一度「開く」ダイアログを表示すると,その後は問題ない.
フォルダの更新日時の設定
以前に作成した 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 環境では相変わらず.
ここまでは,以前調べたもの.
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
.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 が返っている.
最初現象を簡単には再現できなかったが,エクスプローラのサムネイル表示を行っていると発生しやすい.
また,今回のテスト用 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 が返ってくる.