Đâ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.
Vâng. Hàm InStr có thể dùng bởi hàm Pos hoặc PosEx cảu Delphi rất nhanh, code nguồn Delphi hàm Pos() viết bằng Assemble rất ngọt. Tuy nhiên hàm InStrRev Delphi không viết giúp, mình phải tự viết và dùng vòng lặp và duyệt PChar nên cảm thấy chưa ưng. Nếu lấy được InStrRev em sẽ test để so sánh tốc độ với Delphi. Khi viết Delphi cho Office thì cứ thằng nào ngon nhất ta dùng. Ý em là vậy đó bác .
Lỗi {$ *.Res} không phải là lỗi nghiêm trọng.
Khi bạn tạo project mới thì Delphi tự thêm {$R *.RES}. Bạn chon Save All rồi đóng Delphi. Trên đĩa sẽ có project.res. Nếu bạn xóa project.res rồi mở lại project.dpr thì Delphi sẽ thông báo là không tìm thấy project.res. Nó tìm vì trong unit project.dpr có {$R *.RES}. Và nó hỏi có tạo lại project.res không. Chỉ cần gật đầu là xong. Đây không phải là lỗi nghiêm trọng.
-------
Bạn có nhìn thấy thông báo "CoInitialize has not been called" không?
Thực ra tôi chỉ cài Delphi 5 vì máy 18 tuổi, C có 10 GB, XP Home. Bạn hãy thử như sau.
Trước dòng
Mã:
App := GetActiveOleObject('Excel.Application');
thì thêm dòng
Mã:
if InitProc <> nil then TProcedure(InitProc);
------
Mà chỉ thêm như sau cũng được
Mã:
TProcedure(InitProc);
vì trong ComObj có
Mã:
initialization
begin
...
if not IsLibrary then
begin
SaveInitProc := InitProc;
InitProc := @InitComObj;
end;
end;
Tức InitProc <> nil (InitProc := @InitComObj)
Tức sẽ thực hiện InitComObj
Mã:
procedure InitComObj;
begin
if SaveInitProc <> nil then TProcedure(SaveInitProc);
if (CoInitFlags <> -1) and Assigned(ComObj.CoInitializeEx) then
begin
NeedToUninitialize := Succeeded(ComObj.CoInitializeEx(nil, CoInitFlags));
IsMultiThread := IsMultiThread or
((CoInitFlags and COINIT_APARTMENTTHREADED) <> 0) or
(CoInitFlags = COINIT_MULTITHREADED); // this flag has value zero
end
else
NeedToUninitialize := Succeeded(CoInitialize(nil));
end;
Trường hợp này (nếu tôi không lầm thì trong trường hợp đang nói thì CoInitFlags =-1
Mã:
var
CoInitFlags: Integer = -1; // defaults to no threading model, call CoInitialize()
Lỗi {$ *.Res} không phải là lỗi nghiêm trọng.
Khi bạn tạo project mới thì Delphi tự thêm {$R *.RES}. Bạn chon Save All rồi đóng Delphi. Trên đĩa sẽ có project.res. Nếu bạn xóa project.res rồi mở lại project.dpr thì Delphi sẽ thông báo là không tìm thấy project.res. Nó tìm vì trong unit project.dpr có {$R *.RES}. Và nó hỏi có tạo lại project.res không. Chỉ cần gật đầu là xong. Đây không phải là lỗi nghiêm trọng.
-------
Bạn có nhìn thấy thông báo "CoInitialize has not been called" không?
Thực ra tôi chỉ cài Delphi 5 vì máy 18 tuổi, C có 10 GB, XP Home. Bạn hãy thử như sau.
Trước dòng
Mã:
App := GetActiveOleObject('Excel.Application');
thì thêm dòng
Mã:
if InitProc <> nil then TProcedure(InitProc);
------
Mà chỉ thêm như sau cũng được
Mã:
TProcedure(InitProc);
vì trong ComObj có
Mã:
initialization
begin
...
if not IsLibrary then
begin
SaveInitProc := InitProc;
InitProc := @InitComObj;
end;
end;
Tức InitProc <> nil (InitProc := @InitComObj)
Tức sẽ thực hiện InitComObj
Mã:
procedure InitComObj;
begin
if SaveInitProc <> nil then TProcedure(SaveInitProc);
if (CoInitFlags <> -1) and Assigned(ComObj.CoInitializeEx) then
begin
NeedToUninitialize := Succeeded(ComObj.CoInitializeEx(nil, CoInitFlags));
IsMultiThread := IsMultiThread or
((CoInitFlags and COINIT_APARTMENTTHREADED) <> 0) or
(CoInitFlags = COINIT_MULTITHREADED); // this flag has value zero
end
else
NeedToUninitialize := Succeeded(CoInitialize(nil));
end;
Trường hợp này (nếu tôi không lầm thì trong trường hợp đang nói thì CoInitFlags =-1
Mã:
var
CoInitFlags: Integer = -1; // defaults to no threading model, call CoInitialize()
Làm gì có server Excel nào đang hoạt động mà đòi Get?
Tôi không tin là Tuân không gặp lỗi. Vì Tuân có thể cho code không hẳn như có trên đĩa (vụ vbTextCompare), không hẳn là đúng thực tế, nên khó đoán. Nếu là code đưa trên GPE thì nhất định có lỗi 1.
Debug thì thấy lỗi "EOleSysError: CoInitialize has not been called" nhưng trên cơ sở "Đọc kỹ hdsd trước khi dùng" thì có đến tết Công Gô kieu manh cũng không đoán được phải thêm cái gì. "Đọc kỹ hdsd trước khi dùng" là chung chung chả nói lên cái gì cụ thể.
Làm gì có server Excel nào đang hoạt động mà đòi Get?
Tôi không tin là Tuân không gặp lỗi. Vì Tuân có thể cho code không hẳn như có trên đĩa (vụ vbTextCompare), không hẳn là đúng thực tế, nên khó đoán. Nếu là code đưa trên GPE thì nhất định có lỗi 1.
Debug thì thấy lỗi "EOleSysError: CoInitialize has not been called" nhưng trên cơ sở "Đọc kỹ hdsd trước khi dùng" thì có đến tết Công Gô kieu manh cũng không đoán được phải thêm cái gì. "Đọc kỹ hdsd trước khi dùng" là chung chung chả nói lên cái gì cụ thể.
Cái dòng màu đem như dân quãng ninh kia nhột lắm Anh ... Em mò học mà cứ quăng thế tết tây quá !!!
Mạnh Phán xanh dì 1 câu trên cung trăng có đầy vàng mi cứ lên đó mà lấy ........... vãi kinh hồn nuôn !!!
kieu manh không làm đúng thì sẽ có lỗi "EOleSysError: Operation unavailable". Chỉ cần "Đọc kỹ hdsd trước khi dùng" một lần nữa thì sẽ hết lỗi này.
Nhưng còn lỗi khó hơn là "EOleSysError: CoInitialize has not been called" mà chỉ trên cơ sở "Đọc kỹ hdsd trước khi dùng" thì có đọc đến tết Công Gô kieu manh vẫn không biết phải sửa gì, thêm gì.
Cái dòng màu đem như dân quãng ninh kia nhột lắm Anh ... Em mò học mà cứ quăng thế tết tây quá !!!
Mạnh Phán xanh dì 1 câu trên cung trăng có đầy vàng mi cứ lên đó mà lấy ........... vãi kinh hồn nuôn !!!
Bạn @kieu manh đang làm theo hàm rctTypeName chứ không phải hàm InStrRev anh @batman1 a. Code cả project em để full không che ấy. EM chạy không lỗi gì.
Trong VBA có hàm TypeName() để lấy tên của class hay tên của lớp khai báo control hay các object. Khi các bạn lập trình Delphi cho Excel muốn dùng hàm TypeName không thể được vì nó không cùng môi trường VBA. Giải pháp chúng ta phải biết hàm API nào trong thư viên VBAxxx xuất nó ra đồng thời phải biết tham số để sử dụng. Chúng ta thực sự khó nếu không có tài liệu cung cấp từ nhà lập trình ra vbaxxx.
Nhân chủ đề Undocument API VBA ở bài số #10 tại đây
Cái laptop hư lâu lắc, phải gởi vào thành hồ chứa mưa sữa, mới lấy về. Nên quay lại tiếp với cái gọi là "rờ chxx em" Windows và VBA. Topic này tui sẽ đăng lần lượt những gì cu anh tui phát hiện ra trong quá trình "rờ em" Windows API, DLLs và VBAxxx.dll. Các tips, tricks này sẽ bảo đảm không có...
www.giaiphapexcel.com
Code mà bác CU Anh moi ra nó là C và rất phức tạp đây:
Điều quan trọng là bác @ThangCuAnh đã giúp lấy được tên hàm API của hàm TypeName cùng prototype, tôi viết lại code để chúng ta dùng trong Delphi như sau.
1. Các bạn thao khảo cách dùng bên VB/VBA (mang tính học tập vì trong VBA hàm TypeName đã có.
Option Explicit
#If VBA7 Then
Declare PtrSafe Function rtcTypeName Lib "VBE7.DLL" (v As Variant) As String
#Else
Declare Function rtcTypeName Lib "VBE6.DLL" (v As Variant) As String
#End If
Sub TestTypeNameAPI()
Dim sName As String
sName = rtcTypeName(ActiveCell)
MsgBox StrConv(sName, vbFromUnicode)
End Sub
2. Cách khai báo API hàm rtcTypeName() để dùng trong Delphi. Nếu chúng ta tạo Add-in thì đây là tư liệu quý.
Code dưới đây tôi viết trong chương trình chính dạng Console (màn hình đen trắng). Các bạn làm trình tự như sau.
1. Từ Delphi, tạo application dạng Console (nếu ai có add-in rồi thì chỉ cần code chính của nó).
2. Paste đoạn code dưới đây.
3. Chạy Excel với quyền "Run as administrator"
4. Chạy progam trong Delphi (F9)
Mã:
program Test_VBA_API.dproj;
//This code call function API in VBAxxx "rtcTypeName()". In VBA its name is TypeName()
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Winapi.Windows,
ComObj,
System.Variants;
type
TFuncVBAPI_rtcTypeName = function(var v: OleVariant): PWideChar; stdcall;
var sName: WideString;
h: HMODULE;
pFunc: TFuncVBAPI_rtcTypeName;
App: OleVariant;
v: OleVariant;
begin
try
App := GetActiveOleObject('Excel.Application');
Writeln('Ung dung da ma la', ': ', App.Name);
h := LoadLibrary('C:\Program Files (x86)\Common Files\Microsoft Shared\VBA\VBA7\VBE7.DLL');
try
pFunc := GetProcAddress(h, 'rtcTypeName');
v := App.ActiveCell;
sName := PWideChar(TFuncVBAPI_rtcTypeName(pFunc)(v));
Writeln('Gia tri bien la', ': ', sName);
finally
FreeLibrary(h);
App := Unassigned;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Tóm lại đã hết "EOleSysError: CoInitialize has not been called". Chỉ còn "EOleSysError: Operation unavailable"? Nếu bạn đã khởi động Excel mà còn lỗi này thì có nghĩa là lỗi không còn ở code nữa. Tôi không rõ lắm về các quyền vì tôi chỉ quan tâm tới XP Home của tôi thôi. Nhưng nếu nói về quyền thì theo lôgíc của tôi phải phân quyền cho Project1.exe. Tức run project1.exe với quyền "Run as administrator". Dù sao thì theo tôi lỗi không nằm trong code nữa.
Tóm lại đã hết "EOleSysError: CoInitialize has not been called". Chỉ còn "EOleSysError: Operation unavailable"? Nếu bạn đã khởi động Excel mà còn lỗi này thì có nghĩa là lỗi không còn ở code nữa. Tôi không rõ lắm về các quyền vì tôi chỉ quan tâm tới XP Home của tôi thôi. Nhưng nếu nói về quyền thì theo lôgíc của tôi phải phân quyền cho Project1.exe. Tức run project1.exe với quyền "Run as administrator". Dù sao thì theo tôi lỗi không nằm trong code nữa.
Tóm lại đã hết "EOleSysError: CoInitialize has not been called". Chỉ còn "EOleSysError: Operation unavailable"? Nếu bạn đã khởi động Excel mà còn lỗi này thì có nghĩa là lỗi không còn ở code nữa. Tôi không rõ lắm về các quyền vì tôi chỉ quan tâm tới XP Home của tôi thôi. Nhưng nếu nói về quyền thì theo lôgíc của tôi phải phân quyền cho Project1.exe. Tức run project1.exe với quyền "Run as administrator". Dù sao thì theo tôi lỗi không nằm trong code nữa.
Chạy tới lui các kiểu nó cũng báo cái dòng màu đỏ đó Anh còn lại ko thấy chi hết ... còn tại sao Em Tịt ....!
Em thử chạy cái File Delphi *.exe Run As nó cũng thế