Web前端如何啟動本地可執行檔案

語言: CN / TW / HK

如果在使用者本地電腦上有個exe可執行檔案,不能修改這個可執行檔案本身,想在瀏覽器中通過點選按鈕,呼叫這個exe檔案,Web前端可以做到麼?

由於瀏覽器的安全限制,是不允許直接呼叫exe檔案的。但是有時候非要實現這種需求,因此只能用一些折中的方法。

  • 方法1 登錄檔協議法
    方法通用且簡單,但是經過測試只有FireFox瀏覽器支援,Chrome瀏覽器禁用這個請求。
  • 方法2 本地監聽法
    自己寫一個小的服務端在本地一直監聽請求。
  • 方法3 IE有自己的呼叫方法

下面對每個方法分別進行介紹。

方法1 登錄檔協議法

這個方法的步驟是:

  1. 新建一個登錄檔檔案,裡面描述一個新協議,這個協議的動作是:當訪問這個協議時,開啟一個可執行檔案。
  2. 前端點選時,訪問這個協議的連結,就會呼叫可執行檔案。
    比如我們需要開啟的檔案位置在:e:/abc/needOpen/needOpen.exe
    做新設立一個協議叫做newopenprotocol,則編寫登錄檔檔案如下:

    Windows Registry Editor Version 5.00

    [HKEY_CLASSES_ROOT\newopenprotocol] @="URL:newopenprotocol Protocol" "URL Protocol"=""

    [HKEY_CLASSES_ROOT\newopenprotocol\DefaultIcon] @="cmd.exe,1"

    [HKEY_CLASSES_ROOT\newopenprotocol\shell]

    [HKEY_CLASSES_ROOT\newopenprotocol\shell\open]

    [HKEY_CLASSES_ROOT\newopenprotocol\shell\open\command] @="cmd /k e: && cd e:/abc/needOpen && needOpen.exe"

儲存這個登錄檔檔案,字尾名是.reg。點選執行這個檔案,協議就被寫入登錄檔了。

然後前端訪問這個協議連結,各種方式都可以:

// HTML
<a href="newopenprotocol://test">點選執行exe</a>
// js
window.open("newopenprotocol://test");

甚至在瀏覽器直接訪問這個連結也行。

經測試,火狐瀏覽器開啟時會有瀏覽器的提示框。

注意:

  1. 協議後面的test目前並沒有什麼用處。這個方法由於谷歌瀏覽器不能使用,因此我也沒有繼續研究下去。有興趣的同學可以研究一下協議後面的文字是否可以作為引數傳遞給可執行檔案。
  2. 讓使用者自己編輯登錄檔檔案寫入可執行檔案路徑有點不現實。可以寫一個windows指令碼檔案與可執行檔案在同一路徑,一起分發給使用者。windows指令碼動態生成登錄檔檔案,並且自動寫入登錄檔。詳細在後面介紹。

這個方法來源於網路部落格:谷歌瀏覽器chrome呼叫cmd命令 雖然文章名字包含:“谷歌瀏覽器chrome”,但是經過我實際測試,只有火狐瀏覽器支援這個功能。可能是谷歌瀏覽器的舊版本支援,但是新版本限制了。

方法2 本地監聽法

可以自己開發一個小的可執行程式,監聽前端發的web請求。收到請求後,我們自己編寫的可執行程式啟動本地的可執行檔案即可。想要啟動本地可執行檔案的關鍵就是本地有一個小服務端,我們通過本地網路與服務端通訊,服務端負責啟動可執行檔案。這種方法對於任何瀏覽器都相容,但是需要使用者額外安裝程式。這個程式需要常駐電腦後臺。

不過,前端請求localhost本地依然會發生跨域。但這時候可以用一些常見的方式來規避跨域請求,相對更容易。如果這種需求較大,可以做一個通用的工具。我這邊正好有這種其他人開發的類似工具(非開源),因此可以直接使用。
當然,如果這個可執行檔案可以適配開發,直接讓可執行檔案本身提供服務端功能即可。

方法3 IE有自己的呼叫方法

IE瀏覽器下有自己的呼叫程式的方法,但是IE瀏覽器已經逐漸被淘汰,因此本文不涉及相關內容,感興趣可以上網自行搜尋。

用Windows指令碼自動生成並登錄檔檔案並寫入

上面我們提到,由於可執行程式安裝的位置不同,因此登錄檔也不同。但是讓使用者自己編輯登錄檔肯定不現實,容易出錯又不安全。因此我們可以寫一個windows指令碼,自動生成登錄檔檔案並寫入。假設我們需要寫的登錄檔檔案類似這樣:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\XXXX\YYYY]
"needOpen"="E:\\abc\\needOpen\\needOpen.exe"

注意登錄檔檔案的路徑必須用兩個反斜槓。同樣字尾名是.reg,點選可執行。在系統搜尋“登錄檔編輯器”,輸入路徑(這個路徑是我瞎編的)HKEY_CURRENT_USER\Software\XXXX\YYYY可以檢查是否正確寫入登錄檔。登錄檔編輯器可以手動新增/刪除登錄檔,除錯指令碼的時候會用到。

windows指令碼檔案字尾名是.bat。指令碼檔案如下:

@echo off
echo Windows Registry Editor Version 5.00> regi.reg
:: echo=是輸出空行
echo=>> regi.reg
echo [HKEY_CURRENT_USER\Software\XXXX\YYYY]>> regi.reg
:: 雙引號符號需要用^轉義
set a=^"needOpen^"=^"
:: 登錄檔寫入路徑需要兩個反斜槓號\\
set c=\\needOpen.exe^"
:: chdir是獲取當前路徑,結果儲存在變數b中
for /F %%i in ('chdir') do (set b=%%i)
:: 替換變數b中的單個反斜槓為兩個反斜槓
set bb=%b:\=\\%
:: 三個字串在同一行輸出
echo %a%%bb%%c% >> regi.reg
echo=>> regi.reg
:: 執行登錄檔檔案
regi.reg

':: '代表這一行是註釋。我寫的註釋基本上說的很清楚了。這個指令碼需要與可執行檔案在同一路徑,壓縮後一起分發給使用者。使用者收到後,解壓縮到合適的位置,執行這個指令碼檔案,可能需要管理員許可權。

瀏覽器行為的思考

為什麼前端啟動可執行檔案這麼困難?因為這有較高的安全風險。我們的前端程式碼本身是執行在瀏覽器中的,收到瀏覽器制約,不能直接影響電腦環境本身。但本地可執行檔案的許可權是非常大的,是如果前端程式碼可以隨便啟用電腦上的可執行檔案,那麼就可以直接操控電腦了。如果是惡意的前端程式碼,可以給使用者電腦造成嚴重的破壞。因此,瀏覽器會傾向於限制前端啟動可執行檔案的能力。希望前端程式碼僅限制在瀏覽器中活動。即使目前採用的方法,也有被限制的風險。在高版本的谷歌瀏覽器中,即使請求本地的圖片也會有跨域限制。

因此隨著後續瀏覽器安全功能的完善,前端想要啟動本地可執行檔案,可能會越來越難的。