使用 .NET 架構類替代 API 呼叫 (一)

來源:互聯網
上載者:User
使用 .NET 架構類替代 API 呼叫
升級到 Microsoft .NET
Ken Getz
MCW Technologies
2002 年 2 月

摘要:通過學習 Microsoft .NET 架構中某些特定而有用的類,可以減少您對 Win32 API 呼叫的依賴。本文討論的每個類都可以代替一個或多個 Win32 API 呼叫,而在 Microsoft Visual Basic 6.0 中,您必須調用一個或多個 Win32 API 才能完成相同的任務。

目標

  • 尋找現有 Win32 API 呼叫的特定替代品。
  • 瞭解 Registry 類。
  • 使用 FileVersionInfo 類。
  • 使用環境資訊和系統資訊。

目錄

  • 避免使用 Win32 API
  • 使用註冊表
  • 使用常用對話方塊
  • 檢索檔案版本資訊
  • 檢索環境資訊
  • 總結
避免使用 Win32 API
如果您是一位 Microsoft Visual Basic® 6.0 開發人員,您就無法避免調用 Win32 API。開發人員有太多的任務需要完成,而 Visual Basic 卻不能提供任何實現方法。例如,在 Visual Basic 6.0 中,您很難完成以下任務:
  • 確定檔案版本資訊。
  • 在註冊表的任何位置進行讀取和寫入操作。
  • 確定使用者的特定檔案夾,例如 Microsoft Windows® 收藏夾或個人資料夾。
  • 檢索所有可用磁碟機的列表。
  • 尋找使用者的登入名稱或電腦名稱。
  • 檢索所有開啟視窗的列表。

如果僅使用 Visual Basic 6.0 中提供的工具,您不可能解決上述任何問題。對於每個問題,開發人員都需要使用 Windows API。許多開發人員使用 Windows API 已經找到了完成這些(以及許多其他)任務的方法。

Windows API 存在什麼問題?


為什麼不繼續在 .NET 環境中使用 Windows API 呢?如果使用 .NET 平台叫用服務(稱為“P/Invoke”),您當然可以這樣做。從 Visual Basic 開發人員的角度來說,調用 Windows API 並不比使用他們所熟悉的 Declare 語句困難。不過,在 .NET 環境中使用 Windows API 存在一些比較嚴重的缺陷,您可能需要考慮採取任何可行的措施來避免這些問題。例如:
  • .NET 通用語言執行平台不會受平台影響。當您使用 Windows API 呼叫時,您將代碼綁定到編寫代碼的特定平台上(即,相對於其他動作系統的某個特定 Windows 版本或 Windows 本身)。必要時,您需要將代碼轉換到另一個平台上,而這樣做就需要修改使用 API 呼叫的每行代碼。
  • 從 .NET 中調用 Windows API(或 DLL 中的任何Unmanaged 程式碼)不像在 Visual Basic 6.0 中那樣簡單。例如,對結構的工作方式的限制使得很難將結構傳遞給 API 呼叫。此外,由於資料類型的更改以及更嚴格的類型轉換,Visual Basic 6.0 的 API 聲明也需要變更。
  • 根據語言的不同,使用 Windows API(以及通常情況下使用的外部代碼)的技巧也不盡相同。如果您打算在多 .NET 語言環境中工作,則需要掌握各種語言的不同技巧。
  • 調用 Windows API 的代碼要求調用這些代碼的使用者具有執行此操作的許可權。這將影響應用程式的安全保護方案,您需要對此要求提前做出安排。

這個問題很簡單:儘管您可以在 Visual Basic .NET 應用程式中繼續使用 Windows API,但通常情況下,您應當儘可能尋找由 .NET 架構提供的替代品。雖然 .NET 架構的目的並不是要阻止您直接使用 Windows 的功能,但架構的確提供了大量的類,可以協助您放棄對 Windows API 呼叫的依賴。
如果能夠給出一個完整列表,列出 Win32 API 呼叫以及在 .NET 架構中完成相同任務的相應方法(如果有),可能會很方便,不過本文不涉及此任務。在本文中,您將瞭解到一些由 .NET 架構提供的特定且非常有用的類,它們可以解決您的問題。在每個樣本中,本文所討論的類都可以用來替代一個或多個 Win32 API 呼叫,而在 Microsoft Visual Basic 6.0 中,您必須調用一個或多個 Win32 API 才能完成相同的任務。 使用註冊表
如果您與大多數 Visual Basic 6.0 開發人員一樣,您會發現 Microsoft Visual Basic for Applications (VBA) 中內建的 SaveSetting、GetSetting、GetAllSettings 和 DeleteSetting 方法有點兒用處,但卻很可能被它們的局限性弄得精疲力盡。所有這些方法都只能在註冊表的 HKEY_CURRENT_USER\Software\VB 和 VBA Program Settings 下的項中使用。如果您要在註冊表的其他地方讀取或寫入登錄機碼或註冊表值,則必須使用複雜的 API 呼叫,或依靠別人的代碼來處理此問題。
.NET 架構在 Microsoft.Win32 名稱空間中提供了一對功能強大的類(Registry 和 RegistryKey),從而簡化了註冊表的使用,即不再需要 API 呼叫!
作為示範,請在樣本項目的主表單上單擊 Work with the Registry(使用註冊表)按鈕。此表單提供了 SOFTWARE\Microsoft\Windows\CurrentVersion\Run 項的 HKEY_LOCAL_MACHINE 登錄區中所有註冊表值的列表。您可以按右鍵列表中的任何項,然後選擇插入新項,或者編輯或刪除選定項,如圖 1 所示。
提示:樣本表單也已經過設計,在列表框中按下 Enter 鍵時,可以編輯當前選定的項。按下 Delete 鍵可以刪除選定項,按下 Insert 鍵可以添加一個新值。這些項對應於列表框的操作功能表中的項。


