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,651
Đượ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:
Cho mình xem files trong thư mục con sys và win với. Bạn xài RAD Studio gì ?
 
Upvote 0
Không biết nhiêu đó thông tin là đủ chưa ?
Delphi.JPG
 
Upvote 0
OK rồi bạn, giờ bạn chỉ có việc là khi nào rãnh thì gác chân lên bàn, vô thư mục này đọc từng file 1 thôi. Chỗ nào không hiểu thì bỏ qua, sau này đọc lại. Đọc xem gồm có các hàm/procedure/class gì, nó được code ra sao, làm gì...
Ưu tiên các file sau:
1. SysInit.pas: file này khó nhai nhất, core của Delphi và C++Builder app đó.
2. System.pas: chứa các function/procedure của Pascal truyền thống và new Delphi. Nên đọc kỹ, chừng nào thuộc thôi :)
3. SysUtils.pas: nên đọc, nắm hết các function/procedures trong này.
Cậu rành hết 3 file này thôi thì đủ code như ý rồi, không còn hỏi kiểu QuoteStr là gì nữa :p

Mấy file nào mà có Exc hay Exception hay Unwind thì hơi khó nhai với bạn, nó liên quan đến cơ chế exception handling của Windows và implement của Delphi. Giờ tui đọc lại cũng còn lùng bùng đó. Bỏ qua.
Sharemem.pas, SimpleShareMem.pas cũng vậy, khó nhai và khó hiểu được, liên quan đến quản lý memory của Windows và Delphi.
StrHlpr: string helper: nên đọc. Cùng với SysConst và Types.
Cũng nên lướt qua các file .inc. Nó cũng là code Pascal thôi, được include vào.

Làm với Excel và kiểu Variant thì phải, bắt buộc phải đọc kỹ các file này: VarHlpr.pas, Variants.pas và VarUtils.pas

Mấy hàm có inline/builtin assembler thì bỏ qua việc hiểu, chỉ cần nắm cách dùng, mấy hàm về PChar đó, StrPos, StrLen...

Muốn test hàm thì chỉ nên new app console thôi, uses rồi code gọi hàm thắc mắc để test. Tập debug trong IDE đi. Hổ trợ debug trong IDE của Delphi gấp mấy chục lần VB/VBA đấy. Nắm rành nó thôi thì sau này sẽ không sợ bug nào.

Mã:
program Test;

{$APPTYPE CONSOLE}

uses
  ....xxx, yyy, zzz;

begin
   ReadLn...
   WriteLn...
end.

Xong rồi, sau này, thì hảy qua thư mục win, net, các thư mục con của các platform khác. Xong RTL rồi thì nhảy qua VCL, Data...

Nhiêu đây thôi đủ cho cậu nổ não rồi, ở đó mà còn lang thang tìm code. Học được cách code của Borland coders luôn. Guru không đó.
Hồi xưa tui cũng học trong này. Khi nào cậu hiểu sơ sơ được kiểu string trong Delphi là gì, tổ chức trong memory như thế nào, các hàm internal thao tác nó ra sao, cậu sẽ dần dần bỏ, nhảy qua PChar. Vậy là gần tới C rồi đó. string trong Delphi từa tựa như string(BSTR) của VB/VBA.

Chúc học tốt.

PS:À quên, còn 1 mớ file trong thư mục Win nữa, như Classes, TypeInfo, RTTI... cậu úp hình lên luôn đi. Mấy file nào có chữ Type trong đó thì nên đọc sau này để hiểu cách Delph/C++Builder tổ chức, quản lý các object, đối tượng, types...ra sao. Sau này có học "rờ chim em" gặp Delphi app hay mèo nào viết = Delphi thì sẽ dễ hiểu hơn.

Từ Delphi 1 tới giờ, vẫn các file đó. Nó chỉ mở rộng và bổ sung thêm. Thêm 1 mớ file về generic, template cho new Delphi Language sau này nữa.
 
Lần chỉnh sửa cuối:
Upvote 0
File getmem.inc là của cha đẻ của Delphi code đó, coding style của ông ta hơi dị dị :)
Đọc file này nổ não đấy.
 
Upvote 0
thật ra đã lục coi hết ngõ hẻn của nó lâu rồi nhưng cái biết cái không .... xong cái đầu nó u lên mấy cục đó .... vãi lắm
và khi rảnh còn bới cả windows của Bill nữa đó + office tò mò hay thích cái chi là quậy cái đó
 
