Trang 1 trên tổng số 2 12 Cuối cùngCuối cùng
Từ 1 tới 10 trên tổng số 11 kết quả

Đề tài: Gọi hàm export của file .DLL trong lập trình C#

  1. #1
    Ngày gia nhập
    05 2007
    Nơi ở
    HCMC
    Bài viết
    60

    Mặc định Gọi hàm export của file .DLL trong lập trình C#

    Giới thiệu

    DLL (Dynamic Link Library) là một dạng mô-đun để chứa các hàm (function) và dữ liệu phục vụ cho các ứng dụng hoặc cho DLL khác. Bằng cách này, DLL giúp tiết kiệm bộ nhớ khi chia sẻ các hàm của nó cho nhiều chương trình cùng truy xuất tại một thời điểm.

    Bài viết này sẽ giúp bạn “tái sử dụng” các DLL ngày xửa ngày xưa trong môi trường C#, bằng cách gọi các hàm export chứa trong nó.

    Lưu ý:
    - Khi .NET ra đời, Microsoft đã phát triển thêm một dạng khác của DLL là Class Library khá tiện lợi. Tuy nhiên, bài viết này chỉ đề cập đến dạng DLL “cổ điển”.
    - Để thử nghiệm, bạn chỉ cần có Visual Studio 7.1 (VS 2003) trở lên.

    Tạo file DLL phục vụ thử nghiệm

    Trước hết, chúng ta cần một file DLL phục vụ thử nghiệm. Bạn tạo một project Visual C++ mới, chọn Configuration type là “Dynamic Library (.dll)”. Sau đó tạo mới 2 file như sau:

    - File “TestAPI.cpp”: chứa nội dung chính của DLL, với 2 hàm export. Hàm GetAge “bình dân” với kiểu trả về và tham số đều là kiểu dữ liệu nguyên thủy (integer). Hàm GetUser() phức tạp hơn một chút với một tham chiếu dạng struct “UserInfo”.

    - File “TestAPI.def”: khai báo các hàm được export.

    File “TestAPI”
    Visual C++ Code:
    1. //khai báo 1 struct thử nghiệm
    2. struct UserInfo
    3. {
    4.     int id;
    5.     int age;
    6.     char name[30];
    7. };
    8.  
    9. //hàm có giá trị trả về và 1 tham số là kiểu int
    10. __declspec(dllexport) DWORD _stdcall GetAge(int id)
    11. {
    12.     if (id == 1)
    13.     {
    14.         return 10;
    15.     }
    16.     return -1;
    17. }
    18.  
    19. //hàm có tham số là một biến tham chiếu struct
    20. __declspec(dllexport) DWORD _stdcall GetUser(int id, UserInfo &user)
    21. {
    22.     if (id == 1)
    23.     {
    24.         user.id = 1;
    25.         user.age = 10;
    26.         strcpy(user.name, "sonhn");
    27.         return 0;
    28.     }
    29.     return -1;
    30. }
    31.  
    32. //entry point cho DLL
    33. BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
    34. {
    35.     return TRUE;
    36. }

    File “TestAPI.def”
    Dll Define Code:
    1. LIBRARY      "TestDLL"
    2. DESCRIPTION  'sample dll Interface Windows DLL
    3.  
    4. EXPORTS
    5.     ; Explicit exports can go here
    6.     GetAge
    7.     GetUser
    Biên dịch project này để sinh ra file “TestDLL.dll”.

    Tạo project C# thử nghiệm

    Trước hết, tạo một project C# dạng Console Application (cho đơn giản!). Sau đó, hãy copy file “TestDLL.dll” vào folder “\bin\Debug” của project này.

    Bạn sẽ thấy nội dung của file .cs chính có dạng như bên dưới. Lưu ý, để import và gọi các hàm trong DLL, bạn cần khai báo thêm gói InteropServices như dòng số 2.
    Visual C# Code:
    1. Using System;
    2. Using System.Runtime.InteropServices;   //cần để thao tác với DLL
    3.  
    4. namespace CSharp
    5. {
    6.     class TestCS
    7.     {
    8.         static void Main(string[] args)
    9.         {
    10.             //nội dung đặt ở đây
    11.         }
    12.     }
    13. }

    Gọi hàm cơ bản trong DLL từ C#

    Để gọi một hàm trong DLL từ C#, chúng ta phải làm 3 bước:
    - Import file DLL
    - Khai báo một “nguyên mẫu” hàm sẽ gọi
    - Gọi hàm

    Ví dụ:
    - Để import và khai báo nguyên mẫu cho hàm GetAge(int id), chúng ta chỉ cần dùng 2 dòng code sau:
    Visual C# Code:
    1. [DllImport("TestDLL.DLL", EntryPoint="GetAge")]  //import hàm
    2. public static extern int GetAge(int id);   //khai báo nguyên mẫu
    - Sau đó, sử dụng hàm GetAge() này như thể nó đang nằm trong project C#:
    Visual C# Code:
    1. int age = GetAge(1);
    2. Console.WriteLine("age = " + age);

    Khi tham số hàm là các kiểu dữ liệu phức tạp

    Với tham số hàm là kiểu string, struct… thì mọi chuyện phức tạp hơn một chút, ví dụ:
    - Để chứa chuỗi ký tự, C# có kiểu string, nhưng ANSI C++ lại là một mảng kiểu char kết thúc bằng giá trị ‘0’.
    - Với dữ liệu dạng struct, hãy nhìn vào cấu trúc UserInfo ở ví dụ trên: data struct này được khai báo bên DLL thuộc project VC++. Khi sang bên project C#, chỉ có… trời mới hiểu UserInfo là cái quái gì!

    Giải quyết?

    Với biến string, ta dùng những “chỉ dẫn” để bắt C# “hiểu” và thao tác với dữ liệu của C++. Với biến struct, ta khai báo lại một data struct tương tự bên project C#, kèm theo một số chỉ dẫn của C#.

    Ví dụ: khai báo cấu trúc UserInfo tương tự bên C#
    Visual C# Code:
    1. [StructLayout(LayoutKind.Sequential)]
    2. public struct UserInfo
    3. {
    4.     public int id;
    5.     public int age;
    6.     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
    7.     public string name;   //tương đương char name [30] trong C++
    8. };
    Chú ý dòng thứ 1 và 6, đây là những “chỉ dẫn” giúp C# quản lý các kiểu dữ liệu không thuộc phạm vi của nó.

    Và sau đó là sử dụng “vô tư”:
    Visual C# Code:
    1. UserInfo user = new UserInfo();
    2. int errCode = GetUser(1, ref user);
    3. Console.WriteLine("id = " + user.id + ", name = " + user.name + ", age = " +  user.age);

  2. #2
    Ngày gia nhập
    07 2007
    Bài viết
    41

    hơi nghi ngờ cái chỗ: UnmanagedType.ByValTStr, yếu tố nào quyết định nó tương úng với char mà không phải là WCHAR

  3. #3
    Ngày gia nhập
    05 2007
    Nơi ở
    HCMC
    Bài viết
    60

    Thanks zxc. Quả thật đó là 1 thiếu sót nhỏ. Nhưng ByValTStr sẽ được tự động chuyển kiểu để tương thích với cả ANSI lẫn Unicode. Trong Tut trên, khi không khai báo ChatSet, VS sẽ hiểu:
    Code:
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.None)]
    tức tương đương với chuỗi ANSI.

    Nếu muốn rõ ràng hơn, chúng ta có thể bổ sung thêm khai báo CharSet:
    - Cho chuỗi ANSI:
    Code:
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
    - Cho Unicode:
    Code:
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    - Và tự động theo hệ điều hành: Unicode (Win NT, 2K, XP) và ANSI (Win98, Me)
    Code:
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
    Đã được chỉnh sửa lần cuối bởi sonhn : 20-10-2007 lúc 07:28 PM.

  4. #4
    Ngày gia nhập
    09 2006
    Bài viết
    711

    Các cậu hiểu gì về DLL chưa, đã tự tay viết 1 DLL nào chưa, hỏi đơn giản thôi: tại sao lại cần file .DEF, file .def để làm gì ?
    Cứ bê nguyên sê ri mấy bài đó thì càng chết, biểu A thì các cậu cứ làm A, chả biết tại sao, đúng hay sai. Tai hại, tai hại, đó là hậu quả của .NET đó.

  5. #5
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    Theo Dr thì:
    File .DEF trước hết có thể hiểu đơn giản nó là file định nghĩa (Define file), dùng để định nghĩa các tùy chọn cho việc linking (cho linker) với các thông tin liên quan đến exports, attributes và các thông tin liên quan khác của ứng dụng. File .def phần lớn được sử dụng khi building một thư việc .dll.
    File .def là không nhất thiết phải có, mình có thể sử dụng __declspec(dllexport)_ để thay thế khi cần thiết.

    Bác TQN bổ sung thêm xem có thiếu phần nào không? Dr chỉ có biết từng đó!
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

  6. #6
    Ngày gia nhập
    05 2007
    Nơi ở
    HCMC
    Bài viết
    60

    Mặc định Gọi hàm export của file .DLL trong lập trình C#

    Trích dẫn Nguyên bản được gửi bởi TQN Xem bài viết
    Các cậu hiểu gì về DLL chưa, đã tự tay viết 1 DLL nào chưa, hỏi đơn giản thôi: tại sao lại cần file .DEF, file .def để làm gì ?
    Cứ bê nguyên sê ri mấy bài đó thì càng chết, biểu A thì các cậu cứ làm A, chả biết tại sao, đúng hay sai. Tai hại, tai hại, đó là hậu quả của .NET đó.
    Theo tôi được biết, file .DEF còn có tác dụng giúp các hàm export có được cái tên tường minh (đúng với tên của hàm) trong Export Table của file DLL. Bước này quả thật là không cần thiết, nhưng tôi vẫn dùng nó như một thói quen.

  7. #7
    Ngày gia nhập
    09 2006
    Bài viết
    711

    Sao lại không cần thiết, cậu thử bỏ file .def đi xem code C# của cậu có get address các hàm export trong file .def được hay không ? Làm thử xem sao !

  8. #8
    Ngày gia nhập
    05 2007
    Nơi ở
    HCMC
    Bài viết
    60

    Sao lại không cần thiết, cậu thử bỏ file .def đi xem code C# của cậu có get address các hàm export trong file .def được hay không ? Làm thử xem sao !
    Câu trả lời của tôi đã nằm trong poscount #7. Còn từ "không cần thiết" của tôi ám chỉ trường hợp sử dụng file .DLL trong VC++ có kèm theo file Library và Header (vì trong file Header đã có sẵn mẫu hàm). Cảm ơn sự nhiệt tình của cậu.

  9. #9
    Ngày gia nhập
    06 2007
    Bài viết
    2

    Đọc tut này rất hay ,cảm ơn mọi người đã thảo luận.Mình có một thắc mắc nhỏ nhử sau mong mọi người giúp đỡ:
    Mình sử dụng hàm CryptAcquireContext,CryptGetUserKey của thư viện advapi32.dll ,tuy nhiên các tham số của hàm sử dụng các tham số mà khai báo dạng
    HCRYPTPROV hCryptProv;
    HCRYPTKEY hKey;
    HCRYPTKEY hXchgKey;
    HCRYPTHASH hHash;

    PBYTE pbKeyBlob;
    DWORD dwKeyBlobLen;
    Đó là khai báo trên C++ vậy khi sử dụng trên C# thì thế nào ,mong mọi người giúp đỡ.
    Mình muốn sử dụng các hàm Crypto API viết bằng C# đó mà
    Chân thành cảm ơn !

  10. #10
    Ngày gia nhập
    10 2007
    Bài viết
    3

    Bài viết rất bổ ích, mình cũng đang khắp vấn đề với *.DLL thanks pác sonhn