圖 1:使用 Registry 和 RegistryKey 類輕鬆檢索和修改 Windows 註冊表中的資訊
.NET 架構提供了兩個非常有用的類,使您可以便於使用 Windows 註冊表。第一個類是 Registry,它提供的欄位與標準 Registry 登錄區的各欄位相對應:
  • ClassesRoot (HKEY_CLASSES_ROOT)
  • CurrentConfig (HKEY_CURRENT_CONFIG)
  • CurrentUser (HKEY_CURRENT_USER)
  • DynData (HKEY_DYN_DATA)
  • LocalMachine (HKEY_LOCAL_MACHINE)
  • PerformanceData (HKEY_PERFORMANCE_DATA)
  • Users (HKEY_USERS)

要使用 Registry 類,只需檢索所需登錄區的引用。樣本表單的 LoadList 過程中包含如下代碼,以便使用註冊表中的 HKEY_LOCAL_MACHINE 登錄區:
Imports Microsoft.Win32Dim reg As RegistryKey = Registry.LocalMachine

另一個類是 RegistryKey,它可以完成所有工作。它提供了一組使用 Registry 的方法。表 1 列出了 RegistryKey 類的所有有用方法。
表 1:RegistryKey 類方法 方法 說明CreateSubKey建立新子項或開啟現有子項DeleteSubKey刪除指定子項。DeleteSubKeyTree以遞迴方式刪除子項和該子項的所有子項。DeleteValue從該項中刪除指定項值。GetSubKeyNames檢索包含所有子項名稱的字串數組。GetValue檢索指定的值。GetValueNames檢索包含與此項相關聯的所有項值名稱的字串數組。OpenSubKey檢索指定子項,具有可選的寫入許可權。SetValue設定指定的值。
RegistryKey 類還提供以下三個屬性:
  • Name:檢索項的名稱。
  • SubkeyCount:檢索與該項相關聯的子項的數量。
  • ValueCount:檢索與該項相關聯的項值的數量。

樣本表單的 ListLoad 過程將檢索所請求項中的所有值,並將檢索到的值添加到表單的列表框中:
Private Const conRegKey As String = _ "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"Private Structure RegData    Public Value As String    Public Data As String    Public Overrides _     Function ToString() As String        Return Me.Value    End FunctionEnd StructurePrivate Sub ListLoad()    Dim reg As RegistryKey = Registry.LocalMachine    Dim astrValues() As String    Dim strValue As String    Dim rd As RegData    ' 清除列表框中的現有項。    lstItems.BeginUpdate()    lstItems.Items.Clear()    ' 開啟登錄機碼,然後使用    ' 該項的值載入列表框。    reg = reg.OpenSubKey(conRegKey)    astrValues = reg.GetValueNames()    For Each strValue In astrValues        rd.Value = strValue.ToString        rd.Data = reg.GetValue(strValue)        lstItems.Items.Add(rd)    Next    lstItems.EndUpdate()End Sub

要編輯樣本表單中的值或添加新值,需要運行以下代碼:
Private Sub AddOrEdit( _ ByVal rd As RegData, _ ByVal Mode As frmAddValue.AccessMode)    Dim reg As RegistryKey = Registry.LocalMachine    Dim frm As New frmAddValue(Mode)    frm.KeyName = rd.Value    frm.KeyData = rd.Data    If frm.ShowDialog() = DialogResult.OK Then        If frm.KeyName <> String.Empty Then            reg = reg.OpenSubKey(conRegKey, True)            reg.SetValue(frm.KeyName, frm.KeyData)            ListLoad()        End If    End IfEnd Sub