Upvote 0
Cậu chỉ cần hiểu các unit (file) đó gồm các hàm nào, làm gì thôi đã. Còn sau này rãnh thì coi nó được code ra sao.
 
Upvote 0
TRONG Folder Win có 132 file đó nhiều lắm .... nổ nảo luôn
4.JPG1.JPG2.JPG3.JPG
Bài đã được tự động gộp:

Kiểu này lại học tiếng Em đây... mặc dù phát âm hay ngữ pháp ko ai giống mình nhưng nhìn câu từ cũng đoán mò ra được một chút ===\. -0-0-0-
Capture.JPG
 
Lần chỉnh sửa cuối:
Upvote 0
Đã nói đừng nhảy vào file getmem.inc mà, nhảy vào đó có hiểu gì đâu.
Thôi bỏ qua thư mục win này đi. Đa số files nó là port từ Windows SDK C/C++ header files qua thôi, cũng không có gì coi đâu. Tò mò thì coi thử.
Cậu tìm thêm file Classes.pas, coi file này thôi. Chắc nó nằm trong thư mục common.
Và nhớ xem các file trong thư mục sys trên.
Xong rồi, giờ cậu tìm và chụp cho tui xem 2 hàm sau trong unit nào,được code ra sao: VarArrayHighBound và VarArrayCreate.
Khi nào mà cậu không cần dùng Delphi IDE nữa, soạn code = Notepad hay Notepad++ cậu đang xài đó, ra ngoài command line compile = dcc32 hay dcc64 thì cậu tương đối rành Delphi rồi đó.
 
Lần chỉnh sửa cuối:
Upvote 0
tìm hoài ko thấy: VarArrayHighBound và VarArrayCreate.
Ctrl +F hoài ko ra ??!!! ko biết nó nằm chỗ nào ??

Lâu lâu thấy có cái hàm rất hay ... coi diết hiểu thêm cách nó code If then ... For ... nói chung hay hay
Mã:
function IsBinary(const Input: TStream; const Signatures: array of TBinarySignature): Boolean;
var
  I: Integer;
  Signature: Integer;
  Pos: Integer;
begin
  Pos := Input.Position;
  for I := Low(Signatures) to High(Signatures) do
  begin
    Signature := 0;
    Input.Read(Signature, Min(Signatures[I].SignatureLength, SizeOf(Signature)));
    Input.Position := Pos;
    if Signature = Signatures[I].BinarySignature then
      Exit(True);
  end;
  Result := False;
end;
 

File đính kèm

  • System.Classes.rar
    88.5 KB · Đọc: 3
Upvote 0
Khổ ghê, nó nằm trong mấy file VarXXX.pas, trong thư mục sys đó.
À, nay Delphi có thêm vụ Exit(True) nữa ta, nó tương đương:
Mã:
Result := True;
Exit;
Viết vầy ngắn gọn hơn.
Mấy cái TStream, Txxx trong unit Classes, cậu từ từ ngâm cú sau, giờ tập trung vào thư mục RTL\sys đi. Chừng nào cậu nắm được Object Pascal, phần class rồi quay lại.
 
Lần chỉnh sửa cuối:
Upvote 0
chắc là nó
Capture.JPGm.JPG
 

File đính kèm

  • System.Variants.rar
    30.1 KB · Đọc: 4
Upvote 0
Nó chứ chắc gì nữa, đó là khai báo ở phần interface, vào phần implementation xem nó viết ra sao đi.
 
Upvote 0
Biết tại sao Mạnh lại ôn lại cái mảng Delphi này ko !?:

1/ từ VBA Excel thì mảng nó đóng vai trò rất quan trọng và cho tốc độ nhanh hơn duyệt trên Cells
2/ Khi mạnh lấy dữ liệu Từ Access lên hay Server hầu hết lấy lên mảng tính toán xong làm linh tinh
3/ khi mạnh viết qua VB6 thì nó cũng thế
4/ cách đây mấy năm có vọc VB.net thì nó cũng thế
5/ giờ qua Delphi thì cái mảng nó cũng thế
.....
Vì abcxyz như thế cho nên Mạnh mong muốn học thật kỹ cái mảng Delphi các kiểu xem sao để mà vận dụng là thế ??!!!

Nói chung cái mảng theo ngu ý của Mạnh thì bất cứ tay coder nào cũng phải học thật thuần thục nó các kiểu ... xong vận dụng nó
 
