diff --git a/sakura_core/Makefile b/sakura_core/Makefile index 39ffe880c5..d58763fc0e 100644 --- a/sakura_core/Makefile +++ b/sakura_core/Makefile @@ -98,7 +98,6 @@ LIBS= \ -lwinmm \ -lwindowscodecs \ -lmsimg32 \ - -lurlmon \ -mwindows \ -municode \ $(MYLIBS) diff --git a/sakura_core/cmd/CViewCommander_File.cpp b/sakura_core/cmd/CViewCommander_File.cpp index 178fe24387..72c43af18d 100644 --- a/sakura_core/cmd/CViewCommander_File.cpp +++ b/sakura_core/cmd/CViewCommander_File.cpp @@ -451,10 +451,28 @@ void CViewCommander::Command_BROWSE( void ) ErrorBeep(); return; } - - std::wstring_view path(GetDocument()->m_cDocFile.GetFilePath()); - std::wstring url(strprintf(L"file:///%s", path.data())); - OpenWithBrowser(m_pCommanderView->GetHwnd(), url); +// char szURL[MAX_PATH + 64]; +// auto_sprintf( szURL, L"%ls", GetDocument()->m_cDocFile.GetFilePath() ); + /* URLを開く */ +// ::ShellExecuteEx( NULL, L"open", szURL, NULL, NULL, SW_SHOW ); + + SHELLEXECUTEINFO info; + info.cbSize =sizeof(info); + info.fMask = 0; + info.hwnd = NULL; + info.lpVerb = NULL; + info.lpFile = GetDocument()->m_cDocFile.GetFilePath(); + info.lpParameters = NULL; + info.lpDirectory = NULL; + info.nShow = SW_SHOWNORMAL; + info.hInstApp = 0; + info.lpIDList = NULL; + info.lpClass = NULL; + info.hkeyClass = 0; + info.dwHotKey = 0; + info.hIcon =0; + + ::ShellExecuteEx(&info); return; } @@ -523,9 +541,17 @@ void CViewCommander::Command_OPEN_FOLDER_IN_EXPLORER(void) return; } - // ドキュメントパスを変数に入れてWindowsエクスプローラーで開く - if (std::filesystem::path docPath = GetDocument()->m_cDocFile.GetFilePath(); - !OpenWithExplorer(GetMainWindow(), docPath)) { + // ドキュメントパスを変数に入れる + LPCWSTR pszDocPath = GetDocument()->m_cDocFile.GetFilePath(); + + // Windows Explorerの引数を作る + CNativeW explorerCommand; + explorerCommand.AppendStringF(L"/select,\"%s\"", pszDocPath); + LPCWSTR pszExplorerCommand = explorerCommand.GetStringPtr(); + + auto hInstance = ::ShellExecute(GetMainWindow(), L"open", L"explorer.exe", pszExplorerCommand, NULL, SW_SHOWNORMAL); + // If the function succeeds, it returns a value greater than 32. + if (hInstance <= (decltype(hInstance))32) { ErrorBeep(); return; } diff --git a/sakura_core/dlg/CDlgAbout.cpp b/sakura_core/dlg/CDlgAbout.cpp index d735db8ab0..3ffae9a82b 100644 --- a/sakura_core/dlg/CDlgAbout.cpp +++ b/sakura_core/dlg/CDlgAbout.cpp @@ -313,28 +313,28 @@ BOOL CDlgAbout::OnStnClicked( int wID ) // case IDC_STATIC_URL_ORG: del 2008/7/4 Uchi // Web Browserの起動 { - std::wstring url; - ApiWrap::DlgItem_GetText(GetHwnd(), wID, url); - OpenWithBrowser(GetHwnd(), url); + WCHAR buf[512]; + ::GetWindowText( GetItemHwnd( wID ), buf, _countof(buf) ); + ::ShellExecute( GetHwnd(), NULL, buf, NULL, NULL, SW_SHOWNORMAL ); return TRUE; } case IDC_STATIC_URL_CI_BUILD: { #if defined(CI_BUILD_URL) - OpenWithBrowser(GetHwnd(), _T(CI_BUILD_URL)); + ::ShellExecute(GetHwnd(), NULL, _T(CI_BUILD_URL), NULL, NULL, SW_SHOWNORMAL); #elif defined(GIT_REMOTE_ORIGIN_URL) - OpenWithBrowser(GetHwnd(), _T(GIT_REMOTE_ORIGIN_URL)); + ::ShellExecute(GetHwnd(), NULL, _T(GIT_REMOTE_ORIGIN_URL), NULL, NULL, SW_SHOWNORMAL); #endif return TRUE; } case IDC_STATIC_URL_GITHUB_COMMIT: #if defined(GITHUB_COMMIT_URL) - OpenWithBrowser(GetHwnd(), _T(GITHUB_COMMIT_URL)); + ::ShellExecute(GetHwnd(), NULL, _T(GITHUB_COMMIT_URL), NULL, NULL, SW_SHOWNORMAL); #endif return TRUE; case IDC_STATIC_URL_GITHUB_PR: #if defined(GITHUB_PR_HEAD_URL) - OpenWithBrowser(GetHwnd(), _T(GITHUB_PR_HEAD_URL)); + ::ShellExecute(GetHwnd(), NULL, _T(GITHUB_PR_HEAD_URL), NULL, NULL, SW_SHOWNORMAL); #endif return TRUE; } diff --git a/sakura_core/prop/CPropComPlugin.cpp b/sakura_core/prop/CPropComPlugin.cpp index 065f5763af..eed2d5fb82 100644 --- a/sakura_core/prop/CPropComPlugin.cpp +++ b/sakura_core/prop/CPropComPlugin.cpp @@ -243,7 +243,7 @@ INT_PTR CPropPlugin::DispatchEvent( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPAR break; } } - OpenWithExplorer( hwndDlg, sBaseDir ); + ::ShellExecute( NULL, L"open", sBaseDir.c_str(), NULL, NULL, SW_SHOW ); } break; case IDC_PLUGIN_README: // ReadMe表示 // 2011/11/2 Uchi @@ -268,7 +268,7 @@ INT_PTR CPropPlugin::DispatchEvent( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPAR if (sel >= 0){ CPlugin* plugin = CPluginManager::getInstance()->GetPlugin(sel); if (plugin != NULL){ - OpenWithBrowser( hwndDlg, plugin->m_sUrl ); + ::ShellExecute(NULL, L"Open", plugin->m_sUrl.c_str(), NULL, NULL, SW_SHOW); } } } diff --git a/sakura_core/util/shell.cpp b/sakura_core/util/shell.cpp index c168c2c65f..a2566dea92 100644 --- a/sakura_core/util/shell.cpp +++ b/sakura_core/util/shell.cpp @@ -25,21 +25,11 @@ */ #include "StdAfx.h" -#include "util/shell.h" - -#include // CDERR_FINDRESFAILURE等 -#include -#include -#include -#include #include -#include #include - -#include - -#include "debug/Debug1.h" -#include "util/RegKey.h" +#include +#include // Nov. 3, 2005 genta //CDERR_FINDRESFAILURE等 +#include "util/shell.h" #include "util/string_ex2.h" #include "util/file.h" #include "util/os.h" @@ -50,8 +40,8 @@ #include "extmodule/CHtmlHelp.h" #include "config/app_constants.h" #include "String_define.h" +#include -#pragma comment(lib, "urlmon.lib") /* フォルダー選択ダイアログ */ BOOL SelectDir( HWND hWnd, const WCHAR* pszTitle, const WCHAR* pszInitFolder, WCHAR* strFolderName, size_t nMaxCount ) @@ -224,8 +214,36 @@ static LRESULT CALLBACK PropSheetWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, L // 選択されたメニューの処理 switch( nId ){ - case 100: // 設定フォルダーを開く - OpenWithExplorer(hwnd, GetIniFileName()); + case 100: // 設定フォルダを開く + WCHAR szPath[_MAX_PATH]; + GetInidir( szPath ); + + // フォルダの ITEMIDLIST を取得して ShellExecuteEx() で開く + // Note. MSDN の ShellExecute() の解説にある方法でフォルダを開こうとした場合、 + // フォルダと同じ場所に <フォルダ名>.exe があるとうまく動かない。 + // verbが"open"やNULLではexeのほうが実行され"explore"では失敗する + // (フォルダ名の末尾に'\\'を付加してもWindows 2000では付加しないのと同じ動作になってしまう) + LPSHELLFOLDER pDesktopFolder; + if( SUCCEEDED(::SHGetDesktopFolder(&pDesktopFolder)) ){ + LPMALLOC pMalloc; + if( SUCCEEDED(::SHGetMalloc(&pMalloc)) ){ + LPITEMIDLIST pIDL; + WCHAR* pszDisplayName = szPath; + if( SUCCEEDED(pDesktopFolder->ParseDisplayName(NULL, NULL, pszDisplayName, NULL, &pIDL, NULL)) ){ + SHELLEXECUTEINFO si; + ::ZeroMemory( &si, sizeof(si) ); + si.cbSize = sizeof(si); + si.fMask = SEE_MASK_IDLIST; + si.lpVerb = L"open"; + si.lpIDList = pIDL; + si.nShow = SW_SHOWNORMAL; + ::ShellExecuteEx( &si ); // フォルダを開く + pMalloc->Free( (void*)pIDL ); + } + pMalloc->Release(); + } + pDesktopFolder->Release(); + } break; case 101: // インポート/エクスポートの起点リセット(起点を設定フォルダーにする) @@ -574,7 +592,7 @@ BOOL MyWinHelp(HWND hwndCaller, UINT uCommand, DWORD_PTR dwData) WCHAR buf[256]; swprintf( buf, _countof(buf), L"https://sakura-editor.github.io/help/HLP%06Iu.html", dwData ); - OpenWithBrowser( ::GetActiveWindow(), buf ); + ShellExecute( ::GetActiveWindow(), NULL, buf, NULL, NULL, SW_SHOWNORMAL ); } return TRUE; @@ -628,173 +646,3 @@ BOOL MySelectFont( LOGFONT* plf, INT* piPointSize, HWND hwndDlgOwner, bool Fixed return TRUE; } - -//! Windows エクスプローラーで開く -bool OpenWithExplorer(HWND hWnd, const std::filesystem::path& path) -{ - if (path.empty()) { - return false; - } - - std::filesystem::path explorerPath; - std::wstring_view verb = L"explore"; - std::wstring_view file = path.c_str(); - std::wstring params; - const wchar_t* lpParameters = nullptr; - - // ファイル名(最後の'\'に続く部分)がドット('.')でない場合、 - // Windowsエクスプローラーのコマンドを指定してファイルを選択させる。 - // ※ドットは「フォルダー自身」を表す特殊なファイル名。 - if (path.filename() != L".") { - std::wstring buf(_MAX_PATH, wchar_t()); - size_t requiredSize; - _wgetenv_s(&requiredSize, buf.data(), buf.capacity(), L"windir"); - verb = L"open"; - explorerPath = buf.data(); - explorerPath /= L"explorer.exe"; - file = explorerPath.c_str(); - params = strprintf(L"/select,\"%s\"", path.c_str()); - lpParameters = params.c_str(); - } - - // If the function succeeds, it returns a value greater than 32. - if (auto hInstance = ::ShellExecuteW(hWnd, verb.data(), file.data(), lpParameters, nullptr, SW_SHOWNORMAL); - hInstance <= (decltype(hInstance))32) { - return false; - } - - return true; -} - -/*! - * 指定したプロトコルに関連付けされたProgIDを取得する - */ -std::wstring GetProgIdForProtocol(std::wstring_view protocol) -{ - constexpr const auto& defaultProgId = L"MSEdgeHTM"; - - // HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice - if (const auto keyPath(strprintf(LR"(SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\%s\UserChoice)", protocol.data())); - CRegKey::ExistsKey(HKEY_CURRENT_USER, keyPath.data())) - { - CRegKey regKey; - if (const auto errorCode = regKey.Open(HKEY_CURRENT_USER, keyPath.data(), KEY_READ); - errorCode != 0) - { - return defaultProgId; - } - - std::wstring buf(1024, wchar_t()); - if (const auto errorCode = regKey.GetValue(L"ProgId", buf.data(), static_cast(buf.capacity()), nullptr); - errorCode != 0) - { - return defaultProgId; - } - - buf.resize(::wcsnlen(buf.data(), 1024)); - - return buf; - } - - return defaultProgId; -} - -/*! - * 指定したProgIDに関連付けされたコマンドラインを取得する - */ -std::wstring GetCommandAssociatedWithProgID(std::wstring_view progId) -{ - constexpr const auto& notAssociated = L""; - - // HKEY_CLASSES_ROOT\MSEdgeHTM\shell\open\command - if (const auto keyPath(strprintf(LR"(%s\shell\open\command)", progId.data())); - CRegKey::ExistsKey(HKEY_CLASSES_ROOT, keyPath.data())) - { - CRegKey regKey; - if (const auto errorCode = regKey.Open(HKEY_CLASSES_ROOT, keyPath.data(), KEY_READ); - errorCode != 0) - { - return notAssociated; - } - - std::wstring buf(1024, wchar_t()); - if (const auto errorCode = regKey.GetValue(nullptr, buf.data(), static_cast(buf.capacity()), nullptr); - errorCode != 0) - { - return notAssociated; - } - - buf.resize(::wcsnlen(buf.data(), 1024)); - - return buf; - } - - return notAssociated; -} - -//! ブラウザで開く -bool OpenWithBrowser(HWND hWnd, std::wstring_view url) -{ - if (url.empty()) { - return false; - } - - using namespace Microsoft::WRL; - ComPtr pUri; - DWORD dwFlags = Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES | Uri_CREATE_NO_IE_SETTINGS; - if (const auto hr = ::CreateUri(url.data(), dwFlags, 0, &pUri); - FAILED(hr)) { - _com_error ex(hr); - auto desc = ex.Description(); - TRACE("%s", (const wchar_t*)desc); - return false; - } - - _bstr_t bstrSchemeName; - if (const auto hr = pUri->GetSchemeName(&bstrSchemeName.GetBSTR()); - FAILED(hr)) { - _com_error ex(hr); - auto desc = ex.Description(); - TRACE("%s", (const wchar_t*)desc); - return false; - } - - std::filesystem::path browserPath; - std::wstring_view verb = L"open"; - std::wstring_view file = url.data(); - std::wstring params; - const wchar_t* lpParameters = nullptr; - - // fileプロトコル対策 - if (bstrSchemeName == _bstr_t(L"file")) { - // 実行可能ファイルはダウンロードになるので失敗させる - if (const std::filesystem::path urlPath(url.data()); - ::_wcsicmp(urlPath.extension().c_str(), L".exe") == 0) { - return false; - } - - // HTTPプロトコルに関連付けられたコマンドラインを取得し、パターンマッチでパラメータを組み立てる - // => "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --single-argument %1 - std::wsmatch matched; - std::wregex re(LR"(^("[^"]+"|[^ ]+)\s+(.+))"); - if (auto browserCommandline = GetCommandAssociatedWithProgID(GetProgIdForProtocol(L"http")); - std::regex_search(browserCommandline, matched, re)) { - // $1 ブラウザのパス - std::wstring buf = matched[1]; - buf.erase(std::remove(buf.begin(), buf.end(), L'\"'), buf.cend()); - browserPath = buf.data(); - file = browserPath.c_str(); - // $2 パラメータ - params = std::regex_replace(matched[2].str(), std::wregex(L"%1"), url.data()); - lpParameters = params.c_str(); - } - } - - // If the function succeeds, it returns a value greater than 32. - if (auto hInstance = ::ShellExecuteW(hWnd, verb.data(), file.data(), lpParameters, nullptr, SW_SHOWNORMAL); - hInstance <= (decltype(hInstance))32) { - return false; - } - - return true; -} diff --git a/sakura_core/util/shell.h b/sakura_core/util/shell.h index 8cea219c51..b2f8ce3e14 100644 --- a/sakura_core/util/shell.h +++ b/sakura_core/util/shell.h @@ -31,9 +31,6 @@ #include -#include -#include - BOOL MyWinHelp(HWND hwndCaller, UINT uCommand, DWORD_PTR dwData); /* WinHelp のかわりに HtmlHelp を呼び出す */ // 2006.07.22 ryoji /* Shell Interface系(?) */ @@ -59,11 +56,4 @@ INT_PTR MyPropertySheet( LPPROPSHEETHEADER lppsph ); // 独自拡張プロパテ //!フォント選択ダイアログ BOOL MySelectFont( LOGFONT* plf, INT* piPointSize, HWND hwndDlgOwner, bool ); // 2009.10.01 ryoji ポイントサイズ(1/10ポイント単位)引数追加 - -//! Windows エクスプローラーで開く -bool OpenWithExplorer(HWND hWnd, const std::filesystem::path& path); - -//! ブラウザで開く -bool OpenWithBrowser(HWND hWnd, std::wstring_view url); - #endif /* SAKURA_SHELL_0A8B6454_B007_46E5_9606_8D2FD7993B91_H_ */ diff --git a/sakura_core/view/CEditView.cpp b/sakura_core/view/CEditView.cpp index e4271b8e76..56a4a9fdf4 100644 --- a/sakura_core/view/CEditView.cpp +++ b/sakura_core/view/CEditView.cpp @@ -774,13 +774,6 @@ LRESULT CEditView::DispatchEvent( /* タイマー終了 */ ::KillTimer( GetHwnd(), IDT_ROLLMOUSE ); - // 「URLを開く」処理の完了をチェックして必要があれば待機する - // 開始後、joinされてないstd::threadを破棄すると例外が起きる。 - // ダブルクリックで「URLを開く」をしてない場合、このif文には入らない。 - if (m_threadUrlOpen.joinable()) { - m_threadUrlOpen.join(); - } - // MYTRACE( L" WM_DESTROY\n" ); /* ||子ウィンドウの破棄 diff --git a/sakura_core/view/CEditView.h b/sakura_core/view/CEditView.h index d3ced9be15..8f4cb2457e 100644 --- a/sakura_core/view/CEditView.h +++ b/sakura_core/view/CEditView.h @@ -47,8 +47,6 @@ #include // LPDATAOBJECT #include // HDROP -#include - #include "CTextMetrics.h" #include "CTextDrawer.h" #include "CTextArea.h" @@ -123,8 +121,6 @@ class CEditView , public CMyWnd , public CDocListenerEx { - std::thread m_threadUrlOpen; - public: const CEditDoc* GetDocument() const { diff --git a/sakura_core/view/CEditView_Mouse.cpp b/sakura_core/view/CEditView_Mouse.cpp index 82e7407cc7..84f2e66140 100644 --- a/sakura_core/view/CEditView_Mouse.cpp +++ b/sakura_core/view/CEditView_Mouse.cpp @@ -22,15 +22,9 @@ */ #include "StdAfx.h" -#include "CEditView.h" - +#include // _beginthreadex #include - -#include -#include -#include -#include - +#include "CEditView.h" #include "_main/CAppMode.h" #include "CEditApp.h" #include "CGrepAgent.h" // use CEditApp.h @@ -1537,6 +1531,15 @@ void CEditView::OnLBUTTONUP( WPARAM fwKeys, int xPos , int yPos ) return; } +/* ShellExecuteを呼び出すプロシージャ */ +static unsigned __stdcall ShellExecuteProc( LPVOID lpParameter ) +{ + LPWSTR pszFile = (LPWSTR)lpParameter; + ::ShellExecute( NULL, L"open", pszFile, NULL, NULL, SW_SHOW ); + free( pszFile ); + return 0; +} + // マウス左ボタンダブルクリック // 2007.01.18 kobake IsCurrentPositionURL仕様変更に伴い、処理の書き換え void CEditView::OnLBUTTONDBLCLK( WPARAM fwKeys, int _xPos , int _yPos ) @@ -1580,31 +1583,20 @@ void CEditView::OnLBUTTONDBLCLK( WPARAM fwKeys, int _xPos , int _yPos ) // 2009.05.21 syat UNCパスだと1分以上無応答になることがあるのでスレッド化 CWaitCursor cWaitCursor( GetHwnd() ); // カーソルを砂時計にする - // 前回分の「URLを開く」処理の完了をチェックして必要があれば待機する - if (m_threadUrlOpen.joinable()) { - m_threadUrlOpen.join(); + unsigned int nThreadId; + LPCWSTR szUrl = strOPEN.c_str(); + LPWSTR szUrlDup = _wcsdup( szUrl ); + HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, ShellExecuteProc, (LPVOID)szUrlDup, 0, &nThreadId ); + if( hThread != INVALID_HANDLE_VALUE ){ + // ユーザーのURL起動指示に反応した目印としてちょっとの時間だけ砂時計カーソルを表示しておく + // ShellExecute は即座にエラー終了することがちょくちょくあるので WaitForSingleObject ではなく Sleep を使用(ex.存在しないパスの起動) + // 【補足】いずれの API でも待ちを長め(2~3秒)にするとなぜか Web ブラウザ未起動からの起動が重くなる模様(PCタイプ, XP/Vista, IE/FireFox に関係なく) + ::Sleep(200); + ::CloseHandle(hThread); + }else{ + //スレッド作成失敗 + free( szUrlDup ); } - - // 新規スレッドで「URLを開く」を実行する - // ※初期化完了するまではメインスレッドの実行がブロックされることに注意。 - std::mutex mtx; - std::condition_variable cv; - bool initialized = false; - m_threadUrlOpen = std::thread( [this, strOPEN, &mtx, &cv, &initialized] { - // 初期化 - std::wstring url(strOPEN); - if (!initialized) - { - std::unique_lock lock( mtx ); - initialized = true; - cv.notify_one(); - } - - // 本処理 - OpenWithBrowser( GetHwnd(), url ); - }); - std::unique_lock lock( mtx ); - cv.wait(lock, [&initialized] { return initialized; }); } return; } diff --git a/tests/unittests/Makefile b/tests/unittests/Makefile index 0c0e266915..7d7aa2c58e 100644 --- a/tests/unittests/Makefile +++ b/tests/unittests/Makefile @@ -113,7 +113,6 @@ LIBS= \ -lwinmm \ -lwindowscodecs \ -lmsimg32 \ - -lurlmon \ -lkernel32 \ -lgdi32 \ -lcomdlg32 \