DLL (Dynamic Link Library - thư viện liên kết động) là một thư viện chứa mã và dữ liệu, khá giống với Unit. Tuy nhiên, dll có thể được dùng chung cho nhiều chương trình khác nhau, viết bằng các ngôn ngữ lập trình khác nhau.
Dll được sử dụng rất nhiều trong các phần mềm, kể cả hệ điều hành. Khi mở thư mục phần mềm hoặc Windows, bạn sẽ thấy có rất nhiều file DLL trong đó. Các file dll này là một phần của chương trình, không có chúng, chương trình không hoạt động.
Một số ưu điểm của dll có thể kể đến như:
Sử dụng ít bộ nhớ: Một dll có thể dùng chung cho các chương trình khác nhau thay vì mỗi chương trình sử dụng thư viện riêng. Điều này sẽ giúp sử dụng ít bộ nhớ hơn.
Tốc độ nhanh hơn: Dll chỉ được nạp một lần vào bộ nhớ, nếu chương trình của bạn cần dll mà dll đó đã được nạp rồi thì không cần nạp lại, tiết kiệm thời gian và tài nguyên hệ thống
Dễ dàng cập nhật và sửa đổi: Dll chỉ cần cập nhật một lần, thì các chương trình sử dụng dll đó đều được cập nhật, thay vì phải cập nhật thủ công cho từng chương trình.
Chia sẻ mã giữa các ngôn ngữ khác nhau: Bạn có thể viết dll trong Delphi, và sử dụng dll đó trong C++ hoặc các ngôn ngữ khác đều được.
Phần dll sẽ có 2 bài viết, bài đầu tiên này mình sẽ đề cập đến cách tạo dll trong delphi. Phần sau sẽ trình bày cách sử dụng các hàm trong dll.
Để tạo một project dll, thực hiện theo các bước sau: File > New > Other ... Hoặc bạn muốn thêm vào chung project có sẵn, thì trong Project Manager, chuột phải vào tên project group và chọn Add New Project. Một hộp thoại sẽ hiện ra như sau, chọn Dynamic Library.
Sau đó nhấn Ok, một dll project được tạo ra.
Project dll khá giống với console, bạn phải làm việc với mã, không phải với giao diện đồ họa. Viết dll cũng giống như viết chương trình console.
Chúng ta sẽ cùng tạo một dll đơn giản, với một hàm và một thủ tục.
library NewDll;
uses
VCL.Dialogs,
System.SysUtils;
procedure ShowName(aName: string);
begin
ShowMessage('My name is ' + aName);
end;
function Sum(a, b: Integer): Integer;
begin
Result := a + b;
end;
exports
ShowName name 'NewDll.ShowName',
Sum name 'NewDll.Sum';
begin
end.
Bên cạnh đó, bạn có thể định nghĩa hằng, kiểu và khai báo biến, ...
Lưu ý: Dll không thể chứa được class.
Tên dll được khai báo bằng từ khóa library như trên. Chú ý là tên dll được khai báo phải giống với tên project, là tên file .pas.
Khi viết xong các hàm, thủ tục, thực sự chúng chưa được ghi vào dll. Chúng ta cần phải làm bước export các hàm này vào dll. Có 2 cách export:
Export ngay trên hàm: Ở cuối phần đầu của hàm, bạn thêm từ khóa export (không có s). Khi đó, hàm sẽ được ghi vào dll.
Export chung ở cuối: Trước cụm begin end. chính, bạn để ý thấy từ khóa exports (có s) như ví dụ trên. Các hàm, thủ tục sẽ được tổng hợp lại ở đây và có thể export với tên khác (tên trong dll).
Theo mình, cách 2 sử dụng nhiều hơn, và mình cũng khuyên các bạn nên sử dụng.
Bạn có thể lựa chọn hàm nào được export, hàm nào không. Những hàm không được export thì không cần ghi vào exports. Như sau đây, mình chỉ export hàm Sum thôi.
exports
Sum name 'NewDll.Sum';
Tên hàm trong chương trình dll có thể khác với tên trong dll khi được export. Như ví dụ trên thì hàm ShowName có tên trong dll là NewDll.ShowName. Khi nhập (import) các hàm trong dll có sẵn, bạn cần biết đúng tên (có phân biệt hoa thường) để import cho đúng.
Tên trong dll được định nghĩa bởi từ khóa name 'Tên'. Từ khóa name được sử dụng cùng với exports để xuất các hàm ra dll với tên khác.
exports
ShowName name 'NewDll.ShowName',
Sum name 'NewDll.Sum';
Lưu ý: Export ở trực tiếp trên hàm không định nghĩa tên được.
Bạn có thắc mắc cụm begin end. trong dll dùng để làm gì không ? Vâng, nó dùng để thực hiện các lệnh khi dll được nạp vào bộ nhớ. Nói chung phần này không cần thì để trống cũng được.
begin
ShowMessage('Chương trình sử dụng NewDll');
end.
Khi dll được nạp thì các lệnh trong begin end sẽ được thực thi, và như trên thông báo Chương trình sử dụng NewDll sẽ hiển thị
Delphi cung cấp 5 quy ước gọi dll, sử dụng cho các hàm dll, với mỗi chỉ thị thì delphi sẽ sử dụng cách khác nhau để thao tác trên dll:
Register: Quy ước này là mặc định nếu như không chỉ thị quy ước khác. Theo đó, quy ước register sử dụng thanh ghi CPU để truyền các tham số, đảm bảo tốc độ nhanh hơn các quy ước khác.
Pascal: Giống với register nhưng tương thích với pascal cổ điển.
Cdecl: Là quy ước gọi cho các dll được viết bằng các ngôn ngữ họ C. Theo đó, stack cần được dọn dẹp thủ công sau khi cuộc gọi kết thúc.
Stdcall: Thường được sử dụng cho Windows API. Theo đó, stack được tự động dọn dẹp sau khi gọi.
Safecall: Giống với stdcall nhưng an toàn hơn, các lỗi sẽ được lưu trữ trong biến kiểu HResult.
Thông thường, chúng ta sử dụng stdcall thường xuyên hơn để tương thích với các ngôn ngữ khác.
Lưu ý: Nếu chỉ thị không đúng, ví dụ dùng register hoặc pascal cho các dll viết bằng C++ thì hàm sẽ không hoạt động được.