此代碼將再次開啟登錄機碼,這次將請求寫入項值的許可權(此請求由 OpenSubKey 的第二個參數發出)。然後,代碼將調用 SetValue 方法,傳遞圖 1 所示的對話方塊表單中的項名和項值。為簡化工作,可以使用 SetValue 方法添加新值或修改現有值。如果項值不存在,SetValue 方法將添加一個項值。
要刪除項值,樣本表單將調用以下代碼:
Private Sub DeleteKey(ByVal rd As RegData)    Dim strText As String    Dim reg As RegistryKey = Registry.LocalMachine    If lstItems.SelectedIndex = -1 Then        Exit Sub    End If    ' 刪除選定的項。    strText = String.Format( _     "Are you sure you want to delete ""{0}""?", _     rd.Value)    If MessageBox.Show(strText, _     "Delete Registry Value", _     MessageBoxButtons.YesNo, _     MessageBoxIcon.Question) = DialogResult.Yes Then        ' 開啟項,允許寫入。        reg = reg.OpenSubKey(conRegKey, True)        reg.DeleteValue(rd.Value)        ' 重新載入列表框。        ListLoad()    End IfEnd Sub

此代碼將開啟項並請求對其執行寫入操作,然後將調用 DeleteValue 方法刪除選定的值。
有了樣本表單提供的資訊和 .NET 架構附帶的文檔,便可以輕鬆地完成與註冊表相關的任何任務,而不必使用 Windows API。這是一個簡單的物件模型,但它提供的功能比 Visual Basic 6.0 開發人員先前所擁有的功能更強大。
提示:如果具有必要的許可權,您還可以使用遠端電腦上的註冊表。您可以調用 RegistryKey.OpenRemoteBaseKey 方法檢索其他電腦上的基本項,而不是簡單地使用其中一個 Registry 類屬性,來代表您自己電腦上的 Registry 登錄區。
使用常用對話方塊
Windows 提供了一組常用對話方塊,使開發人員可以方便地請求使用者資訊。您肯定見過並且使用過開啟和儲存檔案、顏色、印表機和字型設定等常用對話方塊。Visual Basic 6.0 開發人員在使用這些對話方塊時有兩種選擇。他們可以:
  • 使用一個 Microsoft ActiveX® 控制項,該控制項提供了一個包含常用對話方塊的簡單物件模型,但是由於控制項有多個不同的版本且底層 DLL 不同,因此該控制項存在嚴重的部署問題。(對於很多 Visual Basic 6.0 開發人員來說,這個問題是最致命的 DLL 問題。)
  • 直接使用 Windows API 發送訊息並提供回叫功能,以管理各個常用對話方塊。

兩個解決方案都不是完美無缺的,而且由於對 .NET 架構進行了增補,這兩個解決方案當前都不是必需的。查看 System.Windows.Forms 名稱空間時,您會發現 ColorDialog、FileDialog、FontDialog 和 PrintDialog 類。這些類都整合在架構中(也就是說,既不需要使用 API 呼叫,也不需要使用 ActiveX 控制項),這樣可以方便地將這些標準功能合并到您的應用程式中。
每個類都提供了一系列屬性,您可以使用類的 ShowDialog 方法在顯示對話方塊之前設定這些屬性。本文將不對每個類進行詳細討論,但在樣本項目中使用了 FileDialog 類,使您可以選擇檔案。如果您在主表單上選擇了 File Version Info(檔案版本資訊)按鈕,則可以使用示範表單上的 Select a File(選擇檔案)按鈕顯示 File Open(開啟檔案)對話方塊,如圖 2 所示。