Các đề tài tương tự

  1. Làm thế nào để export file exel sang file XML
    Gửi bởi quangbinhit trong diễn đàn Thắc mắc lập trình ASP.NET
    Trả lời: 4
    Bài viết cuối: 12-12-2012, 07:01 PM
  2. Làm thế nào để export bảng dữ liệu 2 trường trong sql 2008 sang file txt
    Gửi bởi innoben_txd trong diễn đàn Thắc mắc Microsoft SQL Server & Microsoft Access
    Trả lời: 0
    Bài viết cuối: 16-06-2012, 12:02 PM
  3. Không tìm thấy chức năng Export template trong menu file ?
    Gửi bởi beginner.nguyen trong diễn đàn Thắc mắc lập trình C#
    Trả lời: 0
    Bài viết cuối: 29-06-2011, 05:05 PM
  4. export dữ liệu từ datagridview ra file excell trong C# 2005
    Gửi bởi hc1987 trong diễn đàn Thắc mắc lập trình C#
    Trả lời: 10
    Bài viết cuối: 21-05-2011, 09:58 PM
  5. Import và Export hình ảnh trong SQL2000 ra file .XML bị lỗi!
    Gửi bởi khoavl trong diễn đàn Thắc mắc lập trình C#
    Trả lời: 1
    Bài viết cuối: 30-04-2010, 07:57 PM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn