大家好,這一次我們要講的是檔案的關聯,
大部份的軟體,通常都會為自己的檔案加上關聯,
原因很簡單,就是方便而已,因此,我也不能免俗的加上了這個功能,
而在其中一些功能上,因為...嗯...偷懶吧(^_^)以及VB先天上的限制,
我使用了一些小撇步,並不是很正統的方式(至少書上沒看到這種方法...),
看看就好,有需要還是研究一下正常一點的方法好...嗯~廢話不多說,
開始看看程式吧!
所謂的檔案關聯,其實非常的簡單,只需要在登錄檔寫下一些資訊就好了,
登錄的步驟大概像下面這樣子...
1.將要登錄的附檔名類別登錄在HKEY_CLASS_ROOT中(例如.SPC),設定一個檔案型別的值(例如ScrSPCFile)
2.將檔案型別登錄在HKEY_CLASS_ROOT,設定其對應動作的值,而在這裡,檔案型別
有幾個固定的SubKey,第一個是DefaultIcon,這個是指定該檔案所顯示的Icon圖示來源,
第二個則是shell/open/commend,當你對檔案做了雙擊的動作時,Windows就會依者該檔的登錄值一路
追到這裡,從commend的Key值讀取出要執行的檔名路徑以及呼叫的方式,
大多數的檔案都是”執行檔名 %1”,這裡的%1指得就是你所雙擊的檔案名
那麼,我們就來看看程式是怎麼寫的,請參考程式frmScrSetUP的RegSPM_Click()
Private Sub RegSPM_Click()
Dim hkey As Long
Dim tmpName As String
Dim ShortName As String
Dim ExeName As String
Dim IconName As String
If MsgBox(略, vbQuestion Or vbYesNo, Me.Caption) = vbYes Then
tmpName = workPath & "ScrMaker.exe"
ShortName = String(LenB(tmpName), Chr$(0))
GetShortPathName tmpName, ShortName, Len(ShortName)
ExeName = Left(ShortName, InStr(ShortName, Chr(0)) - 1) & " %1"
IconName = Left$(ShortName, InStr(ShortName, Chr(0)) - 1) & ",1"
首先我們先取得程式的完整執行路徑及檔名,
然後就可以得知執行的完整語法,而IconName
則是指定該檔案的Icon,我將Icon編進資源檔中,製成Exe檔時
就會將其包含在其檔案中,在這裡,利用"執行檔名,n",Windows就會將
其Icon指定成該檔案的第N個Icon圖示,如果不確定自己的執行檔到底包
含了那些Icon以及其順序,可以隨便在桌面建立一個捷徑,
再利用內容-變更圖示-瀏覽,來得知執行檔有包含那一些Icon
接下的步驟就沒什麼了,把相關的登錄寫一寫就可以了
有時候,當你修改完成,並不一定會馬上反應到Window的環境裡
(最常見的就是Icon並沒有更換)
這時候建議你重開機一次,這樣子就可以了
RegOpenKey HKEY_CLASSES_ROOT, "", hkey
'建立subkey .spm
RegSetValue hkey, ".SPM", REG_SZ, "ScrSPMFile", 8
'建立subkey SPMFile
RegSetValue hkey, "ScrSPMFile", REG_SZ, "ScrMaker專案檔", 15
'建立subkey SPMFile\shell 將 open 動作設為預設值
RegSetValue hkey, "ScrSPMFile\shell", REG_SZ, "open", 5
'建立subkey SPMFile\shell\open\command (開啟檔案)
RegSetValue hkey, "ScrSPMFile\shell\open\command", REG_SZ, ExeName, LenB(StrConv(ExeName, vbFromUnicode)) + 1
'建立subkey SPMFile\DefaultIcon (SPM檔案的Icon)
RegSetValue hkey, "ScrSPMFile\DefaultIcon", REG_SZ, IconName, LenB(StrConv(IconName, vbFromUnicode)) + 1
RegCloseKey hkey
MsgBox "設定完成!!", vbOKOnly Or vbInformation, Me.Caption
End If
End Sub
但~~~,登錄完成就好了嗎?當然不是這樣子囉!我們還得做相關的處理呢!
在登錄檔裡,我們在雙擊的處理寫的清清楚楚的-"執行檔名 %1",接下來該做什麼動作,
還是得自己處理的~~~
我們在轉回頭看最前面的Sub Main()處理Command參數的部份,為了不讓程式重覆執行的原因,
所以Sub Main()有兩段處理Command參數的程序,而在程式是否已存在的情況下,
開檔也會有兩種不同的因應方式,關於這一點,稍後會提到,我們先看第二段的處理,也就是
目前還沒有開啟過Screen Saver Maker的情況
Public Sub Main()
'Get WorkPath
略
'Check Program Run Again or Open Program File
略
'Get Windows Directory & System Directory
略
'Check wave type
略
'Check Command Word
Select Case Left$(Command$, 2)
Case "/C", "/c", ""
略
Case Else
這裡就是判斷的部份,我們只要判斷傳進來的參數
是不是Screen Saver Maker的專案檔,如果是,就執行開檔的程序
我們只要判斷最後的幾個Byte
就可以知道要開的是不是Screen Saver Maker的檔案了
在下面的執行程序中,你可以看到,我判斷每一種專案檔都用了
兩個判別式,這裡這麼做的原因是因為,除了雙擊檔案外,
在某些情況(例如當使用者未關聯該檔案,但他雙擊該檔並指定
Screen Saver Maker為開檔程式。又或者,使用者直接拖曳專案檔到
執行檔案上),帶進來的Command參數不一定是ExeName %1,
而有可能會是"ExeName %1",會包含兩個雙引號,
所以在解析Command時要特別的注意
確定開啟的是專案檔後,我會將檔名儲存在HyperLinkOpenFile裡
然後叫出frmScrSetUP這個設定視窗,frmScrSetUP在載入時便會檢查這個值,
然後做對應的處理動作
If UCase$(Right$(Command$, 4)) = ".SPM" Then
HyperLinkOpenFile = Command$
frmScrSetUP.Show
ElseIf UCase$(Right$(Command$, 5)) = ".SPM" & """" Then
HyperLinkOpenFile = StrConv(MidB$(StrConv(Command$, vbFromUnicode), 2, LenB(StrConv(Command$, vbFromUnicode)) - 2), vbUnicode)
frmScrSetUP.Show
ElseIf UCase$(Right$(Command$, 4)) = ".SPC" Then
HyperLinkOpenFile = Command$
frmScrSetUP.Show
ElseIf UCase$(Right$(Command$, 5)) = ".SPC" & """" Then
HyperLinkOpenFile = StrConv(MidB$(StrConv(Command$, vbFromUnicode), 2, LenB(StrConv(Command$, vbFromUnicode)) - 2), vbUnicode)
frmScrSetUP.Show
ElseIf UCase$(Right$(Command$, 4)) = ".SPF" Then
HyperLinkOpenFile = Command$
frmScrSetUP.Show
ElseIf UCase$(Right$(Command$, 5)) = ".SPF" & """" Then
HyperLinkOpenFile = StrConv(MidB$(StrConv(Command$, vbFromUnicode), 2, LenB(StrConv(Command$, vbFromUnicode)) - 2), vbUnicode)
frmScrSetUP.Show
Else
frmScrSetUP.Show
End If
End Select
End Sub
接者我們就來看frmScrSetUP怎麼處理,請看frmScrSetUP Form_Activate的部份
Private Sub Form_Activate()
這裡要做的其實非常的簡單,只要判斷HyperLinkOpenFile是否是空值
如果不是,就是要開專案檔,再依據檔案類別做相關的動作
SPM專案檔的開檔動作很單純,就像開啟舊檔一樣
載入專案的資料,再將一些初始值設定好就可以了
而SPC以及SPF這兩個專案檔,因為要先開啟相關的Form,
所以我會將專案檔的值設定到lblLoadFile.Caption中,
當Form載入時,會啟動一個Timer來檢查,
檢查到lblLoadFile.Caption有值的時候再把它打開,
要小心的是,Form_Activate在其它的設定視窗關閉,
取回控制權時,還會再觸發一次,因此要記得把HyperLinkOpenFile的值清空
才不會重覆執行。
另外,在呼叫其它設定視窗SPC或SPF開啟專案檔時,
因為要考慮到Screen Saver Maker已開啟的狀況,
設定視窗可能已經開啟,正在處理檔案,例如,SPF檔製作中等情況,
必須記得設一個變數什麼的來Check,確定不會有問題才能將專案檔打開
這一段請自行參考frmSPFManager及frmAdvSetUP的tmpDetect_Timer的部份
If HyperLinkOpenFile <> "" Then
Select Case UCase$(Right$(HyperLinkOpenFile, 3))
Case "SPM"
Call LoadProFileData(HyperLinkOpenFile)
lstAddData.ListIndex = 0
picName = lstAddData.List(0)
EffectBuffer = cmbEffect.ListIndex
Call Picture_PreView
Call SetControlEnabled(True)
SetControlFlag = True
SetProFileNo = 1
Call LoadProFileSet("ProFile")
ProFileUpdate = False
LoadFileUpdate = False
Case "SPC"
lblLoadFile.Caption = HyperLinkOpenFile
HyperLinkOpenFile = ""
frmAdvSetUP.Show 1
Case "SPF"
lblLoadFile.Caption = HyperLinkOpenFile
HyperLinkOpenFile = ""
frmSPFManager.Show 1
End Select
End If
End Sub
接下來,我們在回過頭來看第二種情況,當Screen Saver Maker已經執行時,
我們該如何因應。其中需要處理的只有一點,那就是,我要如何將開檔的要求
傳給正在執行中的視窗,只要解決這一點,一切就好解決了。
那要如何將訊息傳給正在執行的Screen Saver Maker呢?
書上提了很多的方法,我先列出來給各位看看
1.ClipBoard(剪貼簿)
2.DDE
3.SendMessage
而剪貼簿因為是Windows所有程式所共用的資源,在資料傳遞上並不保險,
因此實用性不高,不予以考慮,而DDE的方法呢?因為我們並不是兩個不
同的程式再傳遞訊息資料,就我看到的資料而言,似乎不能應用在這裡,
最後的第三點-SendMessage,這可以說是最好的方法了,
它可以直接以傳遞WM_COPYDATA訊息的方式傳遞訊息給目標視窗,
但是...,VB不能用......!!詳情可以參考王國榮的Windows API講座,
這是因為VB本身的限制,所以我也沒有辦法....
最後我採取的方法是...INI檔,我將開檔要求的檔名記錄在INI檔中,
而執行中的視窗則不斷的去檢查,如此一來,只要一檢查到資料更新,
就能做出相對應的措施了
那麼,我們再回到Sub Main看第一段程式
Public Sub Main()
'Get WorkPath
'略
'Check Program Run Again or Open Program File
Select Case Left$(Command$, 2)
Case "/C", "/c", ""
Case Else
Dim hwnd As Long
hwnd = FindWindow(vbNullString, "ScreenSaver Maker")
If hwnd <> 0 Then
經過剛剛的說明,大家應該就可以了解這邊在做什麼了,
只要檢查到程式重覆執行,而又是做開啟專案檔的動作時
我們就將開檔的檔名寫到ADVSET.INI這個檔案中
然後將focus設定到已執行視窗,再將程式關閉即可
If UCase$(Right$(Command$, 4)) = ".SPM" Then
HyperLinkOpenFile = Command$
WriteStringToIni "TEMP", "OPENFILE", HyperLinkOpenFile, workPath & "ADVSET.INI"
ShowWindow hwnd, 1
SetForegroundWindow hwnd
ElseIf UCase$(Right$(Command$, 5)) = ".SPM" & """" Then
''略
End If
End
End If
If App.PrevInstance = True Then End
End Select
接者我們再回到frmScrSetUP看看程式如何檢查,
Private Sub tmrDetectFile_Timer()
tmrDetectFile.Enabled = False
檢查INI檔的資料,如果檔案內容不為空值,就代表有開啟專案檔的要求,
我們就必需做開檔的處理,再這之前,記得將INI檔的內容清除,
下一次Timer跑起來時才不會又跑一次相同的程序
再這邊,開檔的方式其實和剛才在frmScrSetUP的Form_Activate的處理原理並無不同
只不過,現在處理的情形是程式已執行的情況,你並無法保證,目前視窗的Focus在那裡,
基本上來講,SPM檔最好只在frmScrSetUP取得Focus,而開啟SPC或SPF檔,則最好是在
該專案檔的設定視窗或frmScrSetUP取得Focus的情況下來做開檔的處理會比較好,
其它情形我們則不做處理,只Show出一段Message,以免發生不可預期的狀況
因此你們可以看到我做了一段檢查Screen.ActiveFrom.Name
就是這個目的
tmpOpenFile = GetStringFromIni("TEMP", "OPENFILE", "", workPath$ & "ADVSET.INI")
If tmpOpenFile <> "" Then
WriteStringToIni "TEMP", "OPENFILE", "", workPath & "ADVSET.INI"
Select Case UCase$(Right$(tmpOpenFile, 3))
Case "SPM"
If Screen.ActiveForm.Name = Me.Name Then
Call OLELoadFile(tmpOpenFile)
Else
MsgBox "目前程式無法為您開啟SPM檔案,請先關閉『" & Screen.ActiveForm.Caption & "』視窗,再開啟檔案", vbOKOnly, Screen.ActiveForm.Caption
End If
Case "SPC"
If Screen.ActiveForm.Name = Me.Name Then
lblLoadFile.Caption = tmpOpenFile
frmAdvSetUP.Show 1
ElseIf Screen.ActiveForm.Caption = ADVSETUP_CAPTION Then
lblLoadFile.Caption = tmpOpenFile
Else
MsgBox "目前程式無法為您開啟SPC檔案,請先關閉『" & Screen.ActiveForm.Caption & "』視窗,再開啟檔案", vbOKOnly, Screen.ActiveForm.Caption
End If
Case "SPF"
If Screen.ActiveForm.Name = Me.Name Then
lblLoadFile.Caption = tmpOpenFile
frmSPFManager.Show 1
ElseIf Screen.ActiveForm.Caption = SPFMANAGER_CAPTION Then
lblLoadFile.Caption = tmpOpenFile
Else
MsgBox "目前程式無法為您開啟SPF檔案,請先關閉『" & Screen.ActiveForm.Caption & "』視窗,再開啟檔案", vbOKOnly, Screen.ActiveForm.Caption
End If
End Select
End If
tmrDetectFile.Enabled = True
End Sub
關聯的處理大致上就是這樣子了,最後我們要講一下另一種開檔的方式,
"拖曳",這種方法是說,當你設定視窗已開啟時,我們可以將專案檔拖到
設定視窗上,這時候,你會看到滑鼠游標會多了一個加號
(之前的版本會出現禁止的符號,不會有任何作用)
當滑鼠放開時,就會引發OLDDragDrop的事件
而我們就可以從Data.Files(1)取得該檔檔名,再做開檔的動作,
要達到這種功能非常的簡單,只要將物件的OLEDropMode設為1-手動,
這樣程式就能夠偵測在該物件上拖曳的物件了
這一段的程式很簡單,我就不多說了,其它的部份如果還有問題,歡迎來信討論
|