圖 2:使用 FileDialog 類顯示 Windows 常用對話方塊
雖然 FileDialog 類不像直接使用 Windows API 那樣靈活,但它提供了大量的屬性,您可以使用這些屬性控制對話方塊的操作。您可以決定檔案的來源,選擇一個或多個檔案,還可以檢索選定的檔案名稱。表 2 列出了可能會用到的 FileDialog 類的部分屬性和方法。
表 2:FileDialog 對象的屬性和方法 屬性/方法 說明AddExtension指示當使用者省略副檔名時,對話方塊是否自動為檔案添加一個副檔名。CheckFileExists指示當使用者指定的檔案名稱不存在時,對話方塊是否顯示警告資訊。CheckPathExists指示當使用者指定的路徑不存在時,對話方塊是否顯示警告資訊。DefaultExt預設副檔名。DereferenceLinks指示對話方塊是否返回捷徑所引用的檔案的位置,或者是否返回捷徑 (.lnk) 所在的位置。FileName在檔案對話方塊中選定的檔案名稱。FileNames(唯讀)對話方塊中所有選定檔案的檔案名稱。Filter當前檔案名稱篩選字串,確定對話方塊的“Save as file type”(另存新檔檔案類型)或“Files of type”(檔案類型)框中顯示的選項。FilterIndex檔案對話方塊中當前選定的篩選器的索引。InitialDirectory檔案對話方塊顯示的初始目錄。RestoreDirectory指示對話方塊在關閉之前是否還原目前的目錄。ShowHelp指示檔案對話方塊中是否顯示 Help(協助)按鈕。Title檔案對話方塊標題。ValidateNames指示對話方塊是否只接受有效檔案名稱。Reset (Method)將所有屬性重設為預設值。ShowDialog (Method)顯示檔案對話方塊。如果使用者按 OK(確定),將返回 DialogResult.OK,否則返回 DialogResult.Cancel。
單擊 Select a File(選擇檔案)時,樣本表單 frmFileVersionInfo 將調用以下代碼:
Private Sub btnSelectFile_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnSelectFile.Click    Dim ofd As OpenFileDialog = New OpenFileDialog()    ofd.Filter = _        "Executable files (*.exe;*.dll;*.ocx)|" & _        "*.exe;*.dll;*.ocx|" & _        "Drivers (*.sys;*.drv;*.fnt)|" & _        "*.sys;*.drv;*.fnt|" & _        "All files (*.*)|*.*"    ofd.FilterIndex = 1    ofd.ShowReadOnly = False    ofd.RestoreDirectory = True    If ofd.ShowDialog() = DialogResult.OK Then        If ofd.FileName.Length > 0 Then            ' 顯示檔案版本資訊。            DisplayFileInfo(ofd.FileName)        End If    End IfEnd Sub
提示:如同使用 Visual Basic 6.0 CommonDialog ActiveX 控制項一樣,您可以將 FileDialog 類的 Filter 屬性設定為一個字串,在其中包含一對以豎線分隔的值,如下所示:“Description|FileSpec”。

在上面的樣本中,一旦您選擇了一個檔案名稱,樣本表單就會在表單的 ListView 控制項中顯示有關該檔案的資訊。下一節將討論 FileVersionInfo 類,它可以實現上述操作。 檢索檔案版本資訊
開發人員和編譯人員可以將版本資訊嵌入到可執行檔、DLL 檔案和驅動程式檔案中。您可能需要檢索部分或全部版本資訊以用作應用程式的一部分,在 Visual Basic 6.0 中執行此操作需要大量的 API 呼叫。您需要調用 GetVersionInfoSize、VerQueryValue 和 GetFileVersionInfo Win32 API 函數,在 Visual Basic 中使用上述任何函數都不容易。
這種情況再一次顯示出 .NET 架構的強大:使用 FileVersionInfo 對象使得這些工作變得非常簡單。您只需調用 FileVersionInfo 對象的共用 GetVersionInfo 方法,傳遞一個檔案名稱,一切問題就都迎刃而解了。樣本表單使用了以下代碼:
Dim fvi As FileVersionInfo = _ FileVersionInfo.GetVersionInfo(strFile)

完成以上操作之後,檢索 FileVersionInfo 對象的屬性就是一件非常簡單的事情了。樣本表單使用下面所示的一小段程式,將每個屬性名稱和值都添加到表單的 ListView 控制項中:
Private Sub AddItem( _ByVal strProperty As String, _ByVal strValue As String)    With lvwInfo.Items.Add(strProperty)        .SubItems.Add(strValue)    End WithEnd Sub

真正起作用的是代碼,而代碼只需反覆調用 AddItem,每個屬性調用一次即可:
AddItem("Comments", fvi.Comments)AddItem("CompanyName", fvi.CompanyName)AddItem("Language", fvi.Language)' 此處刪除了一些行...AddItem("Product", fvi.ProductName)AddItem("ProductPrivatePart", _ fvi.ProductPrivatePart.ToString())AddItem("ProductVersion", fvi.ProductVersion)AddItem("SpecialBuild", fvi.SpecialBuild)

圖 3 所示的結果表單顯示了可通過編程使用的所有版本資訊。

圖 3:使用 FileVersionInfo 類檢索檔案版本資訊 檢索環境資訊
Win32 API 提供了一系列函數,使您可以確定使用者的環境設定。GetSystemMetrics 和 SystemParametersInfo 是其中的兩個函數。您可以繼續從 .NET 應用程式中調用這些 API 函數,但很可能您並不需要這樣做。Environment 類(位於 System 名稱空間)和 SystemInformation 類(位於 System.Windows.Forms 名稱空間)提供了許多與 API 函數相同的資訊。在本節中,我們將通過樣本來示範這兩個類的功能。
警告:不要浪費時間從這些類中尋找設定使用者環境設定的方法。此處顯示的所有資訊均為唯讀。如果您仍然希望修改環境設定,則需要尋找其他方法。


相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。