Skip to content
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

外部コマンド実行でキャンセルした時のメッセージが異なる問題を修正 #1721

Conversation

beru
Copy link
Contributor

@beru beru commented Aug 29, 2021

PR の目的

#1720 で報告された、外部コマンド実行でキャンセルした時のメッセージが異なる問題を修正するのが目的です。

カテゴリ

  • 不具合修正

テスト内容

テスト1

手順

  1. 外部コマンド実行で名前「notepad」「標準出力を得る」「アウトプットウィンドウ」でコマンドを実行します。
  2. アウトプット画面が表示されたら閉じます。
  3. notepadの終了待ちのダイアログをキャンセルします。
  4. 2個目の新しくできたアウトプットウィンドウのメッセージが正しいか確認します。

関連 issue, PR

#1720

@beru beru added the 🐛bug🦋 ■バグ修正(Something isn't working) label Aug 29, 2021
@AppVeyorBot
Copy link

Build sakura 1.0.3903 completed (commit dcc6e4666c by @beru)

@@ -570,7 +570,7 @@ bool CEditView::ExecCmd( const WCHAR* pszCmd, int nFlgOpt, const WCHAR* pszCurDi
if( bCancelEnd && bOutputExtInfo ){
// 2006.12.03 maru アウトプットウィンドウにのみ出力
//最後にテキストを追加
oa.OutputW( LS(STR_EDITVIEW_EXECCMD_STOP) );
oa.OutputW( CLoadString().LoadStringW(STR_EDITVIEW_EXECCMD_STOP) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSelectLang.h/cppのコード上のメソッド名定義はLoadStringですね。
WIN32APIのマクロによりLoadStringWに置換されるのだと思いますが、サクラ上の定義とは食い違います。
たぶんここはWなしのLoadStringのほうにしたほうがいいと思います。

Copy link
Contributor Author

@beru beru Aug 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

指摘ありがとうございます。 d0d63b7 で修正しました。

@AppVeyorBot
Copy link

Build sakura 1.0.3904 completed (commit 90f20ba942 by @beru)

@berryzplus
Copy link
Contributor

何がいけなかったんですかね?

@@ -570,7 +570,7 @@ bool CEditView::ExecCmd( const WCHAR* pszCmd, int nFlgOpt, const WCHAR* pszCurDi
if( bCancelEnd && bOutputExtInfo ){
// 2006.12.03 maru アウトプットウィンドウにのみ出力
//最後にテキストを追加
oa.OutputW( LS(STR_EDITVIEW_EXECCMD_STOP) );
oa.OutputW( CLoadString().LoadString(STR_EDITVIEW_EXECCMD_STOP) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

全く分からんです。

この直し方で修正するってことは、他にも「直さないといけない箇所」がたくさん出てきそうで、影響調査とかめんどいです。

oa.OutputW()の呼出し箇所すべてで考慮が必要ですよね?

渡された引数の内容を処理完了までキープしておく責任があるのは呼ばれた側のような気がします。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oa.OutputW()の呼出し箇所すべてで考慮が必要ですよね?

呼び出し箇所で問題が起きそうかどうかの見極めは必要だと思います。

文字列リテラル等の定数値を渡している箇所については特に問題無いと思います。
スタック上の文字列領域もリエントラントなので多分大丈夫だと思います。
LSマクロはstatic記憶領域の変数を使う CLoadString::LoadStringSt の呼び出しになりリエントラントではなく問題が発生しました。

OutputW で Grep したところ他にLSマクロと組み合わせて使用している記述は見当たりませんでした。
なので多分大丈夫な気もしますが、考慮漏れで同様の問題が起きる可能性は否定出来ません。

まぁワニワニパニック大好きなのでその時はまたなんとかすれば良いと思います。変更をする事で不具合がたくさん追加されるとかだとさすがにまずいと思いますが。。

渡された引数の内容を処理完了までキープしておく責任があるのは呼ばれた側のような気がします。

それは一概に言い切れないケースバイケースだと思います。

bool COutputAdapterDefault::OutputW(const WCHAR* pBuf, int size)

こういうプロトタイプのメソッドの呼び出しですが、第1引数のポインタが指す領域の内容が変わる事は、少なくとも利用する呼ぶ側では意識しないと思います(なのでLSマクロのままにしたいんだと言われたら納得しちゃいそう)。呼ばれる側の実装でもなかなか意識しにくいので問題が生じうる実装になっているのではないかと。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

影響確認実施済みなのは了解しました。
また、oa.OutputW()の呼ばれた側で対策するのがつらいのもなんとなく分かりました。

@beru
Copy link
Contributor Author

beru commented Sep 3, 2021

何がいけなかったんですかね?

問題発生のメカニズムについては、#1720 (comment) に書かれている通り、下記の流れで問題が起きているんじゃないかと思います。

=> COutputAdapterDefault::OutputW
=> COutputAdapterDefault::OutputBuf
=> m_pCShareData->TraceOutString
=> CShareData::OpenDebugWindow
=> ActivateFrameWindow
=> SendMessageTimeout

~~~メッセージループ~~~

=> CEditWndProc
=> CEditWnd::DispatchEvent
  case WM_ACTIVATEAPP:
=> CEditWnd::UpdateCaption
=> CSakuraEnvironment::ExpandParameter
  const wstring	PRINT_PREVIEW_ONLY		= LS( STR_PREVIEW_ONLY );	//L"(印刷プレビューでのみ使用できます)";
=> CLoadString::LoadStringSt

LSマクロがstatic記憶領域の変数を使う CLoadString::LoadStringSt の呼び出しになりリエントラントでは無いのが問題の根本的な原因です。ただLSマクロは使用頻度が高いのでメモリの動的確保を避ける為にstatic記憶領域を使う実装にした判断はなかなか否定出来ないです。

他に考えられる対策としては CShareData::TraceOutStringOpenDebugWindow を呼ぶ前に引数の文字列を別の領域にコピーする事でしょうか?ただ文字列リテラル等の定数値を渡している場合にはそれは本来は不要な事だと思うので少しもったいないですね。


GUIのデザインが問題が起きうる操作を誘発している気がしますが、まぁ古いソフトなのでしょうがないですね。

@berryzplus
Copy link
Contributor

妥協できる直し方を書いてみます

			//最後にテキストを追加
			oa.OutputW( LS(STR_EDITVIEW_EXECCMD_STOP) );

 👇

			// L"\r\n中断しました。\r\n"
                        std::wstring msg( LS(STR_EDITVIEW_EXECCMD_STOP) );
			oa.OutputW( msg.c_str(), (int)msg.length() );

・OutputWの処理内容を説明する無駄なコメントを削除。
・リソースの内容が分かるようコメントを付加。
・リソース文字列をコピーするよう変更。

こういう書き方にするメリットは、普通の人でも「ちょっと待て!」と言えるようになることです。

@beru
Copy link
Contributor Author

beru commented Sep 8, 2021

妥協できる直し方を書いてみます

			//最後にテキストを追加
			oa.OutputW( LS(STR_EDITVIEW_EXECCMD_STOP) );

 👇

			// L"\r\n中断しました。\r\n"
                        std::wstring msg( LS(STR_EDITVIEW_EXECCMD_STOP) );
			oa.OutputW( msg.c_str(), (int)msg.length() );

・OutputWの処理内容を説明する無駄なコメントを削除。
・リソースの内容が分かるようコメントを付加。
・リソース文字列をコピーするよう変更。

こういう書き方にするメリットは、普通の人でも「ちょっと待て!」と言えるようになることです。

berryzplusさんがその書き方にしたいならそうします。ちなみに大文字の単語 LS でGrepすると900件近くヒットします。文字列ロード簡易化マクロ LS がサクラエディタのコードでは標準的に使われているので、リソース文字列を読み込む記述で変な例外的な記述をしたくはないという考えでしょうか?

個人的には CLoadString クラスの LoadString メソッドを使うと異常者と見做されるのが解せないのですが…。

@berryzplus
Copy link
Contributor

berryzplusさんがその書き方にしたいならそうします。

「その書き方にしたいかどうか」は自明だと思いますが 😃
長いこと回答を付けてなかったカタチになってるのであえて回答します・・・「はい」です。

ちなみに大文字の単語 LS でGrepすると900件近くヒットします。
文字列ロード簡易化マクロ LS がサクラエディタのコードでは標準的に使われているので、リソース文字列を読み込む記述で変な例外的な記述をしたくはないという考えでしょうか?

ほぼほぼお察しの通りです。

「標準的な記述プラスアルファ」にしておけば、
「なんか特殊なことしてる」が分かりやすいんじゃないかなと思います。

個人的には CLoadString クラスの LoadString メソッドを使うと異常者と見做されるのが解せないのですが…。

「異常者」と看做したつもりはないです。
が、その方式はなんか気に食わんです・・・。

CLoadString クラスの LoadString メソッドを使う方式が気に食わない理由を挙げてみます。
(理由を挙げて妥協できるか検討します。)

  • クラス名がWindows SDKのマクロと酷似していて紛らわしい(目視による誤認を誘発する気がします
  • メソッド名がWindows SDKのマクロと衝突していて「超」紛らわしい(IDEのコード参照機能が使えなくて不便です
  • 既存コードで利用実績がほとんどない

 👇

  • クラス名が~はなんかもう、存在否定ですよね。ただ、マクロなどを使ってクラス名がコード中に現れないようにしてやれば、クラス名の問題は回避できます。マクロを使った回避策だと「クラス名を直接書かないといけないケース」に遭遇したときに「なんだこの珍クラス名は?」ってなりますね、今回のように。まぁ、誤認による被害(?)は起きない気がするので、この点は妥協できそうです。
  • メソッド名が~はLoadStringWと書くことで回避できます。外部コマンド実行でキャンセルした時のメッセージが異なる問題を修正 #1721 (comment) で指摘されて「Wなし」に修正してますね。問題の本質はIDEがショボ・・・じゃなかった、windows SDKの「マクロ」と同名の関数を「誤って」定義していることなので、指摘も修正も「悪いってわけじゃない」と思います。このメソッドは、利用箇所が少ないうちに適切な名前(≒Windows SDKマクロと衝突しない名前)にリネームすべきだと思います。この点は、できれば妥協したくないです。
  • 既存コードは、1箇所だけですがCLoadString::LoadStringWメソッドを利用しています。たった1箇所でも利用実績なので、これをもって「流用できる」と判断するのは妥当と思います。なので、この点は妥協できます。

というわけで、総合的に見て結論は「妥協できる」になりました。

@beru
Copy link
Contributor Author

beru commented Sep 20, 2021

「その書き方にしたいかどうか」は自明だと思いますが 😃
長いこと回答を付けてなかったカタチになってるのであえて回答します・・・「はい」です。

回答ありがとうございます。特にこの変更に関してこだわりがあるわけではないのでberryzplusさんが書いてくれた内容で更新しておきました。

「標準的な記述プラスアルファ」にしておけば、
「なんか特殊なことしてる」が分かりやすいんじゃないかなと思います。

事情を知らない人が見ると文字列型の一時変数にどうしてコピーしてるんだろう?と思うかもしれないですね。
とはいえ読み手に分かるようにコメントで解説を書くのもなんか辛いです。

CLoadString クラスの LoadString メソッドを使う方式が気に食わない理由を挙げてみます。

というわけで、総合的に見て結論は「妥協できる」になりました。

命名はなんだか悩ましいですね。CLoadString::LoadString という名前が微妙ですが、これを今更変える気は自分はしないです。LSマクロは名前が2文字で衝突が怖いですが、お手軽に使えるのは良いとこですね。

@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

0.0% 0.0% Coverage
0.0% 0.0% Duplication

@AppVeyorBot
Copy link

Build sakura 1.0.3910 completed (commit 2acbd09a5d by @beru)

Copy link
Contributor

@berryzplus berryzplus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

対応ありがとうございます。

コードの意図を1行コメントで追加したほうがいいかも・・・と思ったので気が向いたら別件で追加修正の提案を出すかも知れません。

@beru
Copy link
Contributor Author

beru commented Sep 20, 2021

レビューありがとうございました。Mergeします。

@beru beru merged commit f706330 into sakura-editor:master Sep 20, 2021
@beru beru deleted the ExecCmd_LS_overwritten_STR_EDITVIEW_EXECCMD_STOP branch September 20, 2021 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛bug🦋 ■バグ修正(Something isn't working)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants