大家好,這一次我們要講的是檔案的關聯, 大部份的軟體,通常都會為自己的檔案加上關聯, 原因很簡單,就是方便而已,因此,我也不能免俗的加上了這個功能, 而在其中一些功能上,因為...嗯...偷懶吧(^_^)以及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-手動,
這樣程式就能夠偵測在該物件上拖曳的物件了
這一段的程式很簡單,我就不多說了,其它的部份如果還有問題,歡迎來信討論


Screen Saver Maker教學教室 V1.0補完版 完
Screen Saver Maker Project Close - D.J. Studio,South Wind 2000.11.21
回到VB教學教室