什么是未公開函數(shù)?
對于Windows的API函數(shù)調(diào)用相信大家已經(jīng)不會陌生了。API函數(shù)調(diào)用是通過在VB中定義和調(diào)用Windows動態(tài)連接庫中的函數(shù)從而擴展VB程序的功能。API函數(shù)的定義和調(diào)用方法在微軟的開發(fā)工具中都有詳細的說明。
那么什么是“未公開”函數(shù)呢?微軟為了某種目的。對于一些封裝在系統(tǒng)中的函數(shù)沒有在任何開發(fā)文檔提供任何函數(shù)說明和定義。而這些函數(shù)有很多都是很有用的。所幸的是一些有心之人對Windows系統(tǒng)動態(tài)連接庫做了十分詳細的分析,從而將這些未公開函數(shù)公開以供廣大開發(fā)人員共享(我對他們的感激之情就象滔滔江水,綿綿不絕……)
好了,廢話少說,言歸正傳,這里首先向大家介紹的是Windows下未公開的關(guān)閉Windows的函數(shù)。在Windows API函數(shù)中雖然提供了ExitWindowsEx這樣的API函數(shù),但是在有一些程序中我們需要象一些程序安裝完畢那樣提示用戶重新啟動計算機或者不重新啟動計算機?;蛘咭诔绦蛑袕棾鲫P(guān)閉系統(tǒng)對話框。要實現(xiàn)這些功能就要使用Windows未公開函數(shù)了。下面來看程序。
首先建立一個新的工程文件,在工程文件中加入一個Module文件。在Module文件中加入以下代碼:
Option Explicit
Public bIsWinNT As Boolean
'下面就是未公開的函數(shù)定義,注意在Alias之后沒有使用函數(shù)的真正名字
'而是用了函數(shù)編號,這是因為微軟沒有公開函數(shù)名
Declare Function SHRestartSystemMB Lib“shell32"-
Alias “#59"-
(ByVal hOwner As Long, ―
ByVal sExtraPrompt As String,-
ByVal uFlags As Long) As Long
Declare Function SHShutDownDialog Lib “shell32" -
Alias “#60" -
(ByVal YourGuess As Long) As Long
Declare Function GetVersionEx Lib “kernel32" -
Alias“GetVersionExA" -
(lpVersionInformation As OSVERSIONINFO) As Long
Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBuildNumber As Long
dwPlatformId As Long
szCSDVersion As String * 128
End Type
Public Const EWX-LOGOFF = 0
Public Const EWX-SHUTDOWN = 1
Public Const EWX-REBOOT = 2
Public Const EWX-FORCE = 4
Public Const EWX-POWEROFF = 8
Public Const shrsExitNoDefPrompt = 1
Public Const shrsRebootSystem = 2
Const VER-PLATFORM-WIN32s = 0
Const VER-PLATFORM-WIN32-WINDOWS = 1
Const VER-PLATFORM-WIN32-NT = 2
Declare Sub CopyMemory Lib “kernel32"
Alias “RtlMoveMemory" -
?。╬Dest As Any, -
pSource As Any, -
ByVal ByteLen As Long)
Declare Function IsTextUnicode Lib “advapi32"-
(lpBuffer As Any,-
ByVal cb As Long, -
lpi As Long) As Long
Public Const IS-TEXT-UNICODE-ASCII16 = &H1
Public Const IS-TEXT-UNICODE-REVERSE-ASCII16 = &H10
Public Const IS-TEXT-UNICODE-STATISTICS = &H2
Public Const IS-TEXT-UNICODE-REVERSE-STATISTICS = &H20
Public Const IS-TEXT-UNICODE-CONTROLS = &H4
Public Const IS-TEXT-UNICODE-REVERSE-CONTROLS = &H40
Public Const IS-TEXT-UNICODE-SIGNATURE = &H8
Public Const IS-TEXT-UNICODE-REVERSE-SIGNATURE = &H80
Public Const IS-TEXT-UNICODE-ILLEGAL-CHARS = &H100
Public Const IS-TEXT-UNICODE-ODD-LENGTH = &H200
Public Const IS-TEXT-UNICODE-DBCS_LEADBYTE = &H400
Public Const IS-TEXT-UNICODE-NULL-BYTES = &H1000
Public Const IS-TEXT-UNICODE-UNICODE-MASK = &HF
Public Const IS-TEXT-UNICODE-REVERSE-MASK = &HF0
Public Const IS-TEXT-UNICODE-NOT-UNICODE-MASK = &HF00
Public Const IS-TEXT-UNICODE-NOT-ASCII_MASK = &HF000
Public Function IsWinNT() As Boolean
Dim osvi As OSVERSIONINFO
osvi.dwOSVersionInfoSize = Len(osvi)
GetVersionEx osvi
IsWinNT = (osvi.dwPlatformId = VER-PLATFORM-WIN32-NT)
End Function
Public Function CheckString(msg As String) As String
If bIsWinNT Then
CheckString = StrConv(msg, vbUnicode)
Else: CheckString = msg
End If
End Function
Public Function GetStrFromPtr(lpszStr As Long, nBytes As Integer) As String
ReDim ab(nBytes) As Byte
CopyMemory ab(0), ByVal lpszStr, nBytes
GetStrFromPtr = GetStrFromBuffer(StrConv(ab(), vbUnicode))
End Function
Public Function GetStrFromBuffer(szStr As String) As String
If IsUnicodeStr(szStr) Then szStr = StrConv(szStr, vbFromUnicode)
If InStr(szStr, vbNullChar) Then
GetStrFromBuffer = Left$(szStr, InStr(szStr, vbNullChar) - 1)
Else: GetStrFromBuffer = szStr
End If
End Function
Public Function IsUnicodeStr(sBuffer As String) As Boolean
Dim dwRtnFlags As Long
dwRtnFlags = IS-TEXT-UNICODE-UNICODE-MASK
IsUnicodeStr = IsTextUnicode(ByVal sBuffer, Len(sBuffer), dwRtnFlags)
End Function
然后在Form1中加入一個ComboBox控件、兩個CommandButton控件,然后在Form1的代碼窗口中加入以下代碼:
Private Sub Command1_Click()
Call SHShutDownDialog(0)
End Sub
Private Sub Command2_Click()
Dim sPrompt As String
Dim uFlag As Long
Select Case Combo1.ListIndex
Case -1: uFlag = Val(Combo1.Text)
Case 0: uFlag = shrsExitNoDefPrompt
Case 1: uFlag = shrsRebootSystem
End Select
If SHRestartSystemMB(hWnd, sPrompt, uFlag) = vbYes Then
End If
End Sub
Private Sub Form_Load()
bIsWinNT = IsWinNT()
If bIsWinNT Then 'WinNT操作系統(tǒng)
With Combo1
.AddItem “0 - 關(guān)閉程序并以其它用戶身份登陸"
.AddItem “1 - 關(guān)閉計算機"
.AddItem “2 - 重新啟動計算機"
.Text = “"
End With
Else 'Win95/98操作系統(tǒng)
With Combo1
.AddItem“1 - 關(guān)閉計算機"
.AddItem “2 - 重新啟動計算機"
.Text = “"
End With
End If
Command1.Caption = “關(guān)閉系統(tǒng)對話框"
Command2.Caption = “關(guān)閉或重新啟動計算機"
End Sub
運行程序,點擊“關(guān)閉系統(tǒng)對話框”按鈕就可以彈出關(guān)閉系統(tǒng)對話框。在Combo1中選擇關(guān)閉系統(tǒng)、重新啟動或者關(guān)閉程序并以其它用戶身份登陸項再點擊“關(guān)閉或重新啟動計算機”按鈕,系統(tǒng)就會彈出提示對話框提示是否執(zhí)行相應的操作,點擊“是”就可以執(zhí)行了。
Windows下未公開的API函數(shù)還有很多,以后我將會一一向大家介紹。 以上程序在VB6,Windows98,Windows NT4,Windows 2000下運行通過
這次介紹的是如何利用Windows未公開函數(shù)實現(xiàn)系統(tǒng)文件操作監(jiān)視功能。利用該功能可以對Windows下的任何文件操作,包括建立文件、文件夾;刪除文件;改變文件大小等操作都可以紀錄在案。
首先來介紹實現(xiàn)上面操作的兩個未公開函數(shù):SHChangeNotifyRegister和SHChangeNotifyDeregister,SHChangeNotifyRegister函數(shù)的定義如下:
Declare Function SHChangeNotifyRegister Lib “shell32" Alias “#2" _
(ByVal hWnd As Long, _
ByVal uFlags As SHCN_ItemFlags, _
ByVal dwEventID As SHCN_EventIDs,
ByVal uMsg As Long, _
ByVal cItems As Long, _
lpps As PIDLSTRUCT) As Long
其中參數(shù)hWnd指定接受系統(tǒng)通告的窗口句柄,參數(shù)uMsg指定消息值,如果函數(shù)調(diào)用成功,系統(tǒng)就會將hWnd指定的窗口加入到系統(tǒng)通告鏈中,并且返回系統(tǒng)通告句柄。當有建立文件等系統(tǒng)操作發(fā)生時,系統(tǒng)會向hWnd指定的窗口發(fā)送uMsg消息,關(guān)于其它參數(shù),會在下面的程序中說明。函數(shù)SHChangeNotifyDeregister的定義如下:
Declare Function SHChange Notify Deregister Lib“shell32" Alias “#4" _
(ByVal hNotify As Long) As Boolean
其中參數(shù)hNotify指定系統(tǒng)通告的句柄。
下面是操作的具體的VB范例:
首先建立一個新的工程,在Form1中加入一個TextBox控件。在Form1的代碼窗口之中加入以下代碼:
Option Explicit
Private Sub Form_Load()
If SubClass(hWnd) Then '改變Form1的消息處理函數(shù)
If IsIDE Then
Text1.Text = vbCrLf & _
“一個 Windows的文件目錄操作即時監(jiān)視程序," & vbCrLf & “可以監(jiān)視在Explore中的重命名、新建、刪除文" & _
vbCrLf & “件或目錄;改變文件關(guān)聯(lián);插入、取出CD和添加“& vbCrLf & "刪除網(wǎng)絡共享都可以被該程序記錄下來。"
End If
Call SHNotify_Register(hWnd)
Else
Text1 =“系統(tǒng)不支持操作監(jiān)視程序 :-)"
End If
Move Screen.Width - Width, Screen.Height - Height
End Sub
Private Function IsIDE() As Boolean
On Error GoTo Out
Debug.Print 1 / 0
Out:
IsIDE = Err
End Function
Private Sub Form_Unload(Cancel As Integer)
Call SHNotify_Unregister
Call UnSubClass(hWnd)
End Sub
Public Sub NotificationReceipt(wParam As Long, lParam As Long)
Dim sOut As String
Dim shns As SHNOTIFYSTRUCT
Dim sDisplayname1 As String
Dim sDisplayname2 As String
MoveMemory shns, ByVal wParam, Len(shns)
If shns.dwItem1 Then
sDisplayname1 = GetDisplayNameFromPIDL(shns.dwItem1)
End If
If shns.dwItem2 Then
sDisplayname2 = GetDisplayNameFromPIDL(shns.dwItem2)
End If
sOut = SHNotify_ GetEvent Str(sDisplayname1, sDisplayname2, lParam) & vbCrLf
Text1 = Text1 & sOut & vbCrLf
Text1.SelStart = Len(Text1)
End Sub
然后在工程中加入三個模塊(Bas)文件,將三個文件分別保存為mDef.Bas、mShell.Bas、mSub.Bas。在mDef.Bas中加入以下代碼:
'mDef.Bas包含Shell操作的函數(shù)和數(shù)據(jù)類型的定義
Option Explicit
Declare Sub MoveMemory Lib “kernel32" Alias“RtlMoveMemory" (pDest As Any, _
pSource As Any, ByVal dwLength As Long)
Declare Sub CoTaskMemFree Lib “ole32.dll" (ByVal pv As Long)
Public Const MAX_PATH = 260
Public Const NOERROR = 0
'SHGetSpecialFolderLocation獲得某一個特殊的目錄的位置,如果函數(shù)調(diào)用成功返回NOERROR
'或者一個OLE錯誤
Declare Function SHGetSpecialFolderLocation Lib “shell32.dll" _
(ByVal hwndOwner As Long, _
ByVal nFolder As SHSpecialFolderIDs, _
pidl As Long) As Long
Public Enum SHSpecialFolderIDs
'列出所有Windows下特殊文件夾的ID
CSIDL_DESKTOP = &H0
CSIDL_INTERNET = &H1
CSIDL_PROGRAMS = &H2
CSIDL_CONTROLS = &H3
CSIDL_PRINTERS = &H4
CSIDL_PERSONAL = &H5
CSIDL_FAVORITES = &H6
CSIDL_STARTUP = &H7
CSIDL_RECENT = &H8
CSIDL_SENDTO = &H9
CSIDL_BITBUCKET = &HA
CSIDL_STARTMENU = &HB
CSIDL_DESKTOPDIRECTORY = &H10
CSIDL_DRIVES = &H11
CSIDL_NETWORK = &H12
CSIDL_NETHOOD = &H13
CSIDL_FONTS = &H14
CSIDL_TEMPLATES = &H15
CSIDL_COMMON_STARTMENU = &H16
CSIDL_COMMON_PROGRAMS = &H17
CSIDL_COMMON_STARTUP = &H18
CSIDL_COMMON_DESKTOPDIRECTORY = &H19
CSIDL_APPDATA = &H1A
CSIDL_PRINTHOOD = &H1B
CSIDL_ALTSTARTUP = &H1D
CSIDL_COMMON_ALTSTARTUP = &H1E
CSIDL_COMMON_FAVORITES = &H1F
CSIDL_INTERNET_CACHE = &H20
CSIDL_COOKIES = &H21
CSIDL_HISTORY = &H22
End Enum
'SHGetPathFromIDList函數(shù)將一個Item轉(zhuǎn)換為文件路徑
Declare Function SHGetPathFromIDList Lib“shell32.dll" Alias “SHGetPathFromIDListA" _
(ByVal pidl As Long, _
ByVal pszPath As String) As Long
'SHGetFileInfoPidl函數(shù)獲得某個文件對象的信息。
Declare Function SHGetFileInfoPidl Lib “shell32" Alias“SHGetFileInfoA" (ByVal pidl As Long, _
ByVal dwFileAttributes As Long, _
psfib As SHFILEINFOBYTE, _
ByVal cbFileInfo As Long, _
ByVal uFlags As SHGFI_flags) As Long
Public Type SHFILEINFOBYTE
hIcon As Long
iIcon As Long
dwAttributes As Long
szDisplayName(1 To MAX_PATH) As Byte
szTypeName(1 To 80) As Byte
End Type
Declare Function SHGetFileInfo Lib “shell32" Alias “SHGetFileInfoA" _
(ByVal pszPath As String, _
ByVal dwFileAttributes As Long, _
psfi As SHFILEINFO, _
ByVal cbFileInfo As Long, _
ByVal uFlags As SHGFI_flags) As Long
Public Type SHFILEINFO
hIcon As Long
iIcon As Long
dwAttributes As Long
szDisplayName As String * MAX_PATH
szTypeName As String * 80
End Type
Enum SHGFI_flags
SHGFI_LARGEICON = &H0
SHGFI_SMALLICON = &H1
SHGFI_OPENICON = &H2
SHGFI_SHELLICONSIZE = &H4
SHGFI_PIDL = &H8
SHGFI_USEFILEATTRIBUTES = &H10
SHGFI_ICON = &H100
SHGFI_DISPLAYNAME = &H200
SHGFI_TYPENAME = &H400
SHGFI_ATTRIBUTES = &H800
SHGFI_ICONLOCATION = &H1000
SHGFI_EXETYPE = &H2000
SHGFI_SYSICONINDEX = &H4000
SHGFI_LINKOVERLAY = &H8000
SHGFI_SELECTED = &H10000
End Enum
(后續(xù))