AI muốn lập trình DLL cho Excel và các loại bằng Delphi thì xem video này nhé!

Liên hệ QC

Nguyễn Duy Tuân

Nghị Hách
Thành viên danh dự
Tham gia
13/6/06
Bài viết
4,652
Được thích
10,140
Giới tính
Nam
Nghề nghiệp
Giáo viên, CEO tại Bluesofts
Lần chỉnh sửa cuối:
Nếu bạn nhận mảng từ GetRows rồi sau đó lại tạo mảng để lưu mới là mất 2 lần làm việc tốc độ sẽ chậm. Giải pháp là không dùng GetRows mà hãy duyệt từng dòng của Recordset rồi lấy vào mảng luôn tốc độ sẽ nhanh.
Chính xác là vậy ... Mình đang tập tành Delphi thì phải tập Ăn cháo xong sau đó mới ăn cơm được chứ ?! :D

Mong các Bạn chỉ thêm 1 vấn đề viết cho Mạnh xin 1 code mẫu vậy là Mạnh từng bước tiếp cận Delphi tốt đó
Cảm ơn rất nhiều
 
Upvote 0
Mạnh mới test lại các kiểu thì thấy hàm đó viết lộn một chút Mạnh điều chỉnh lại như sau mới chạy OK khi ta sử dụng ADO lấy dữ liệu từ 1 Sheet vào Mảng sử dung Phức thức GetRows ... xong dùng hàm chuyển mảng gán lên Range
Mã:
function TransArr(ssArr: OleVariant): OleVariant; stdcall;
var
    tmpArr    : OleVariant;
    x, y    : integer;
    lcol,lRows  : integer;
begin
  lcol := VarArrayHighBound(ssArr, 2); //Cot
  lRows := VarArrayHighBound(ssArr, 1); //dong
  tmpArr := VarArrayCreate([1, lcol + 1, 1, lRows + 1],varVariant);
    for x:= 0 to lcol do begin
        for y:= 0  to lRows do begin
            tmpArr[x + 1, y + 1] := ssArr[y, x];
        end; // y
    end; // x
    Result := tmpArr;
end;
Mô tả sơ bộ 1 chút
1/ Nếu ta ko + thêm 1 trong hàm thì khi lấy lên ta phải cộng thêm 1 khi Resize
Mã:
Range("A2").Resize(UBound(dArr, 1) + 1, UBound(dArr, 2) + 1) = dArr
2/ Còn nếu ta đã cộng thêm 1 trong Hàm TransArr thì khi ta lấy lên gán dữ liệu ko + thêm 1 nữa
Mã:
Range("A2").Resize(UBound(dArr, 1), UBound(dArr, 2)) = dArr
3/ 1 ở đây là 1 cột và 1 dòng

Cảm ơn thuyyeu99 Viết cho Mạnh cái Hàm hay và hay hết tất cả là Mạnh biết xài mảng 2dArray trong Delphi
Mình thấy bạn có máy bài viết Code rất đẹp, mong bạn có cái nào hay chia sẻ với mọi người
 
Upvote 0
Mình đang tập xài thư viện của Windows thử xài Fso trong Delphi mà thấy lỗi Mong các Bạn chỉ dùm
1/ Khởi tạo sử dụng Fso
2/ Giải phóng biến khi thực hiện xong ( Set Fso = nothing ) trên Excel còn trong Delphi giải phóng biến Sao ?!
3/ Code sau chạy làm đơ file Excel ... sai cái gì mong các bạn chỉ dùm ( nó tao xong File D:\MyFile.txt thì thoát luôn Excel )
Mã:
procedure Test_Fso; stdcall;
const
  ForReading = 1;
  ForWriting = 2;
  ForAppending = 8;
  TristateFalse = 0;
var
  f, sPath, fs, objFile : OleVariant;
