New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
フォルダ選択ダイアログを SHBrowseForFolder() でなく IFileDialog を使用するように変更 #1609
Conversation
✅ Build sakura 1.0.3610 completed (commit ac8181694c by @Ocelot1210) |
@Ocelot1210 さん はじめましてでしょうか。PR趣旨は了解です。 いまのところ、レビューして「問題ありません」で解決した実績はないです。
SonarCloud指摘に対する対処は「絶対必要」というわけではないです。
「対応しない理由」が(普通に考えて)納得できるようなら「スルー」で良いと思っています。 |
@berryzplus さん、はじめまして
本件、格納先の要素数を渡すため |
❌ Build sakura 1.0.3612 failed (commit 6d2c2a9783 by @Ocelot1210) |
appveyorのビルド失敗が意味不明なのでリビルドかけときました。 |
✅ Build sakura 1.0.3612 completed (commit 6d2c2a9783 by @Ocelot1210) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
判断できずに放置してしまっていました。
対応したい変更はできてそうなので結論を出しておきます。
「分かんなかったらapprove」で良いこともあると思うんですよね。
人間、一人で全領域のスペシャリストにはなれないのだから。
それで問題を起こさないようにするためのCIで、SonarCloudだと思っています。
一応、今回は動かしたっす 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
テンプレート引数で固定長配列の要素数を取る SelectDir
のオーバーロード関数を追加する事で、呼び出し側で最後の引数指定(例えば _countof(szPath)
)を省略出来るので便利かもと思いました。
@beru さん、PR のご確認ありがとうございます |
✅ Build sakura 1.0.3631 completed (commit 32e6321cdd by @Ocelot1210) |
✅ Build sakura 1.0.3636 completed (commit 63b0339342 by @Ocelot1210) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
細かいところは後まわしでもいいような気がするんですよね・・・。
BOOL SelectDir(HWND hWnd, const WCHAR* pszTitle, const WCHAR* pszInitFolder, WCHAR* strFolderName, size_t nMaxCount ); /* フォルダ選択ダイアログ */ | ||
|
||
template <size_t nMaxCount> | ||
BOOL SelectDir(HWND hWnd, const WCHAR* pszTitle, const WCHAR* pszInitFolder, WCHAR(&strFolderName)[nMaxCount]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここ、SonarCloudの警告がでました。
対応は必須でないと思いますが、あるべき姿で考えると「戻り値BOOL」がマズいのかもです。
std::wstring SelectDir(
HWND hWnd,
std::wstring_view title,
std::wstring_view initFolder);
@@ -259,7 +259,7 @@ BOOL CDlgExec::OnBnClicked( int wID ) | |||
|
|||
case IDC_BUTTON_REFERENCE2: | |||
{ | |||
if( SelectDir( GetHwnd(), LS(STR_DLGEXEC_SELECT_CURDIR), &m_szCurDir[0], &m_szCurDir[0] ) ){ | |||
if( SelectDir( GetHwnd(), LS(STR_DLGEXEC_SELECT_CURDIR), &m_szCurDir[0], &m_szCurDir[0], m_szCurDir.GetBufferCount() ) ){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
戻り値BOOLをやめた場合、ここはこんな感じになります。
if( auto selectedDir = SelectDir( GetHwnd(), LS(STR_DLGEXEC_SELECT_CURDIR), &m_szCurDir[0] ); selectedDir.length() > 0 ){
m_szCurDir = selectedDir.c_str();
m_szCurDir の宣言型がおかしいのが原因で、ロジックが書きづらくなっています。
対応はしなくてもいいんじゃないかなぁ、と思います。
sakura_core/util/shell.cpp
Outdated
@param [in] pDialog 設定対象のダイアログ | ||
@param [in] pszInitFolder 初期フォルダに設定したいパス | ||
*/ | ||
static void SetInitialDir( Microsoft::WRL::ComPtr<IFileDialog> pDialog, const WCHAR* pszInitFolder ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
別に正しく書く必要はありませんが、使い方が間違っています。
static void SetInitialDir( Microsoft::WRL::ComPtr<IFileDialog> pDialog, const WCHAR* pszInitFolder ) | |
static void SetInitialDir( IFileDialog* pDialog, const WCHAR* pszInitFolder ) |
あとは好みですが、第二引数は std::wstring_view がいいっす。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
対応いたしました
ご指摘頂きありがとうございます
sakura_core/util/shell.cpp
Outdated
wcscpy_s( szInitFolder, _countof(szInitFolder), pszInitFolder ); | ||
|
||
// フォルダの最後が半角かつ'\\'の場合は、取り除く "c:\\"等のルートは取り除かない | ||
CutLastYenFromDirectoryPath( szInitFolder ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😃
あるべき姿で考えるとSelectDirのシグニチャはこうなんですよね。 std::filesystem::path SelectDir(
HWND hWnd,
std::wstring_view title,
std::filesystem::path initFolder); このグローバル関数が扱う対象は何でしょう?
|
✅ Build sakura 1.0.3640 completed (commit 8e1ad6126c by @Ocelot1210) |
✅ Build sakura 1.0.3644 completed (commit d0f4746e1d by @Ocelot1210) |
✅ Build sakura 1.0.3645 completed (commit 3c49f909ff by @Ocelot1210) |
sakura_core/util/shell.cpp
Outdated
return FALSE; | ||
} | ||
|
||
if ( nMaxCount < wcslen(pszResult) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この行でSecurity Hotspotが検出されとります。
if ( nMaxCount < wcslen(pszResult) ) { | |
if ( pszResult != nullptr && nMaxCount < wcsnlen( pszResult, nMaxCount ) ) { |
になるのかなぁ・・・。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IShellItem::GetDisplayName
が成功時に pszResult
の値が nullptr になる事があるのかどうかは疑問ですが、仮にそうなる事があるとしてその場合に wcsnlen
を呼ばないようにしたいという事でしょうか?
ただこの記述だと仮に pszResult
が nullptr の時に wcsnlen
は呼ばれないですが、wcscpy_s
は呼ばれますよね。
それならばそもそも pszResult
が nullptr の場合は return FALSE;
した方が良いと思いますね。まぁ無いと思いますが…。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strnlen-strnlen-s?view=msvc-160
の説明に下記のように書かれていました。
strnlen, wcsnlen, and _mbsnlen do not validate their parameters. If str is NULL, an access violation occurs.
strnlen_s and wcsnlen_s validate their parameters. If str is NULL, the functions return 0.
実際に pszResult
が NULL 値になるとは思いませんが使うなら wcsnlen
より wcsnlen_s
が良いと思います。
あと wcsnlen
はC標準規格には無いのか下記のページには載っていませんでした。
https://en.cppreference.com/w/c/string/wide/wcslen
元の wcslen
関数を呼び出す記述だと SonarCloud が Security Hotspot を検出してきますが、実際には問題は無いと思うんですよね。GetDisplayName
成功時に取得した文字列は有効領域と見なせると思います。
なお wcslen
の代わりに wcsnlen_s
を使う事による利点としては、SonarCloud が Security Hotspot を検出しなくなるのと、あと文字列長が出力先バッファ長を超える場合にそこでループを中断させる事が出来るので無駄が少ないですね。
というか IShellItem
が DisplayName
のバッファ長を返すメソッドを用意してくれていたら良かったんですが探しても見つかりませんでした。
util/shell.cpp 104行目からの修正案です。 BOOL bRet = TRUE;
if ( STRUNCATE == wcsncpy_s( strFolderName, nMaxCount, pszResult, _TRUNCATE ) ) {
wcscpy_s( strFolderName, nMaxCount, L"" );
bRet = FALSE;
}
CoTaskMemFree( pszResult );
return bRet; これなら pszResult の長さを取得する必要も、初期値を設定する必要もないです。 |
なお戻り値の判定は
どういう時にエラーコードが返るのか?については に書かれているので転載します。
例えば なお空文字を設定するのに wcscpy_s( strFolderName, nMaxCount, L"" ); を呼び出すのではなく というか nullptr 引数のチェックは |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
問題無いと思います。
PRの説明の影響範囲に列挙されていた箇所で、フォルダ選択ダイアログにVista以降のCommon Item Dialogが使われるようになった事の動作確認をしました。
SonarCloud が wcslen
の呼び出しを Security Hotspot として検出していますが、実際に今のコードでどういうケースでどういう問題が起きるのか(起こせるのか)は分かりません。
自分が分かっている範囲では SelectDir
関数の引数に NULL を渡したら問題が起きると思いますが、そのように呼び出している箇所は無いと思います。
という事で、それについては対応してもしなくてもどちらでも良いとの判断で Approve します。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security Hotspotが検出されないように修正を試みてほしいです。
ご指摘ありがとうございます 以下対応いたしました
|
SonarCloud Quality Gate failed. |
✅ Build sakura 1.0.3653 completed (commit 39b969ebcb by @Ocelot1210) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
対応ありがとうございます。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
動作確認して特に問題は見つかりませんでした。
PR の目的
フォルダ選択ダイアログの操作性を向上させる事が目的です
カテゴリ
PR の背景
SHBrowseForFolder
はツリー形式の UI のため操作性に難があります(特に深い階層のフォルダを選択する場合)SHBrowseForFolder
ではなく、FOS_PICKFOLDERS
オプションを指定したIFileDialog
を使用する事が推奨されています(詳細は参考資料 No.1 をご参照下さい)PR のメリット
フォルダ選択ダイアログの操作性が向上します
PR のデメリット (トレードオフとかあれば)
Vista 以前の OS (2000/XP) でフォルダ選択ダイアログが動作しなくなります
仕様・動作説明
変更前
SHBrowseForFolder
を使用してフォルダ選択ダイアログを表示します変更後
IFileDialog
にFOS_PICKFOLDERS
オプションを指定し、フォルダ選択ダイアログを表示しますPR の影響範囲
フォルダ選択ダイアログを表示する以下の項目に影響があります
テスト内容
テスト1
手順
テスト2
手順
関連 issue, PR
直接的な issue, PR はありませんが、 @beru さんが #1431 にて言及されております
参考資料