早在Ver0.9推出之時,我就在想,Screen Saver Maker自己使用的話,
還算挺方便的軟體,但是如果把眼光放遠一點呢?
就會發覺,這個軟體缺乏一個很重要的功能-互換性,
螢幕保護程式,雖然只是在自己的螢幕上使用的小程式,
但是,通常大家都會想要將好玩的、有趣的、漂亮的螢幕程式與好朋友分享,
或放在自己的網站上給人下載,
而Screen Saver Maker致命的缺點就在這裡,它所製作出來的SPM、SPC檔,
其實只是一個簡單的檔案索引,指示程式在適當的流程中,
應該去作什麼樣的動作,
但是,這一份檔案索引,並不見得能適用於別人的電腦,
難不成你想要求每一個收到你檔案的人說,
你!就是你!在E磁碟建一個xxx的目錄,再把所有檔案copy進去...
當然,我們不可能要求別人這麼做的,
那麼,我們該怎麼辦?
這就是SPF檔案的由來了,
SPF檔案的原理其實很簡單,
我們先想想看,為了達到互換性的要求,
我們必須要做到什麼樣的功能?
其實我們要的功能很簡單,只有一個,那就是~不論到那一臺電腦,
這一個螢幕保護程式都能執行,
而要達到這個要求,使用者所必須做的步驟,當然,要越少越好囉!
其它方面,我們也必須想到,
當你EMail一個螢幕保護程式給別人時,
那~~~~麼多的檔案,難不成你要使用者一個個的加進去嗎?
嗯~~那可不大好,所以,我們應該想辦法,創造一種規格,
能將所有的檔案cat在一起,最好只有一個檔案,
那麼動作就簡單多了,
整個大略的流程大概就成形了
1.使用者已建立SPM專案檔
2.使用者利用SPF檔案管理將SPM專案檔轉成SPF封包檔
3.另一使用者收到SPF封包檔
4.另一使用者利用SPF檔案管理將SPF封包檔轉換回SPM專案檔
這樣看起來是不是跟傳ZIP檔案給別人的步驟差不多?
我就是從那裡聯想出來這個程序的,其實也沒有什麼大道理
整個SPF檔,其實就是將所有SPM檔須要的檔案cat在一起的一個大檔案,
然後再加上一些必要的資訊集合而成的,
只要懂一些檔案讀寫的技巧,就可以很容易瞭解了,
那麼我們來看一下整個SPF檔案的架構
首先,在SPF的檔頭,照例寫下一些資訊,以做為程式的判別
1.Head Code
40Byte
========================================
This is Screen Saver Maker Package File
接下來兩個Byte是標示檔案的Packet種數
因為我們在製作及解開檔案時,必須要知道每個檔案的長度
才能在檔案cat在一起之後,仍可正確的解開
因此必須有一個判定的方法
而我所使用的方法則是將檔案拆成無數個小封包
而這裡標示的就是這個SPF檔案所使用的封包總數
而從這裡我們可以看得出來,SPF檔的最大限制為65535個封包資料
而每個封包我制定為1024byte(1K)
因此SPF檔的最大容許容量約為65535K(64M)左右
如果你的SPM專案檔所需的檔案如果超過此容量
就無法成功建立了
Total Packet No.
檔案的Package總數
2Byte
====
FFFF
接者是16Byte的空白,為什麼要留下16Byte的空白?
好處可多了~~這是為了以後擴充SPF的功能留下的一段空間
如果想要的話,利用這裡可以做不少事喔!這一點我稍後再說明
Not define
未定義,保留
================
16Byte
前面可以說完全是SPF的一些檔案資訊而已,
開接下來的部份才是要解開的檔案
為了方便程式撰寫
每個封包是設計為1024Byte的格式
但是檔案大小不可能永遠都剛好是1024的倍數
那麼,我們就必須在每個解開封包之前
確定可用資料的Byte數
因此在每一個1024Byte的封包之前,還有兩個Byte的可用資料的長度
而在最前方也有兩個Byte,標明了這一個檔案是用幾個封包組合而成
2.Packet Data Format
Total Packet in this file
目前要解的檔案用了幾個封包資料(只有第一個需要)
2Byte
====
FFFF
Packet Length(Useful Data Length in this Packet)
可用資料的長度
2Byte
====
FFFF
Packet Data
資料內容
1024Byte
============.....=====
0107A324902F.....00000
而在建立起這一些SPM檔的封包資料之時,有一個檔案是最必須優先建立的
那就是所有檔案的明細List檔
否則,就算你的SPF檔建立好了,你也不知道解開時要使用什麼檔名啊!
SPF的大略說明就是這樣子
其它詳細的內容,可以參考當初我放上來的SPF規格表
接下來我們開始來看程式
剛剛我們已經說過了,SPF檔其實只是將檔案cat起來的簡單技巧,因此,
並沒有壓縮檔案的功能,相反的,因為多加了些額外的資訊,
檔案還反而會比原來的大了一點,因此程式裡設計了一個功能,
如果你有安裝winzip的話,在SPF檔製作完成後,
你可以選擇讓程式自動為你呼叫winzip來壓縮SPF封包檔,
而我們就必須檢查出使用者是否有安裝winzip,及查出winzip的執行檔路徑,
來看看這一段程式
Private Sub Form_Load()
ActionType = MAKE_SPF
If IsWinZIP = NOT_DETECT Then Detect_WinZIP
If IsWinZIP = HAVE_WINZIP Then chkUseWinZIP.Enabled = True
End Sub
IsWinZIP是用來判斷是否檢查過WinZIP路徑的布林值
如果檢查出WinZIP的存在,就將自動呼叫WinZIP的控制項致能(Enabled=True)
而至於檢查的方法我們來看看Detect_WinZIP這一段副程式
Private Sub Detect_WinZIP()
Dim hkey As Long
Dim sLen As Long
檢查的方法其實很簡單,如果WinZIP如果存在的話,
你應該會在HKEY_CLASSES_ROOT=\WinZip\shell\open\command這個SubKey中
查到WinZIP的執行路徑
再經過一些檔案的確認動作
就可以得知WinZIP的執行檔路徑了
不過有一點要提醒的
其實我的動作有點偷工減料
正確的步驟應該先搜尋.zip是否有被關聯
再依據.zip取得的值一路追回去才對
不過,WinZIP的登錄路徑基本上似乎是沒有改變過
所以就稍稍偷工減料了
但是該了解的還是要了解才行喔!
RegOpenKey HKEY_CLASSES_ROOT, "WinZip\shell\open\command", hkey
RegQueryValueEx hkey, "", 0, REG_SZ, ByVal vbNullString, sLen
WinZIPCommand = String(sLen, Chr(0))
RegQueryValueEx hkey, "", 0, REG_SZ, ByVal WinZIPCommand, sLen
RegCloseKey hkey
If WinZIPCommand <> "" Then
WinZIPCommand = Left(WinZIPCommand, InStr(WinZIPCommand, " ") - 1)
If Dir(WinZIPCommand) <> "" Then
IsWinZIP = HAVE_WINZIP
Else
IsWinZIP = NO_WINZIP
End If
Else
IsWinZIP = NO_WINZIP
End If
End Sub
接者便是等待使用者指定要做的動作,然後做壓解檔的動作,
這裡有用到ActionType的變數來判斷使用者的動作,當使用者按下cmdOK時,
再依據Caption及這個變數來判斷要執行的步驟為何?這邊就比較沒有什麼好講的了,
主要步驟就是
製作->呼叫副程式製作SPF檔->製作完成,確定
解開->指定解開路徑,確定解開->呼叫副程式解開SPF檔->完成,確定
就是這樣而已,主要的工作都是在MakeSPFFile及UnPackSPFFile這兩個副程式,
我們就來分析一下MakeSPFFile
Private Sub MakeSPFFile(SPMFile As String)
'略
On Error GoTo MakeSPFError
'Get Current Path & SPM FileName,if SPM file exist,ask user delete?
首先我們先找出要建立的SPM檔的正確完整路徑,然後,Check SPF的檔案是否已經
存在,如果已經存在,記得詢問使用者是否確定要覆蓋原檔
'略
'Get a temp file name for SPM
接下來要建立一個暫存檔
用來存放要建立在SPF檔中的SPM檔
'略
txtStatus.Text = "開始解析" & SPMFile & vbCrLf
DoEvents
fNum = FreeFile
Open readFile For Input As #fNum
fNum2 = FreeFile
Open tmpSPMFile For Output As #fNum2
'Check Head Data
撿查SPM檔的檔頭
'略
totalFileNo = 0
txtStatus.Text = txtStatus.Text & "處理中"
DoEvents
ReDim SPM_DATA(1 To 301) As String
'SPM File Data Array (MAX file in SPM 100*3+1 (wav,mid and picture + tmpfile))
建立一個陣列存放要用到的檔案資訊
一個SPM專案檔,最多可以設定100張圖片,而每一個圖片設定,最多
可能會包含有Wave,Midi及圖片本身三個檔案,加上SPM專案檔
因此我們最多會需要用到100*3+1個檔案
接下來就要讀取SPM檔的資料寫到暫存檔中
在檔案資訊方面,我將路徑方面的資料都拿掉了,
因為到時候你在解SPF檔的時候,這個路徑根本不能使用,
因此我們只要寫下檔名就可以了
然後我們再把要加入SPF檔的檔名存到SPM_DATA這個陣列中
Do Until EOF(fNum)
Line Input #fNum, rBuf$
Print #fNum2, rBuf
For i = 1 To 3
'略
Next i
For i = 1 To 4
'略
Next i
'Nothing,Just show process
'略
Loop
SPM_DATA(totalFileNo + 1) = tmpSPMFile
Close #fNum
Close #fNum2
'If no file,stop handle
假如沒有任何檔案?那還要做什麼?離開吧!
If totalFileNo = 0 Then
txtStatus.Text = txtStatus.Text & "程式強制中斷,沒有找到任何需要處理的檔案"
Exit Sub
End If
txtStatus.Text = txtStatus.Text & vbCrLf
'Create a temp directory
接下來要準備將檔案製作成SPF的檔案格式了
我們設立一個暫存目錄,避免與其它檔案發生衝突
'略
txtStatus.Text = txtStatus.Text & "開始壓縮作業"
DoEvents
ReDim SPF_DATA(0 To totalFileNo + 1) As String
'SPF file data array (ini file+file of SPM +list file)
SPF_DATA(0) = "scrpack.ini"
在SPF檔案中,第一個放的一定是檔案總表,記載所有要解開的檔名
不然的話,你就不知道要將解開來的檔案取什麼名字囉!
接下來的算是硬功夫,將用到的檔案一個一個寫下來存到暫存檔中,
請自己參考相關書籍
For i = 1 To totalFileNo + 1
'略
Next i
txtStatus.Text = txtStatus.Text & vbCrLf
txtStatus.Text = txtStatus.Text & "壓縮結束,建立List資料檔" & vbCrLf
DoEvents
'Create scrpack.ini,write filename information in file,and create 1024 format packet file
建立List檔,並製作成1024Byte格式的封包檔
'略
txtStatus.Text = txtStatus.Text & "建立List資料檔成功,壓縮資料檔"
DoEvents
fName = tmpPath & "SPF000.tmp"
readFile = tmpPath$ & "scrpack.ini"
j = FileLen(readFile) Mod 1024
If j = 0 Then
PackTime = FileLen(readFile) \ 1024
FileSize = 1024
Else
PackTime = (FileLen(readFile) \ 1024) + 1
FileSize = j
End If
totalPacketNo = totalPacketNo + PackTime
'if total packet no >65535,it can't write in head(more then 2bytes),so we need stop handle.
'before we quit subscript,delete temp file,directory
If totalPacketNo > 65535 Then
MsgBox "檔案容量超過最大限制(64M),程式強制中斷!", vbOKOnly Or vbExclamation
txtStatus.Text = txtStatus.Text & vbCrLf & "刪除暫存檔"
DoEvents
Kill tmpPath & "*.*"
Kill tmpSPMFile
txtStatus.Text = txtStatus.Text & vbCrLf & "刪除暫存目錄"
DoEvents
RmDir tmpPath
txtStatus.Text = txtStatus.Text & vbCrLf & "結束"
Exit Sub
End If
'Create list file's packet file
'略
前置作業大概就到此為止了,該知道的資訊都讀出來了,
暫存檔也都做好了,確定一下封包數量有沒有超過最大限制
就可以把檔案Cat起來了
txtStatus.Text = txtStatus.Text & vbCrLf & "建立List資料檔成功," & vbCrLf & "開始建立SPF資料檔案"
'if SPF file exist,delete it
假如已經SPF檔存在,記得將它砍掉
fName$ = pathBuf$ & Left$(SPMFile, InStrRev(SPMFile, ".")) & "SPF"
If Dir(fName$) <> "" Then Kill fName$
DoEvents
開始製作SPF封包檔
將檔頭等資訊寫入,再將所有的暫存檔一個個cat起來
這樣就行了
'略
'Check Use Winzip,If Used,Call WinZip & Make SPZ File
如果使用者有勾選呼叫WinZIP的話,就幫它呼叫WinZIP來壓縮檔案
If chkUseWinZIP.Value = vbChecked Then Call CallWinZIP(fName)
'create over.delete temp file and directory
建立完成囉!記得將剛剛建立的暫存檔及目錄清乾淨
'略
Exit Sub
'when something error,remember close fileNo
當發生錯誤時,記得將檔案關閉,並將暫存檔刪除喔!
MakeSPFError:
MsgBox "製做SPF檔發生錯誤!請重新檢查你的檔案是否存在,或者有所毀損", vbOKOnly Or vbExclamation
Close #fNum
Close #fNum2
Kill tmpPath & "*.*"
Kill tmpSPMFile
RmDir tmpPath
Resume QuitMakeError
QuitMakeError:
Exit Sub
End Sub
接下來解檔的動作就沒有什麼了,只要等使用者指定了SPF檔,
做相對應的壓解檔動作就行了,這其中的動作算是死工夫,
只要了解binary的讀寫方式,就沒有什麼好講的了
這一部份就不多講了,程式都有相關註解,應該不難懂的,
最後要再提的是,關於那空白的16Byte,這個16Byte可做的東西可多了,
例如,密碼功能,
你可以定下一個密碼寫在這裡,讓使用者必須輸入密碼才能解開檔案
又或者,你認為64M的SPF檔案不夠用?想讓使用者有更多的選擇?
那麼你可以拿兩個Byte來設定每一個封包的大小,只要設成2048,你就
多了一個最大128M的SPF檔案了(當然,程式還是得稍做修改就是了),
又或者,你想用磁片傳給別人,SPF檔又太大?
將SPF的極限設成1.4M(約1000個封包左右),再設定一個檔案序號,做出.SP0,.SP1,.SP2
的多個SPF檔也是可能的,
要怎麼做,能怎麼做,只看你自己的創造力了
這一次的教學教室就到此為止,下次見囉!
|