三太子安裝腳本判斷原有 Opera 安裝路徑的瑕疵

43 views
Skip to first unread message

Jedi

unread,
Mar 3, 2010, 4:35:41 AM3/3/10
to Opera Nalakuvara 三太子
這個問題是我原先沒有預期到的,但是有些使用者遇到了──不知道為什麼,某些使用者可能會把 Opera 直接裝在 %ProgramFiles%!更
糟的是連帶的登錄檔也會受到影響,導致未來要再裝 Opera/三太子,也會繼續發生一樣的錯誤,並且可能也因此弄爛 %UserProfile%(我
的天啊)

在目前的三太子安裝/補綴腳本當中,有這一段:

==
; 安裝前先檢查是否有殘留先前的 Opera 檔案
; 從登錄讀取 Opera 的安裝路徑(如果有的話),讀出來的東西會是類似 "PATH\Opera.exe" "%1" 這樣的字串
RegRead, OperaInstallPathReg, HKLM, SOFTWARE\Classes\Opera.HTML\shell
\open\command
; 祇有 PATH 那串有用,所以用正規表示式切出來
OperaInstallPath := RegExReplace(OperaInstallPathReg, ".(.:.+)\\
[Oo]pera\.exe.+$", "$1")
==

這段正規表示式應該是在我還沒找到 AutoHotKey 逸出字元(`)的時候寫出來的,不過這不是重點,重點是如果這邊讀出來的結果是 C:
\Program Files\ 怎麼辦?目前的腳本僅做了「這個讀出來的路徑是否存在」的檢測:

==
IfExist, %OperaInstallPath%
==

然而,C:\Program Files\ 是一定會存在的,接下來就會發生悲劇,像是把 Opera 直接裝到這裡面,最後並且在 HKLM
\SOFTWARE\Classes\Opera.HTML\shell\open\command 寫入 C:
\PROGRA~1\Opera.exe,導致日後相同的慘劇會再次重演。

Jedi

unread,
Mar 3, 2010, 4:43:08 AM3/3/10
to Opera Nalakuvara 三太子
我現在能夠想到的解法是很蠢的設立一組黑名單,像是:
==
C:\Program Files\
C:\Program Files (x86)\
C:\PROGRA~1\
C:\PROGRA~2\
==
或者是直接把讀出來的 %OperaInstallPath% 跟 %ProgramFiles% 一起轉成 8.3 短路徑,看他們是否一樣。
如果吻合了上述的情況,就表示出錯了,就強迫用預設值蓋掉,或者是讓使用者重選,之類的。

Jedi

unread,
Mar 3, 2010, 4:47:44 AM3/3/10
to Opera Nalakuvara 三太子
另一方面,現有的安裝腳本當中,這一段也會有問題:
==
; 用正規表示式從 Opera 安裝路徑當中切出最後一段
OperaInstallPathPart := RegExReplace(OperaInstallPath, ".:\\.+\\(.+)
$", "$1")
==
問題會發生在,如果安裝路徑是例如 C:\OP10 這樣的話,就會切不出東西來。
或許可以改寫成:
==
; 用正規表示式從 Opera 安裝路徑當中切出最後一段
OperaInstallPathPart := RegExReplace(OperaInstallPath, ".+\\(.+)$",
"$1")
==

Jedi

unread,
Apr 3, 2010, 10:20:00 PM4/3/10
to Opera Nalakuvara 三太子
installer.ahk 和 patch.ahk 加入了這一段:

==

AskUserOperaInstallPath:
; 檢查此路徑下是否真的有 opera.exe 存在,否則就把 OperaInstallPath 變數設回空白,以便詢問使用者
IfNotExist, %OperaInstallPath%\opera.exe
OperaInstallPath = ""

if (OperaInstallPath = "") {
; 如果讀不到路徑,纔去詢問使用者
FileSelectFolder, OperaInstallPath, ::{20d04fe0-3aea-1069-
a2d8-08002b30309d}, 0, %SelectOperaPath% %ProgramFiles%\Opera
}
if (OperaInstallPath = "") {
; 如果從登錄讀不到路徑,使用者又沒有設定(按了取消),就用預設值
OperaInstallPath = %ProgramFiles%\Opera
}
; 檢查此路徑下是否真的有 Opera.exe 存在,否則就重新詢問使用者
IfNotExist, %OperaInstallPath%\opera.exe
Goto, AskUserOperaInstallPath

==

另外,在 installer.ahk 裡面,原本的這段:

==
; 如果通通都沒有,就回到正常的安裝步驟
Goto, installopera
==

修改為:

==
; 如果通通都沒有,就清掉顯然有誤的登錄資料,然後回到正常的安裝步驟
RegDelete, HKLM, SOFTWARE\Classes\Opera.HTML
Goto, installopera
==

有空的時候會來測測看這樣能不能避開先前發現的瑕疵。
如果可以的話,下一步就是加入判斷是否有正黑體可用,
(這部份的討論則會在 http://groups.google.com/group/operanalakuvara/browse_thread/thread/e565203ae70d1af9
進行)
然後就可以釋出新的安裝套件/補綴套件 (for 10.10) 了。

Jedi

unread,
Apr 7, 2010, 1:41:11 PM4/7/10
to Opera Nalakuvara 三太子
patch.ahk 可以檢查 %OperaInstallPath%\opera.exe 是否存在,
但是 installer.ahk 這樣做是不行的,因為稍早已經移開(備份)了:
FileMoveDir, %OperaInstallPath%, %APPDATA%\Opera Nalakuvara Backup\
%A_YYYY%%A_MM%%A_DD%\ProgramFiles, 1

所以看是要更早檢查,還是要怎麼樣,唔。

> (這部份的討論則會在http://groups.google.com/group/operanalakuvara/browse_thread/thread/e...

Jedi

unread,
Apr 7, 2010, 1:44:33 PM4/7/10
to Opera Nalakuvara 三太子
發現原來我自己誤解了 orz

installer.ahk 檢查這個的時候,是在 Opera 已經「安裝好」的時候,所以還是沒問題的。

倒是備份前,也還要補上檢查路徑是否與 ProgramFiles 相同。

Jedi

unread,
Apr 7, 2010, 2:06:15 PM4/7/10
to Opera Nalakuvara 三太子
原本是這樣:

==
previousfound:
; 詢問是否要移除所有 Opera 留下來的檔案(移到備份目錄去)
MsgBox, 36, %TitleDelete%, %AskDeleteInstall%
IfMsgBox, No
ExitApp
if (OperaInstallPath = "") {
; 如果讀不到路徑,纔詢問使用者
...


}
if (OperaInstallPath = "") {
; 如果從登錄讀不到路徑,使用者又沒有設定(按了取消),就用預設值

...
}
; 取得 Opera 安裝路徑後,接著先建立備份要用的到目錄 %APPDATA%\Opera Nalakuvara Backup\年月日
....
==

改成這樣:

==
previousfound:
; 詢問是否要移除所有 Opera 留下來的檔案(移到備份目錄去)
MsgBox, 36, %TitleDelete%, %AskDeleteInstall%
IfMsgBox, No
ExitApp

AskUserOperaInstallPathForBackup:
if (OperaInstallPath = "") {
; 如果讀不到路徑,纔詢問使用者
...


}
if (OperaInstallPath = "") {
; 如果從登錄讀不到路徑,使用者又沒有設定(按了取消),就用預設值

...
}
; 如果安裝路徑等於 ProgramFiles 則要求使用者重選
if ( OperaInstallPath = ProgramFiles ) {


FileSelectFolder, OperaInstallPath, ::{20d04fe0-3aea-1069-
a2d8-08002b30309d}, 0, %SelectOperaPath% %ProgramFiles%\Opera

Goto, AskUserOperaInstallPathForBackup
}
; 取得 Opera 安裝路徑後,接著先建立備份要用的到目錄 %APPDATA%\Opera Nalakuvara Backup\年月日
....
==

晚一點來測試看看。

Jedi

unread,
Apr 7, 2010, 3:25:26 PM4/7/10
to Opera Nalakuvara 三太子
除了 ProgramFiles 之外,也應該要禁止把 Opera 裝到下列這些環境變數指向的路徑(當然,裝到裡面的子目錄就沒問題):

AllUsersProfile
AppData
CommonProgramFiles
HomeDrive
SystemDrive
SystemRoot
Temp
UserProfile
WinDir

所以辦法是這樣的,首先指定一個「黑名單」(我是放進 strings.ahk 裡面):

==
; Opera 安裝路徑黑名單
SystemPathCheckList = %AllUsersProfile%,%AppData%,%CommonProgramFiles%,
%HomeDrive%,%ProgramFiles%,%SystemDrive%,%SystemRoot%,%Temp%,
%UserProfile%,%WinDir%
==

請注意項目之間僅有逗號,沒有空格。
然後就可以這樣來檢查:

==
if OperaInstallPath in %SystemPathCheckList%
......
==

不過要注意 if var in list 這樣的寫法,只有下一列會套用,所以無法做很多事,因此目前只好很蠢的這樣寫:

==
; 如果安裝路徑等於任何系統路徑則要求使用者重選
if OperaInstallPath in %SystemPathCheckList%
MsgBox, 16, %TitleError%, %MessageOperaBackupFromPathError%
if OperaInstallPath in %SystemPathCheckList%


FileSelectFolder, OperaInstallPath, ::{20d04fe0-3aea-1069-
a2d8-08002b30309d}, 0, %SelectOperaPath% %ProgramFiles%\Opera

if OperaInstallPath in %SystemPathCheckList%
Goto, AskUserOperaInstallPathForBackup
if (OperaInstallPath = "") {
Goto, AskUserOperaInstallPathForBackup
}
==

希望之後能想到更好的寫法。

Jedi

unread,
Apr 7, 2010, 3:35:50 PM4/7/10
to Opera Nalakuvara 三太子
剛剛發現 if var in %list% 還是可以用 { ... } 的,關鍵是要把 { 放在下一列...

所以就可以精簡成這樣了:

==
; 如果安裝路徑等於任何系統路徑則要求使用者重選
if OperaInstallPath in %SystemPathCheckList%
{
MsgBox, 16, %TitleError%, %MessageOperaBackupFromPathError%

FileSelectFolder, OperaInstallPath, ::{20d04fe0-3aea-1069-
a2d8-08002b30309d}, 0, %SelectOperaPath% %ProgramFiles%\Opera
Goto, AskUserOperaInstallPathForBackup
}

==

Jedi

unread,
Apr 7, 2010, 4:34:48 PM4/7/10
to Opera Nalakuvara 三太子
除了 Opera 本身的安裝路徑外,UserJS 的路徑也應該做同樣的檢查,所以加入了這段:

==
; 檢查指定的使用者 JavaScript 路徑是否安全可用
if UserJSPath in %SystemPathCheckList%,%OperaInstallPath%
{
MsgBox, 16, %TitleError%, %MessageUserJSPathError%
Goto, enableuserjs
}
==

亦即排除各個系統路徑,以及 Opera 本身的路徑(當然,這些路徑內的子目錄則沒有問題)

另外,由於選擇路徑時,如果選擇了磁碟根目錄,AutoHotKey 會自動補上 \,例如 C: 就會變 C:\,
如此就無法與 %HomeDrive% 與 %SystemDrive% 匹配,因此在列出黑名單時,
就要手動把這兩個環境變數後面預先補上 \
即:

==
SystemPathCheckList = %AllUsersProfile%,%AppData%,%CommonProgramFiles%,
%HomeDrive%\,%ProgramFiles%,%SystemDrive%\,%SystemRoot%,%Temp%,
%UserProfile%,%WinDir%
==

Reply all
Reply to author
Forward
0 new messages