begin
  sPath := 'D:\MyFile.txt';
  fs := CreateOleObject('Scripting.FileSystemObject');
  if not fs.FileExists(sPath) then
  begin
   objFile := fs.CreateTextFile(sPath);
   objFile.Close();
  end;
  f := fs.OpenTextFile(sPath, ForAppending, TristateFalse);
  f.Write('Hello, world!' + #13#10);
  f.Close();
end;
 
Lần chỉnh sửa cuối:
Upvote 0
Mình đang tập xài thư viện của Windows thử xài Fso trong Delphi mà thấy lỗi Mong các Bạn chỉ dùm
1/ Khởi tạo sử dụng Fso
2/ Giải phóng biến khi thực hiện xong ( Set Fso = nothing ) trên Excel còn trong Delphi giải phóng biến Sao ?!
3/ Code sau chạy làm đơ file Excel ... sai cái gì mong các bạn chỉ dùm ( nó tao xong File D:\MyFile.txt thì thoát luôn Excel )
Mã:
procedure Test_Fso; stdcall;
const
  ForReading = 1;
  ForWriting = 2;
  ForAppending = 8;
  TristateFalse = 0;
var
  f, sPath, fs, objFile : OleVariant;
begin
  sPath := 'D:\MyFile.txt';
  fs := CreateOleObject('Scripting.FileSystemObject');
  if not fs.FileExists(sPath) then
  begin
   objFile := fs.CreateTextFile(sPath);
   objFile.Close();
  end;
  f := fs.OpenTextFile(sPath, ForAppending, TristateFalse);
  f.Write('Hello, world!' + #13#10);
  f.Close();
end;

Set Fso = nothing => fs := Unassigned;

Mã:
  begin
   objFile := fs.CreateTextFile(sPath);
   objFile.WriteToTextFile(sPath, 'Hello, world!' + #13#10, objFile.ctANSI, false);
   objFile.Close;
  end;
or
f.WriteLine('Hello, world!' + #13#10');
f.Close;
 
Upvote 0
Set Fso = nothing => fs := Unassigned;

Mã:
  begin
   objFile := fs.CreateTextFile(sPath);
   objFile.WriteToTextFile(sPath, 'Hello, world!' + #13#10, objFile.ctANSI, false);
   objFile.Close;
  end;
or
f.WriteLine('Hello, world!' + #13#10');
f.Close;
Mới thử xong nó vẫn vậy ... tao file sPath := 'D:\MyFile.txt'; xong nó đơ file Excel xong thoát luôn
Nó sai 1 cái gì đó ... phần uses khai báo là vầy ko biết đúng ko nữa
Mã:
uses
System.win.comobj;

Nếu Mình xài Dic Thì cũng giải phóng biến như Fso hay sao và phần Uses khai báo sao ?
Mã:
Dic := CreateOleObject('Scripting.Dictionary')
Dic := Unassigned ===> Set Dic = Nothing hay sao
 
Lần chỉnh sửa cuối:
Upvote 0
Mới thử xong nó vẫn vậy ... tao file sPath := 'D:\MyFile.txt'; xong nó đơ file Excel xong thoát luôn
Nó sai 1 cái gì đó ... phần uses khai báo là vầy ko biết đúng ko nữa
Mã:
uses
System.win.comobj;

Nếu Mình xài Dic Thì cũng giải phóng biến như Fso hay sao và phần Uses khai báo sao ?
Mã:
Dic := CreateOleObject('Scripting.Dictionary')
Dic := Unassigned ===> Set Dic = Nothing hay sao
Ủa mình chạy đâu thấy lỗi đâu ta
User ComObj
may cai CreateOleObject('Scripting.Dictionary') minh khong co dung
ban than Delphi hinh nhu cung co Dic ay
Generics Collections TDictionary

System.Variants.Unassigned

Returns an "empty" variant.

A variant variable can be "empty", meaning it has not yet been assigned to. The Unassigned function returns an empty variant, which can be assigned to a variant variable to restore the variable to its initial state.

Use the VarIsEmpty function to test whether a variant is empty. When used on an empty variant, the VarType standard function returns varEmpty.

If an empty variant is cast to another type (for example, by assigning to a non-variant variable or calling VarAsType) the following conversions occur:
Note: Unassigned is useful with variants referencing OLE Automation Objects that you want to keep "alive" until another value is assigned to the variant.
 
Lần chỉnh sửa cuối:
Upvote 0
Ủa mình chạy đâu thấy lỗi đâu ta
User ComObj
may cai CreateOleObject('Scripting.Dictionary') minh khong co dung
ban than Delphi hinh nhu cung co Dic ay
Generics Collections TDictionary

System.Variants.Unassigned

Returns an "empty" variant.

A variant variable can be "empty", meaning it has not yet been assigned to. The Unassigned function returns an empty variant, which can be assigned to a variant variable to restore the variable to its initial state.

Use the VarIsEmpty function to test whether a variant is empty. When used on an empty variant, the VarType standard function returns varEmpty.

If an empty variant is cast to another type (for example, by assigning to a non-variant variable or calling VarAsType) the following conversions occur:
Note: Unassigned is useful with variants referencing OLE Automation Objects that you want to keep "alive" until another value is assigned to the variant.
Mới thử add vào mà ko biết xài kiểu gì nữa :D:D

Fso2.PNGFuncti.PNG

Thấy có dòng sau nói
Lưu ý: Unassigned là hữu ích với các biến thể tham chiếu OLE Automation Objects mà bạn muốn giữ "alive" giá trị khác được gán cho biến thể.
Giải phóng biến Object đó he Set Fso = Nothing
 
Lần chỉnh sửa cuối:
Upvote 0
Mới thử add vào mà ko biết xài kiểu gì nữa :D:D

View attachment 204532View attachment 204533

Thấy có dòng sau nói
Lưu ý: Unassigned là hữu ích với các biến thể tham chiếu OLE Automation Objects mà bạn muốn giữ "alive" giá trị khác được gán cho biến thể.
Giải phóng biến Object đó he Set Fso = Nothing
bạn dùng CreateOleObject('Scripting.Dictionary') đưa ví dụ lên đây mình mò thử
 
Upvote 0
bạn dùng CreateOleObject('Scripting.Dictionary') đưa ví dụ lên đây mình mò thử
Giờ ta thử làm 1 cái Dic xem tình hình sao nhé ... bước đầu ta làm đơn giản xong ... sẻ làm phức tạp từ từ
1/ Có vùng dữ liệu đưa vào mảng là : Arr = Range("B4:E1000").value
2/ Ta sử dụng Dic lọc duy nhất Cột B xong Gán kết qủa qua cột [H4]
3/ Ta sử dụng thêm điều kiện nếu Cột B có dự liệu thì lấy nguyên dòng đó Nếu ko thì bỏ qua

Nếu trên VBA thì Mạnh hay xài vầy
Mã:
If Len(Arr(i, 1)) Then

Còn Delphi Mạnh đoán vậy hên thì trúng he
Mã:
If Length(Arr(i,1))then
4/ qua bài cơ bản này xong sẻ làm phức tạp rắc rối thêm 1 chút .... quan trọng là biết xài Dic trong Delphi cái Đã xong tính tiếp

Cảm ơn Bạn và rất mong từng bước chỉ Mạnh Tiếp cận Delphi qua các Code cơ bản nhất ... Thì Mạnh sẻ học tốt đó
Capture.PNG
 

File đính kèm

  • Test Code.xlsx
    10.6 KB · Đọc: 9
Lần chỉnh sửa cuối:
Upvote 0
Giờ ta thử làm 1 cái Dic xem tình hình sao nhé ... bước đầu ta làm đơn giản xong ... sẻ làm phức tạp từ từ
1/ Có vùng dữ liệu đưa vào mảng là : Arr = Range("B4:E1000").value
2/ Ta sử dụng Dic lọc duy nhất Cột B xong Gán kết qủa qua cột [H4]
3/ Ta sử dụng thêm điều kiện nếu Cột B có dự liệu thì lấy nguyên dòng đó Nếu ko thì bỏ qua

Nếu trên VBA thì Mạnh hay xài vầy
Mã:
If Len(Arr(i, 1)) Then

Còn Delphi Mạnh đoán vậy hên thì trúng he
Mã:
If Length(Arr(i,1))then
4/ qua bài cơ bản này xong sẻ làm phức tạp rắc rối thêm 1 chút .... quan trọng là biết xài Dic trong Delphi cái Đã xong tính tiếp

Cảm ơn Bạn và rất mong từng bước chỉ Mạnh Tiếp cận Delphi qua các Code cơ bản nhất ... Thì Mạnh sẻ học tốt đó
View attachment 204558
Mạnh cụ thể bằng Code VBA đi để làm cho đúng ý (cái này chắc bạn làm trong 30s), tự trong Delphi mình không dùng Dic mà dùng TStringList đỡ mắc công suy nghĩ hihihihihi
 
Upvote 0
Mạnh cụ thể bằng Code VBA đi để làm cho đúng ý (cái này chắc bạn làm trong 30s), tự trong Delphi mình không dùng Dic mà dùng TStringList đỡ mắc công suy nghĩ hihihihihi
Dic trên VBA thì đơn giản mà .... khó khăn và quan trọng nhất là tùy biến thuật toán link tinh trong đó thui ... còn lọc duy nhất đầy cách viết
Mã:
Sub Test_Dic()
    Dim Arr(), Res(), i As Long, k As Long
    Arr = Range("B4:E1000").Value
    ReDim Res(1 To UBound(Arr, 1), 1 To UBound(Arr, 2))
    With CreateObject("scripting.dictionary")
        For i = 1 To UBound(Arr, 1)
            If Len(Arr(i, 1)) Then
                If Not .Exists(Arr(i, 1)) Then
                    k = k + 1
                    .Add Arr(i, 1), k
                    Res(k, 1) = Arr(i, 1)
                    Res(k, 2) = Arr(i, 2)
                    Res(k, 3) = Arr(i, 3)
                    Res(k, 4) = Arr(i, 4)
                End If
            End If
        Next
        Range("H4:M65536").ClearContents
        Range("H4").Resize(UBound(Arr, 1), UBound(Arr, 2)) = Res
    End With
End Sub
 
Upvote 0
Giờ ta thử làm 1 cái Dic xem tình hình sao nhé ... bước đầu ta làm đơn giản xong ... sẻ làm phức tạp từ từ
1/ Có vùng dữ liệu đưa vào mảng là : Arr = Range("B4:E1000").value
2/ Ta sử dụng Dic lọc duy nhất Cột B xong Gán kết qủa qua cột [H4]
3/ Ta sử dụng thêm điều kiện nếu Cột B có dự liệu thì lấy nguyên dòng đó Nếu ko thì bỏ qua

Nếu trên VBA thì Mạnh hay xài vầy
Mã:
If Len(Arr(i, 1)) Then

Còn Delphi Mạnh đoán vậy hên thì trúng he
Mã:
If Length(Arr(i,1))then
4/ qua bài cơ bản này xong sẻ làm phức tạp rắc rối thêm 1 chút .... quan trọng là biết xài Dic trong Delphi cái Đã xong tính tiếp

Cảm ơn Bạn và rất mong từng bước chỉ Mạnh Tiếp cận Delphi qua các Code cơ bản nhất ... Thì Mạnh sẻ học tốt đó
View attachment 204558
Mạnh chính sửa cho phù hợp với mình nhé
Mã:
procedure TForm1.Button24Click(Sender: TObject);
var
    Src,Des, Tmp,Dic,Arr: OleVariant;
    i, j,n,n1,lcol,lRows: Longint;
    TG: Double;
begin
   try
    E := GetActiveOleObject('Excel.Application');
  except
   ShowMessage('khong lay duoc excel ?');
  end;
 Dic := CreateOleObject('Scripting.Dictionary') ;
    j := 0;
     Src  := E.Range['A4:E100'].Value;
      Des  := E.Range['H4'];
      lcol := VarArrayHighBound(Src, 2); //Cot
      lRows := VarArrayHighBound(Src, 1); //dong
       Arr := VarArrayCreate([1, lcol + 1, 1, lRows + 1],varVariant);
   for i:=VarArrayLowBound(Src, 1) to VarArrayHighBound(Src,1) do begin
    if Src[i, 2]<>'' then begin
            Tmp := Src[i, 2]; // Src(i, 1) & Src(i, 2)
            if  not dic.Exists(Tmp) then begin
                j := j+1;
                Dic.Add(Tmp, '');
                Arr[1, j] := Src[i, 1];
                Arr[2, j] := Src[i, 2];
            end;
        end;
    end;
     if j<>0 then begin
    for n:=VarArrayLowBound(Arr, 2) to VarArrayHighBound(Arr,2) do begin
     Des.Cells.Item[n+1, 1].Value:=Arr[2,n];
    end;
    end;
end;
 
Upvote 0
Mạnh chính sửa cho phù hợp với mình nhé
Mã:
procedure TForm1.Button24Click(Sender: TObject);
var
    Src,Des, Tmp,Dic,Arr: OleVariant;
    i, j,n,n1,lcol,lRows: Longint;
    TG: Double;
begin
   try
    E := GetActiveOleObject('Excel.Application');
  except
   ShowMessage('khong lay duoc excel ?');
  end;
Dic := CreateOleObject('Scripting.Dictionary') ;
    j := 0;
     Src  := E.Range['A4:E100'].Value;
      Des  := E.Range['H4'];
      lcol := VarArrayHighBound(Src, 2); //Cot
      lRows := VarArrayHighBound(Src, 1); //dong
       Arr := VarArrayCreate([1, lcol + 1, 1, lRows + 1],varVariant);
   for i:=VarArrayLowBound(Src, 1) to VarArrayHighBound(Src,1) do begin
    if Src[i, 2]<>'' then begin
            Tmp := Src[i, 2]; // Src(i, 1) & Src(i, 2)
            if  not dic.Exists(Tmp) then begin
                j := j+1;
                Dic.Add(Tmp, '');
                Arr[1, j] := Src[i, 1];
                Arr[2, j] := Src[i, 2];
            end;
        end;
    end;
     if j<>0 then begin
    for n:=VarArrayLowBound(Arr, 2) to VarArrayHighBound(Arr,2) do begin
     Des.Cells.Item[n+1, 1].Value:=Arr[2,n];
    end;
    end;
end;
1/ nếu xài dòng sau không hiểu sao nó làm đơ file Excel xong thoát luôn
Mã:
E := GetActiveOleObject('Excel.Application');

2/ Mạnh chỉnh lại vào chạy Tuyệt vời tuy nhiên kết quả sai 1 chút do mấy vòng For kia sai 1 tẹo chỉnh lại chút là Ok
Mã:
procedure Test_Dic(Src, Des: OleVariant);stdcall;
var
    //Src,
    //Des,
    Tmp,Dic,Arr: OleVariant;
    i, j,n,n1,lcol,lRows: Longint;
    TG: Double;
    //E: OleVariant;
begin
   //try
    //E := GetActiveOleObject('Excel.Application');
  //except
   //ShowMessage('khong lay duoc excel ?');
  //end;
Dic := CreateOleObject('Scripting.Dictionary') ;
    j := 0;
     //Src  := E.Range['A4:E100'].Value;
     //Src  := Range['A4:E100'];
     // Des  := Range['H4'];
      lcol := VarArrayHighBound(Src, 2); //Cot
      lRows := VarArrayHighBound(Src, 1); //dong
       Arr := VarArrayCreate([1, lcol + 1, 1, lRows + 1],varVariant);
   for i:=VarArrayLowBound(Src, 1) to VarArrayHighBound(Src,1) do begin
    if Src[i, 2]<>'' then begin
            Tmp := Src[i, 2]; // Src(i, 1) & Src(i, 2)
            if  not dic.Exists(Tmp) then begin
                j := j+1;
                Dic.Add(Tmp, '');
                Arr[1, j] := Src[i, 1];
                Arr[2, j] := Src[i, 2];
            end;
        end;
    end;
     if j<>0 then begin
    for n:=VarArrayLowBound(Arr, 2) to VarArrayHighBound(Arr,2) do begin
     //Des.Cells.Item[n+1, 1].Value:=Arr[2,n];    //Bao Loi Value
     Des.Cells.Item[n+1, 1]:=Arr[2,n];
    end;
    end;
end;
Giờ lại bận rồi Mai sáng mạnh viết lại thành 1 Function là là tuyệt Vời

3/ Trên VBA ta xài Resize nhhu7 sau còn trong Delphi code nào thay thế như vậy Bạn Nhỉ
Mã:
Range("H4").Resize(UBound(Arr, 1), UBound(Arr, 2)) = Res

hay đó Mai mạnh Nghiên Cứu Kỹ hơn .... Cảm ơn rất NhiềuCapture.PNG

Có lẻ truyền chính tham số từ Excel vào nó tương tác với *.dll cho nên nó chạy rất nhanh thấy bài trước @Nguyễn Duy Tuân có nói ?!
 
Lần chỉnh sửa cuối:
Upvote 0
1/ nếu xài dòng sau không hiểu sao nó làm đơ file Excel xong thoát luôn
Mã:
E := GetActiveOleObject('Excel.Application');

2/ Mạnh chỉnh lại vào chạy Tuyệt vời tuy nhiên kết quả sai 1 chút do mấy vòng For kia sai 1 tẹo chỉnh lại chút là Ok
Mã:
procedure Test_Dic(Src, Des: OleVariant);stdcall;
var
    //Src,
    //Des,
    Tmp,Dic,Arr: OleVariant;
    i, j,n,n1,lcol,lRows: Longint;
    TG: Double;
    //E: OleVariant;
begin
   //try
    //E := GetActiveOleObject('Excel.Application');
  //except
   //ShowMessage('khong lay duoc excel ?');
  //end;
Dic := CreateOleObject('Scripting.Dictionary') ;
    j := 0;
     //Src  := E.Range['A4:E100'].Value;
     //Src  := Range['A4:E100'];
     // Des  := Range['H4'];
      lcol := VarArrayHighBound(Src, 2); //Cot
      lRows := VarArrayHighBound(Src, 1); //dong
       Arr := VarArrayCreate([1, lcol + 1, 1, lRows + 1],varVariant);
   for i:=VarArrayLowBound(Src, 1) to VarArrayHighBound(Src,1) do begin
    if Src[i, 2]<>'' then begin
            Tmp := Src[i, 2]; // Src(i, 1) & Src(i, 2)
            if  not dic.Exists(Tmp) then begin
                j := j+1;
                Dic.Add(Tmp, '');
                Arr[1, j] := Src[i, 1];
                Arr[2, j] := Src[i, 2];
            end;
        end;
    end;
     if j<>0 then begin
    for n:=VarArrayLowBound(Arr, 2) to VarArrayHighBound(Arr,2) do begin
     //Des.Cells.Item[n+1, 1].Value:=Arr[2,n];    //Bao Loi Value
     Des.Cells.Item[n+1, 1]:=Arr[2,n];
    end;
    end;
end;
Giờ lại bận rồi Mai sáng mạnh viết lại thành 1 Function là là tuyệt Vời

3/ Trên VBA ta xài Resize nhhu7 sau còn trong Delphi code nào thay thế như vậy Bạn Nhỉ
Mã:
Range("H4").Resize(UBound(Arr, 1), UBound(Arr, 2)) = Res

hay đó Mai mạnh Nghiên Cứu Kỹ hơn .... Cảm ơn rất NhiềuView attachment 204577

Có lẻ truyền chính tham số từ Excel vào nó tương tác với *.dll cho nên nó chạy rất nhanh thấy bài trước @Nguyễn Duy Tuân có nói ?!
Tự mình copy cai UDF của mạnh phía trên nên nó hơi rối tý hihihi

lcol := VarArrayHighBound(Src, 2); //Cot
lRows := VarArrayHighBound(Src, 1); //dong
//Arr := VarArrayCreate([1, lcol + 1, 1, lRows + 1],varVariant);
Arr := VarArrayCreate([1, lRows + 1, 1, lcol + 1],varVariant);

Arr[j, 1] := Src[i, 1];
Arr[j, 2] := Src[i, 2];


Des.Resize[j, VarArrayHighBound(Arr, 2)].Value:=Arr;
 
Upvote 0
Tự mình copy cai UDF của mạnh phía trên nên nó hơi rối tý hihihi

lcol := VarArrayHighBound(Src, 2); //Cot
lRows := VarArrayHighBound(Src, 1); //dong
//Arr := VarArrayCreate([1, lcol + 1, 1, lRows + 1],varVariant);
Arr := VarArrayCreate([1, lRows + 1, 1, lcol + 1],varVariant);

Arr[j, 1] := Src[i, 1];
Arr[j, 2] := Src[i, 2];


Des.Resize[j, VarArrayHighBound(Arr, 2)].Value:=Arr;
Cũng code đó bạn viết cho Mình xin Tổng hợp cộng lại cột E theo mã hàng cột B

Về Dic như vậy Cơ bản Mạnh đã học xong ... mai mốt chuyển qua cái khác Mong Bạn chỉ cho mạnh học với nhé

Mỗi một lĩnh vực Mạnh xin 1 code cơ bản vậy là tuyệt Vời .... 6 tháng sau sẻ bắt đầu nhập Môn Delphi ok đó
 
Upvote 0
Web KT
Back
Top Bottom