Tại sao lại sử dụng được DLL?

Chào mọi người,

Em đang tìm hiểu về tạo một COM ATL DLL bằng Visual C++. Em có một thắc mắc nhưng chưa tìm được giải đáp, mong mọi người giúp đỡ.

Ở project ATL (P1), em đã tạo được DLL. Trong Project MFC (P2) em muốn dùng DLL đó thì cần include 2 file .h và .c theo đường dẫn tới thư mục chứa 2 file này (.h và .c của P1) trong P1

hoặc

copy 2 file này vào thư mục chạy của P2 thì build và làm như vậy thì chạy được (P2 sử dụng được DLL của P1).

Nhưng em thử copy file .h và .c vào thư mục của P2 xong, em chuyển thư mục chứa P1 đi chỗ khác đi thì P2 sẽ không gọi được DLL của P1.

Vậy mọi người cho em hỏi việc gọi một DLL thì liên quan tới những gì? Tại sao sau khi copy P1 tới một nơi khác thì phải build lại thì khi include file .h và .c ở P2 mới sử dụng được DLL?

1 Like

Khi compile một file DLL ta cần source code của file DLL đó. Build DLL cũng giống như build EXE, ta cũng cần header và source code, tức file .h và file .c. Tuy nhiên, file DLL không tự nó chạy được, mà nó sẽ là thư viện để cho các chương trình khác đọc.

Một khi compile file DLL thì ta sẽ có được bên trong file DLL là mã máy có thể thực hiện được các tính năng mà ta đã thiết kế cho nó trong file .c. Lúc này, ta không còn cần file .c để sử dụng file DLL nữa, đây là điều mà @bigboybang hiểu nhầm. Ở đây, ta chỉ cần file .h là có thể sử dụng được DLL.

Compile một DLL

Tại sao lại cần file .h mà không cần file .c? Ta có thể hiểu như sau, ta có file .c chứa source code, sau khi compile thì toàn bộ source code sẽ chuyển thành mã máy sẵn sàng thực thi nếu ta load các mã này vào RAM và fetch cho CPU chạy từng instruction.

Cấu trúc của DLL

Vậy làm sao để ta biết đoạn mã nào thực thi? Khi compile xong thì DLL sẽ có một cái “bản đồ” hướng dẫn chi tiết hàm nào, ở vị trí nào trong file DLL này. Ví dụ

Ta có code như sau:

/*
 * File name: test.c
 * For C code compile with: 
 * gcc -c test.c
 *
 * For C++ code compile with:
 * g++ -c test.cpp
 */
 
int global_var;
int global_var_init = 26;
 
static int static_var;
static int static_var_init = 25;
 
static int static_function()
{
	return 0;
}
 
int global_function(int p)
{
	static int local_static_var;
	static int local_static_var_init=5;
 
	local_static_var = p;
 
	return local_static_var_init + local_static_var;
}
 
int global_function2()
{
	int x;
	int y;
	return x+y;
}
 
#ifdef __cplusplus
extern "C"
#endif
void non_mangled_function()
{
	// I do nothing
}
 
int main(void)
{
	global_var = 1;
	static_var = 2;
 
	return 0;
}

Thì “bản đồ” của file DLL này như sau

0000000a T global_function
00000025 T global_function2
00000004 C global_var
00000000 D global_var_init
00000004 b local_static_var.1255
00000008 d local_static_var_init.1256
0000003b T main
00000036 T non_mangled_function
00000000 t static_function
00000000 b static_var
00000004 d static_var_init

Đoạn ví dụ trên được lấy từ wiki của lệnh nm trong Linux.

Liên kết với DLL

Để sử dụng được DLL thì ta cần phải thông báo cho compiler biết là ta muốn dùng DLL này. Để giúp cho compiler biết cách sử dụng DLL này ta cần 2 thứ.

  • File header chứa “tên” của các hàm trong DLL có
  • File DLL

Compiler sẽ tự biết cách tìm tên hàm.


Quay trở lại câu hỏi của @bigboybang

Như thế này có nghĩa là file DLL nằm trong thư mục P1. Việc copy file .h và file .c vào P2 không thực hiện việc build lại DLL.

Tương tự, việc copy này không build lại DLL. Bản chất P2 vẫn dùng DLL ở P1.

Chỉ cần include file .h là được. Đồng thời P2 cần phải biết đường đẫn của DLL nằm trong P1 là nằm chỗ nào.


Ở đây chắc là @bigboybang sử dụng Visual Studio, nó che dấu bớt rất nhiều thao tác. Giúp cho việc lập trình dễ hơn. Nhưng đồng thời cũng che giấu luôn việc compile DLL diễn ra như thế nào, việc include diễn ra như thế nào.

4 Likes

Ở trường hợp của em, khi tạo một COM ATL DLL thì trong file .c có IID (Interface ID)CLSID( Class ID). Thì khi dùng dll ở P2 thì cần include .c để gọi đến dll. Có thể bỏ include file .c này nếu khi báo luôn IID và CLSID ở P2. Ví dụ:
P2:

const IID IID_IFirst_ATL =
    {0xC8F6E230,0x2672,0x11D3,
    {0xA8,0xA8,0x00,0x10,0x5A,0xA9,0x43,0xDF}};

const CLSID CLSID_First_ATL =
    {0x970599E0,0x2673,0x11D3,
    {0xA8,0xA8,0x00,0x10,0x5A,0xA9,0x43,0xDF}};

Nguồn: http://www.codeproject.com/Articles/96/Beginner-s-Tutorial-COM-ATL-Simple-Project Step 6.

Nhân tiện có IIDCLSID thuộc GUID, thì có Data4{0xA8,0xA8,0x00,0x10,0x5A,0xA9,0x43,0xDF}. Em đã cố tìm hiểu nhưng không biết dãy số trên từ đâu ra.

Liên kết với DLL

Sau khi em build ra được DLL ở P1. Em copy file .h và file .dll và thư mục ở P2. Thì khi xóa P1 đi, build P2 thì không sử dụng được DLL của P1.

–> Vậy có nghĩa là DLL sau khi build ra được, vẫn cần phải nằm đúng vị trí ở P1 thì P2 mới có thể sử dụng được ạ? Giả sử, để sử dụng được DLL ở 1 máy khác thì vẫn cần đưa cả P1 sang máy đó và build thì mới dùng được DLL? (Em thắc mắc điều này là bởi trước em thấy chỉ cần add reference DLL (chỉ mình file .dll không có cả project tạo ra nó) ở 1 máy khác là đã có thể sử dụng được các hàm trong DLL đó).

Đúng ạ, em dùng Visual Studio 2012. :slight_smile: .

?! Khi em copy file .h vào P2 rồi, thì complier sẽ tìm file .dll như thế nào? Liệu có phải qua Registry? Em mới lần đầu đi tìm hiểu sâu 1 vấn đề, nên có gì không phải mong anh bỏ qua và hướng dẫn ạ. :blush:

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?