Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (7.15 MB, 706 trang )
587
Chương 15: Khả năng liên tác mã lệnh không-được-quản-lý
•
gdi32.dll gồm các hàm đồ họa dùng để để vẽ trực tiếp lên cửa sổ, trình đơn, bề mặt
điều kiểm, cũng như để in ấn.
Ví dụ, xét các hàm Win32 API dùng để đọc và ghi các file INI, chẳng hạn
GetPrivateProfileString và WritePrivateProfileString trong kernell32.dll. .NET
Framework không có lớp nào bọc lấy chức năng này. Tuy nhiên, có thể nhập các hàm này
bằng đặc tính DllImportAttribute như sau:
[DllImport("kernel32.DLL", EntryPoint="WritePrivateProfileString")]
private static extern bool WritePrivateProfileString(string lpAppName,
string lpKeyName, string lpString, string lpFileName);
Các đối số trong phương thức WritePrivateProfileString phải tương thích với hàm trong
DLL, nếu không sẽ có lỗi khi gọi nó. Vì phương thức WritePrivateProfileString được khai
báo để tham chiếu đến một hàm trong DLL nên bạn không được viết mã cho nó. Phần
EntryPoint trong đặc tính DllImportAttribute trong ví dụ này là tùy chọn, vì tên phương
thức được khai báo đã trùng với tên của hàm trong thư viện ngoài.
Trong ví dụ sau, lớp IniFileWrapper khai báo các phương thức riêng tham chiếu tới các hàm
Win32 API, sau đó gọi chúng từ các phương thức công khai khác dựa trên file được chỉ định:
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class IniFileWrapper {
private string filename;
public string Filename {
get {return filename;}
}
public IniFileWrapper(string filename) {
this.filename = filename;
}
[DllImport("kernel32.dll", EntryPoint="GetPrivateProfileString")]
private static extern int GetPrivateProfileString(string lpAppName,
string lpKeyName, string lpDefault, StringBuilder lpReturnedString,
int nSize, string lpFileName);
[DllImport("kernel32.dll", EntryPoint="WritePrivateProfileString")]
588
Chương 15: Khả năng liên tác mã lệnh không-được-quản-lý
private static extern bool WritePrivateProfileString(
string lpAppName, string lpKeyName,
string lpString, string lpFileName);
// Bốn hàm sau không được sử dụng trong ví dụ này,
// nhưng được khai báo cho đầy đủ.
[DllImport("kernel32.dll", EntryPoint="WritePrivateProfileInt")]
private static extern int GetPrivateProfileInt(string lpAppName,
string lpKeyName, int iDefault, string lpFileName) ;
[DllImport("kernel32.dll", EntryPoint="GetPrivateProfileSection")]
private static extern int GetPrivateProfileSection(
string lpAppName, byte[] lpReturnedString,
int nSize, string lpFileName);
[DllImport("kernel32.dll", EntryPoint="WritePrivateProfileSection")]
private static extern bool WritePrivateProfileSection(
string lpAppName, byte[] data, string lpFileName);
[DllImport("kernel32.dll",
EntryPoint="GetPrivateProfileSectionNames")]
private static extern int GetPrivateProfileSectionNames(
byte[] lpReturnedString, int nSize, string lpFileName);
public string GetIniValue(string section, string key) {
StringBuilder buffer = new StringBuilder();
string sDefault = "";
if (GetPrivateProfileString(section, key, sDefault,
buffer, buffer.Capacity, filename) != 0) {
return buffer.ToString();
} else {
return null;
}
}
589
Chương 15: Khả năng liên tác mã lệnh không-được-quản-lý
public bool WriteIniValue(string section, string key, string value) {
return WritePrivateProfileString(section, key, value, filename);
}
}
Phương thức GetPrivateProfileString có một thông số thuộc kiểu StringBuilder
(lpReturnedString). Đó là vì chuỗi này phải là khả đổi—khi lời gọi hàm hoàn tất,
nó sẽ chứa thông tin của file INI. Bất cứ khi nào cần chuỗi khả đổi, bạn phải sử
dụng StringBuilder thay cho String. Thông thường, bạn cần tạo StringBuilder
với một bộ đệm ký tự có kích thước xác định, rồi truyền kích thước này ( nSize)
cho phương thức. Bạn có thể chỉ định số lượng ký tự trong phương thức khởi
dựng của StringBuilder (xem mục 2.1 để có thêm thông tin về StringBuilder).
Để thử nghiệm lớp IniFileWrapper, bạn hãy tạo một file INI chứa thông tin sau:
[SampleSection]
Key1=Value1
Key2=Value2
Key3=Value3
Và thực thi đoạn mã sau để đọc và ghi một giá trị trong file INI.
public class IniTest {
private static void Main() {
IniFileWrapper ini = new IniFileWrapper(
Application.StartupPath + "\\initest.ini");
string val = ini.GetIniValue("SampleSection", "Key1");
Console.WriteLine("Value of Key1 in [SampleSection] is: " + val);
ini.WriteIniValue("SampleSection", "Key1", "New Value");
val = ini.GetIniValue("SampleSection", "Key1");
Console.WriteLine("Value of Key1 in [SampleSection] is now: " +
val);
ini.WriteIniValue("SampleSection", "Key1", "Value1");
Console.ReadLine();
}
}
590
Chương 15: Khả năng liên tác mã lệnh không-được-quản-lý
Lấy handle của một điều kiểm, cửa sổ, hoặc file
2.
Bạn cần gọi một hàm không-được-quản-lý, và hàm này cần handle của một điều
kiểm, cửa sổ, hoặc file.
Nhiều lớp, bao gồm lớp FileStream và tất cả lớp dẫn xuất từ Control, trả về
handle (thuộc cấu trúc IntPtr) thông qua thuộc tính Handle. Cũng có lớp trả về
thông tin tương tự; ví dụ, lớp System.Diagnostics.Process có thêm thuộc tính
Process.MainWindowHandle ngoài thuộc tính Handle.
.NET Framework không che dấu các chi tiết nằm dưới, chẳng hạn handle dùng cho cửa sổ và
điều kiểm. Mặc dù không thường sử dụng thông tin này, bạn có thể lấy nó khi cần gọi một
hàm không-được-quản-lý và hàm này cần đến nó.
Xét ứng dụng dưới đây, form chính luôn hiển thị trên tất cả các cửa sổ khác bất kể nó có focus
hay không (có được chức năng này bằng cách thiết lập thuộc tính Form.TopMost là true).
Form còn có một Timer định kỳ gọi các hàm không-được-quản-lý GetForegroundWindow và
GetWindowText để lấy thông tin của cửa sổ hiện đang có focus. Ngoài ra, handle của form
chính được lấy thông qua thuộc tính Form.Handle, rồi được so sánh với handle của form hiện
đang tích cực để kiểm tra form chính đang có focus hay không.
Hình 15.1 Thông tin về cửa sổ đang tích cực
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Text;
public class ActiveWindowInfo : System.Windows.Forms.Form {
// (Bỏ qua phần mã designer.)
private System.Windows.Forms.Timer tmrRefresh;
private System.Windows.Forms.Label lblCurrent;
private System.Windows.Forms.Label lblHandle;
591
Chương 15: Khả năng liên tác mã lệnh không-được-quản-lý
private System.Windows.Forms.Label lblCaption;
[DllImport("user32.dll")]
private static extern int GetForegroundWindow();
[DllImport("user32.dll")]
private static extern int GetWindowText(int hWnd, StringBuilder text,
int count);
private void tmrRefresh_Tick(object sender, System.EventArgs e) {
int chars = 256;
StringBuilder buff = new StringBuilder(chars);
int handle = GetForegroundWindow();
if (GetWindowText(handle, buff, chars) > 0) {
lblCaption.Text = buff.ToString();
lblHandle.Text = handle.ToString();
if (new IntPtr(handle) == this.Handle) {
lblCurrent.Text = "True";
} else {
lblCurrent.Text = "False";
}
}
}
}
Handle của form được quản lý một cách trong suốt đối với người dùng. Thay đổi
thuộc tính nào đó của form có thể khiến cho CRL tạo một handle mới. Do đó,
bạn nên luôn truy xuất handle ngay trước khi sử dụng nó (không nên giữ nó
trong một biến để sử dụng trong một thời gian dài).
3.
Gọi một hàm không-được-quản-lý có sử dụng cấu trúc
Bạn cần gọi một hàm không-được-quản-lý có thông số là một cấu trúc.
Định
nghĩa
cấu
trúc
trong
mã
C#.
Sử
dụng
đặc
tính
System.Runtime.InteropServices.StructLayoutAttribute để cấu hình việc cấp bộ
nhớ
cho
cấu
trúc.
Sử
dụng
phương
thức
tĩnh
SizeOf
của
lớp