Upvote 0
Đao to búa lớn để sau đi, cậu vào xem 2 cái hàm đó nó viết ra sao chưa ?
1. Nó dùng API gì ?
2. Kiểu dữ liệu VARIANT trên Windows API C/C++ trong Delphi là kiểu gì ?
3. Cậu có thể viết lại 2 hàm đó bằng Delphi, thuần API không ?

Cậu quăng cái code ra, hỏi tôi có cách viết tốt hơn không, thì tới giờ, tôi đã chỉ xong cho cậu cách viết khác đấy. Pure API và sát ở dưới.
Xong....
 
Lần chỉnh sửa cuối:
Upvote 0
Hì hì, à, mà còn cách khác tốt hơn nữa, sâu hơn nữa, mà cậu chưa làm được đâu. Đó là dùng kỹ thuật "rờ em" để đảo ngược hàm API, viết lại = Delphi của cậu, bỏ đi các cái râu ria, không cần thiết. Vd hàm API SafeArrayCreate nằm trong oleaut32.dll của Windows, source của nó có thể tham khảo (tham khảo thôi nhen, không chính xác 100%) ở đây:

À mà sẵn bà 8 chút luôn, tui có đọc sơ qua topic này, thấy cậu hay nói test hàm này hàm kia thì Excel nó bị đơ hay thoát đột ngột luôn. Tức là trong code của cậu bị văng exception ra, cậu không handling nó nên nó trôi tuốt ra ngoài. Nếu là Delphi application thì ở application, Delphi có sinh code để bắt các unhandled exception này, nhưng với Delphi DLL thì không.
Nên khi exception bị quăng ra từ Delphi DLL, không ai bắt nó, nó sẽ quăng ra tới Excel. Do cơ chế xử lý exception của Excel (tức của Visual C++ vì Excel được viết = Visual C++) và Delphi khác nhau, nên Excel sẽ không xử lý được và làm crash.

scrrun.dll mà chúng ta hay dùng class Dictionary, Files, Folders... được viết = VC++, thuần API, VARIANT, BSTR, SAFEARRAY và rất sâu rồi, tốc độ nó đã cực nhanh, khó có thể vượt qua nó, nên dùng TDictionary của Delphi hay các hàm/procedure/ class TxxxStream của Delphi sẽ vẫn không đua lại nổi nó. Vì vậy cứ để bà con dùng VBA trực tiếp với nó, khỏi phải phát minh lại bánh xe to mà chậm hơn.

Cơ chế xử lý lỗi của VB/VBA cũng dựa trên cơ chế exception handling của hệ điều hành Windows, tựa tựa với Visual C++, nên các exception từ các thư viện DLL như scrrun.dll quăng ra, VB/VBA xử lý và catch được.

Nôm na là vậy, cậu hiểu hay không thì tùy.
Cơ chế exception handling trên Windows nó rất phức tạp, thường chỉ dân system coder và dân "rờ em" đào sâu vào nó thôi. Coder ứng dụng thì chỉ cần biết có nó và dùng thôi.
Thật sự ra giờ tui vẫn còn lơ tơ mơ lắm, nói nắm chắc thì không dám nhận.
 
Lần chỉnh sửa cuối:
Upvote 0
Coi diết trong đó thấy Hàm này nó cắn hàm kia nó chạy ... kiểu như thằn lằn cắn đuôi nhau nó chạy thế này .... mò diết mắt nó sẻ sáng ra đó !
Mã:
function VarArrayCreate(const Bounds: array of Integer;
  AVarType: TVarType): Variant;
var
  I, LDimCount: Integer;
  LVarArrayRef: PVarArray;
  LVarBounds: array[0..63] of TVarArrayBound;
begin
  if (not Odd(High(Bounds)) or (High(Bounds) > 127)) or
     (not VarTypeIsValidArrayType(AVarType)) then
    VarArrayCreateError;

  LDimCount := (High(Bounds) + 1) div 2;
  for I := 0 to LDimCount - 1 do
    with LVarBounds[I] do
    begin
      LowBound := Bounds[I * 2];
      ElementCount := Bounds[I * 2 + 1] - LowBound + 1;
    end;

  LVarArrayRef := SafeArrayCreate(AVarType, LDimCount, PVarArrayBoundArray(@LVarBounds));
  if LVarArrayRef = nil then
    VarArrayCreateError;

  _VarClear(TVarData(Result));

  TVarData(Result).VType := AVarType or varArray;
  TVarData(Result).VArray := LVarArrayRef;
