Đây là video hướng dẫn cách tạo DLL trên Delphi nhưng sử dụng trong VBA, Excel. Đây là phương pháp lập trình chuyên nghiệp nhưng không phải là khó. Giúp bạn bảo mật code của phần mềm tốt hơn.
unit UDFExcel;
interface
implementation
Uses ComObj, Classes, Variants;
Function GetSumUnit(a, b : Integer) : Integer;
begin
Result := a + b;
end;
end.
Code Dll
Mã:
library DllATuan;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
//uses
// System.SysUtils,
// System.Classes;
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
ComObj,
Excel2000,
Vcl.StdCtrls,
Math,
Vcl.ComCtrls,
DateUtils,
System.StrUtils,
ActiveX,
Data.DB,
Data.Win.ADODB,
System.Generics.Collections,
UDFExcel in 'UDFExcel.pas',
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
Function GetSumDLL(a, b : Integer) : Integer;
begin
Result := GetSumUnit(a,b);
end;
exports
GetSumDLL;
begin
end.
Code trong Form
Mã:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
Uses UDFExcel; //ten cua Unit
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
ketqua,a,b:integer;
begin
a:=10;
b:=5;
ketqua:=GetSumUnit(a,b);
end;
end.
có khai báo cái dòng này trong form khong đó
nó gạch đỏ như vậy là nó không hiểu cái hàm đó ở đâu
implementation
Uses UDFExcel; //ten cua Unit coi chừng cái tên của mạnh khác của mình áh
có khai báo cái dòng này trong form khong đó
nó gạch đỏ như vậy là nó không hiểu cái hàm đó ở đâu
implementation
Uses UDFExcel; //ten cua Unit coi chừng cái tên của mạnh khác của mình áh
PÓ TAY MẠNH LUU FILE CHƯA
CÁI LỖI ĐÓ LÀ NO KHÔNG BIẾT HÀM ĐÓ LÀ GÌ
ĐÂY CỦA MÌNH NÓ THAM CHIẾU ĐƯỢC HÀM NÀY NẰM TRONG Unit (UDFExcel.pas) View attachment 205374
Thì làm y trang mà ... chụp cái hình vầy mình nhìn cũng tịt Luôn
Chịu khó làm úp cho Mình 1 cái Source coi biết liền à ... có khi nói bên tây lại nghe bên đông à
Mới chụp xong nó như Hình mà Khi Buil nó lại lỗi Hàm
Thì làm y trang mà ... chụp cái hình vầy mình nhìn cũng tịt Luôn
Chịu khó làm úp cho Mình 1 cái Source coi biết liền à ... có khi nói bên tây lại nghe bên đông à
Mới chụp xong nó như Hình mà Khi Buil nó lại lỗi Hàm View attachment 205375
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,UDFExcel;
type
TForm1 = class(TForm)
Button1: TButton;
//procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
UDF : TUDFExcel;
implementation
//Uses ; //ten cua Unit
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
ketqua,a,b:integer;
begin
a:=10;
b:=5;
ketqua:= UDF.GetSumUnit(a,b);
ShowMessage('LowBound 2 '+IntToStr(ketqua));
end;
end.
Dlll
Mã:
library DllATuan;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
//uses
// System.SysUtils,
// System.Classes;
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
ComObj,
Excel2000,
Vcl.StdCtrls,
Math,
Vcl.ComCtrls,
DateUtils,
System.StrUtils,
ActiveX,
Data.DB,
Data.Win.ADODB,
System.Generics.Collections,
UDFExcel in 'UDFExcel.pas',
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
var
UDF : TUDFExcel;
Function GetSumDLL(a, b : Integer) : Integer;
begin
Result := UDF.GetSumUnit(a,b);
end;
Unit
Mã:
unit UDFExcel;
interface
type TUDFExcel = class
private
public
Function GetSumUnit(a, b : Integer) : Integer;
end;
var
E:variant;
implementation
Uses ComObj, Classes, Variants;
Function TUDFExcel.GetSumUnit(a, b : Integer) : Integer;
begin
Result := a + b;
end;
end.
Hồi nya4 chưa Buil, cái này Buil ok rồi nhé ma không biết có chạy hông hihihihi
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,UDFExcel;
type
TForm1 = class(TForm)
Button1: TButton;
//procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
UDF : TUDFExcel;
implementation
//Uses ; //ten cua Unit
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
ketqua,a,b:integer;
begin
a:=10;
b:=5;
ketqua:= UDF.GetSumUnit(a,b);
ShowMessage('LowBound 2 '+IntToStr(ketqua));
end;
end.
Dlll
Mã:
library DllATuan;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
//uses
// System.SysUtils,
// System.Classes;
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
ComObj,
Excel2000,
Vcl.StdCtrls,
Math,
Vcl.ComCtrls,
DateUtils,
System.StrUtils,
ActiveX,
Data.DB,
Data.Win.ADODB,
System.Generics.Collections,
UDFExcel in 'UDFExcel.pas',
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
var
UDF : TUDFExcel;
Function GetSumDLL(a, b : Integer) : Integer;
begin
Result := UDF.GetSumUnit(a,b);
end;
Unit
Mã:
unit UDFExcel;
interface
type TUDFExcel = class
private
public
Function GetSumUnit(a, b : Integer) : Integer;
end;
var
E:variant;
implementation
Uses ComObj, Classes, Variants;
Function TUDFExcel.GetSumUnit(a, b : Integer) : Integer;
begin
Result := a + b;
end;
end.
Hồi nya4 chưa Buil, cái này Buil ok rồi nhé ma không biết có chạy hông hihihihi
Chạy ok rồi đó tuy nhiên thấy khai báo dài dòng quá ... Ít hàm thì ko sao ... Nhiều Hàm chết chắc
Có cách nào khác khai báo sử dung hàm ngắn gọn hơn 1 chút ko ???!!!
À sẵn tiện đây cho mình hỏi khi viết hàm kết nối ADO mình đang phân vân không biết hướng nào tốt.
Hướng thứ 1:
Khi mở Chương trình lên thì cho kết nói ADO khi nào cần truy vấn tới Table nào thì mình chỉ cần connec tới Table đó. khi thoát chương trình thì mới ngắt kết nối.
Hướng thứ 2:
Khi cần truy vấn tới Table nào thì mình connec tới Table đó xong rồi thì ngắt kết nối.
À sẵn tiện đây cho mình hỏi khi viết hàm kết nối ADO mình đang phân vân không biết hướng nào tốt.
Hướng thứ 1:
Khi mở Chương trình lên thì cho kết nói ADO khi nào cần truy vấn tới Table nào thì mình chỉ cần connec tới Table đó. khi thoát chương trình thì mới ngắt kết nối.
Hướng thứ 2:
Khi cần truy vấn tới Table nào thì mình connec tới Table đó xong rồi thì ngắt kết nối.
Vấn đề sử dụng hàm tham chiếu qua UNIT tôi thấy cách bạn Thuyyeu99 làm qua Class cũng được nhưng chỉ nên dùng trong những trường hợp cần phải thế. Còn khi hàm đóng vai trò như một tài nguyên dùng chung ở mọi nơi với việc gọi thuận tiện thì không làm thế.
Delphi có một cách tổ chức code rất khoa học và "gói gọn". Khi một Project có nhiều function, procedure, Class thì Delphi cho phép tách code thành các unit, mỗi unit chứa một số tài nguyên làm một số tác vụ nào đó theo người lập trình sắp xếp. Với Form lưu mỗi form một unit đi cùng với file đính kèm một cặp là *.DFM. (sẽ thấy trong unit form ở gần từ khóa "implementation".
Nguyên tắc tách code ra unit. Bạn có thể bê một cụm các hàm và thủ tục vào một file unit riêng, ví dụ là "Unit1". Trong Unit1 này bạn chú ý 2 phần code:
INTERFACE: là nơi khai báo các Class, các biến - Var; hăng số - const; các function và procedure để các unit, project khác có thể gọi những tài nguyên này. Ví dụ bạn muốn các unit khác được phép sử dụng hàm GetSum thì trong khu vực INTERFACE cần khai báo
Mã:
function GetSum(a,b: Double): Double; //stdcall;
Khai báo trên gọi là Prototype - trong ngôn ngữ C, C++ thì nó chính là khai báo trong file *.h
Khu vực viết mã nguồn cho hàm là
IMPLEMENTATION (trong nguôn ngữ C, C++ thifcode phần này nằm trong file *.C, *.CPP)
{$ *.dfm} //khai báo này Delphi tự thêm vào nếu unit này được tạo ra khi bạn tạo Form, bản chất là đính kèm file khai báo cấu trúc hiển thị của form.
Trong khu vực này bạn vẫn có thể sử dụng khai báo USES để đưa vao các unit mà nó cung cấp các tài nguyên phục vụ cho việc viết mã nguồn phía dưới, nếu các unit đã khai báo ở mục USES trong INTERFACE chưa đáp ứng được.
Tiếp theo bạn viết mã nguồn hoặc tham chiếu tới DLL ở đây:
Mã:
function GetSum(a,b: Double): Double;
begin
Result := a + b;
end;
Bạn hãy nhớ, nếu không có khai báo prototye ở phần INTERFACE với function GetSum(a,b: Double): Double; thì hàm GetSum sẽ không gọi được ở các unit khác. Bây giờ giả sử trong một Project hoặc Unit khác muốn dùng các hàm trong "Unit1" (nói ở trên) thì cần khai báo
Mã:
USES Unit1;
Các bạn hãy chú ý có hai nơi được khai báo USES như nhau là INTERFACE và IMPLEMENTATION, thông thường khu vực INTERFACE chung ta khai báo các unit cần để sử dụng để khai báo được các prototype. Khu vực IMPLEMENTATION là phục vụ cho việc triển khai viết mã nguồn.
Sau khi bạn đã khai bảo Unit1 ở trên bạn đã có thể gọi ngay hàm GetSum một cách bình thường như nó đang nằm trong chính Unit bạn đang lập trình (mặc dù nó đang ở Unit khác).
Mã:
procedure CallSum;
var
res: Double;
begin
res := GetSum(10, 20);
end;
...
Tóm lại còn khá nhiều kiến thức mà nếu các bạn không đọc kỹ một chút tài liệu Object Pascal thì sẽ phải mò mẫm hơi lâu. Loạt bài trên các bạn đang đeo duổi phần ngọn mà gốc bị đuối.
Các bạn hãy chú ý có hai nơi được khai báo USES như nhau là INTERFACE và IMPLEMENTATION, thông thường khu vực INTERFACE chung ta khai báo các unit cần để sử dụng để khai báo được các prototype. Khu vực IMPLEMENTATION là phục vụ cho việc triển khai viết mã nguồn.
Cần nói rõ là "thông thường" là thế này thế này. Nhưng không phải thích chỗ nào cũng được. Vd. không thể có
Mã:
unit Unit1;
interface
uses
..., Unit2;
và
Mã:
unit Unit2;
interface
uses
..., Unit1;
Không thể để cả 2 unit (uses) trong phần interface (lỗi circular unit reference). Cả 2 ở phần implementation hoặc 1 ở implementation 1 ở interface thì được.
Các bạn thêm ý của anh Batman1 vào nữa nhé. Bài trước tôi chưa nói về vấn đề lỗi tham chiếu vòng “circular unit reference”. Khai báo Unit phải có cách tổ chức code khoa học kẻo sau này khi làm nhiều unit khai bái loạn lên là dò lỗi mệt. Trước đây tôi từng bị lỗi này mặc dù đã làm khá lắm thứ trên Delphi.