end;
Mã:
function VarArrayOf(const Values: array of Variant): Variant;
var
  I: Integer;
begin
  Result := VarArrayCreate([0, High(Values)], varVariant);
  for I := 0 to High(Values) do
    Result[I] := Values[I];
end;
Mã:
function VarArrayDimCount(const A: Variant): Integer;
var
  LVarType: TVarType;
  LVarArray: PVarArray;
begin
  if GetVarDataArrayInfo(TVarData(A), LVarType, LVarArray) then
    Result := LVarArray^.DimCount
  else
    Result := 0;
end;

function VarArrayLowBound(const A: Variant; Dim: Integer): Integer;
begin
  VarResultCheck(SafeArrayGetLBound(VarArrayAsPSafeArray(A), Dim, Result));
end;

function VarArrayHighBound(const A: Variant; Dim: Integer): Integer;
begin
  VarResultCheck(SafeArrayGetUBound(VarArrayAsPSafeArray(A), Dim, Result));
end;
Giải thích dùm mạnh tại sao nó có 2 procedure giống nhau và nó chạy theo cơ chế nào ??!! chưa hiểu .... có đọc trang gì đó trong Delphi nó cho phép như vậy nhưng cái gì đó quên mất tiêu ròi hehehe ;)
Mã:
procedure VarResultCheck(AResult: HRESULT); overload;
begin
  if AResult <> VAR_OK then
    TranslateResult(AResult);
end;

procedure VarResultCheck(AResult: HRESULT; ASourceType, ADestType: TVarType); overload;
begin
  if AResult <> VAR_OK then
    case AResult of
      VAR_TYPEMISMATCH:  VarCastError(ASourceType, ADestType);
      VAR_OVERFLOW:      VarOverflowError(ASourceType, ADestType);
    else
      TranslateResult(AResult);
    end;
end;
Mạnh có coi mấy trang tây nó viết cái hàm chuyển mãng đó còn dài dòng và rắc rối hơn mạnh đã viết .... vãi kinh :p
 
Lần chỉnh sửa cuối:
Upvote 0
Coi diết trong đó thấy Hàm này nó cắn hàm kia nó chạy ... kiểu như thằn lằn cắn đuôi nhau nó chạy thế này .... mò diết mắt nó sẻ sáng ra đó !
Mã:
function VarArrayCreate(const Bounds: array of Integer;
  AVarType: TVarType): Variant;
var
  I, LDimCount: Integer;
  LVarArrayRef: PVarArray;
  LVarBounds: array[0..63] of TVarArrayBound;
begin
  if (not Odd(High(Bounds)) or (High(Bounds) > 127)) or
     (not VarTypeIsValidArrayType(AVarType)) then
    VarArrayCreateError;

  LDimCount := (High(Bounds) + 1) div 2;
  for I := 0 to LDimCount - 1 do
    with LVarBounds[I] do
    begin
      LowBound := Bounds[I * 2];
      ElementCount := Bounds[I * 2 + 1] - LowBound + 1;
    end;

  LVarArrayRef := SafeArrayCreate(AVarType, LDimCount, PVarArrayBoundArray(@LVarBounds));
  if LVarArrayRef = nil then
    VarArrayCreateError;

  _VarClear(TVarData(Result));

  TVarData(Result).VType := AVarType or varArray;
  TVarData(Result).VArray := LVarArrayRef;
end;
Mã:
function VarArrayOf(const Values: array of Variant): Variant;
var
  I: Integer;
begin
  Result := VarArrayCreate([0, High(Values)], varVariant);
  for I := 0 to High(Values) do
    Result[I] := Values[I];
end;
Mã:
function VarArrayDimCount(const A: Variant): Integer;
var
  LVarType: TVarType;
  LVarArray: PVarArray;
begin
  if GetVarDataArrayInfo(TVarData(A), LVarType, LVarArray) then
    Result := LVarArray^.DimCount
  else
    Result := 0;
end;

function VarArrayLowBound(const A: Variant; Dim: Integer): Integer;
begin
  VarResultCheck(SafeArrayGetLBound(VarArrayAsPSafeArray(A), Dim, Result));
end;

function VarArrayHighBound(const A: Variant; Dim: Integer): Integer;
begin
  VarResultCheck(SafeArrayGetUBound(VarArrayAsPSafeArray(A), Dim, Result));
end;
Giải thích dùm mạnh tại sao nó có 2 procedure giống nhau và nó chạy theo cơ chế nào ??!! chưa hiểu .... có đọc trang gì đó trong Delphi nó cho phép như vậy nhưng cái gì đó quên mất tiêu ròi hehehe ;)
Mã:
procedure VarResultCheck(AResult: HRESULT); overload;
begin
  if AResult <> VAR_OK then
    TranslateResult(AResult);
end;

procedure VarResultCheck(AResult: HRESULT; ASourceType, ADestType: TVarType); overload;
begin
  if AResult <> VAR_OK then
    case AResult of
      VAR_TYPEMISMATCH:  VarCastError(ASourceType, ADestType);
      VAR_OVERFLOW:      VarOverflowError(ASourceType, ADestType);
    else
      TranslateResult(AResult);
    end;
end;
Mạnh có coi mấy trang tây nó viết cái hàm chuyển mãng đó còn dài dòng và rắc rối hơn mạnh đã viết .... vãi kinh :p

Có lẽ ý của bác ThangCuAnh muốn bạn biết về ngôn ngữ Pascal là trước tiên, và biết được nguyên lý làm việc vơi các hàm API của Delphi để bạn hiểu cách viết code là chính? Chứ vào việc cụ thể thì đã có các hàm hỗ trợ với một hai vòng lặp là xong rôi.
 
Upvote 0
Uhm, ngộ ra từ từ rồi đó. Cứ gác chân lên bàn mà nhâm nhi, nhảy tới nhảy lui trong source mà coi.
Mã:
procedure VarArrayCreateError;
begin
  raise EVariantArrayCreateError.Create(SVarArrayCreate);
end;
Bạn Mạnh chú ý chổ này, nếu có lỗi trong hàm VarArrayCreate, exception EVariantArrayCreateError sẽ được raise.
Nên ở ngoài, nếu call hàm này, để chắc chắn, phải try/except on xxx để catch exception này, không thì nó throw tuốt luốt ra ngoài cùng luôn.

À, overload đó hả. Tính năng này mượn từ C++ qua, cho phép các hàm/procedure cùng tên, nhưng bắt buộc phải khác tham số. Nôm na vậy thôi. Nên cậu thấy có 2 hàm VarResultCheck đó, nhưng parameter khác nhau đó, thấy không ?

Sâu xa hơn nữa thì nó liên quan tới Delphi compiler và Borland C++ name mangling. Nói ra dài dòng. Cứ hiểu overload, overwrite vậy là được đủ dùng rồi.

Vì vậy tui mới nói cậu chịu khó học lại ngôn ngữ Pascal, Object Pascal đã. Rồi phải biết cách dùng Pointer, PChar để thao tác với API.
 
Lần chỉnh sửa cuối:
Upvote 0
Uhm, ngộ ra từ từ rồi đó. Cứ gác chân lên bàn mà nhâm nhi, nhảy tới nhảy lui trong source mà coi.
Mã:
procedure VarArrayCreateError;
begin
  raise EVariantArrayCreateError.Create(SVarArrayCreate);
end;
Bạn Mạnh chú ý chổ này, nếu có lỗi trong hàm VarArrayCreate, exception EVariantArrayCreateError sẽ được raise.
Nên ở ngoài, nếu call hàm này, để chắc chắn, phải try/except on xxx để catch exception này, không thì nó throw tuốt luốt ra ngoài cùng luôn.

À, overload đó hả. Tính năng này mượn từ C++ qua, cho phép các hàm/procedure cùng tên, nhưng bắt buộc phải khác tham số. Nôm na vậy thôi. Nên cậu thấy 2 hàm VarResultCheck đó, nhưng parameter khác nhau đó, thấy không ?

Sâu xa hơn nữa thì nó liên quan tới Delphi compiler và Borland C++ name mangling. Nói ra dài dòng. Cứ hiểu overload, overwrite vậy là được đủ dùng rồi.
Cái này bị đơ hoài nên ngộ ra rồi .... xử lý tạm ok
 
Upvote 0
À, giờ mới để ý, Embarcadero coder hay dùng tiền tố L cho các biến local trong hàm hen ! Vụ này mới à nhen
 
Upvote 0
Web KT
Back
Top Bottom