Undocument Windows API và VBA

Liên hệ QC

ThangCuAnh

Mới rờ Ét xeo
Tham gia
1/12/17
Bài viết
896
Được thích
792
Giới tính
Nam
Nghề nghiệp
Coder nghỉ hưu, RCE dạo
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ó trên ông "Gấu gồ". Và dùng được cho VBA trên Offices. Chứ "ưn đồ cú mèn" API mà chỉ dùng được cho C/C++, Delphi... thì dân tin học VP ở đây thua.
Tui chỉ sẽ tập trung ở các Windows DLL sau: kernel32.dll, shell32.dll, shlwapi.dll, oleaut32.dll, ole32.dll, advapi32.dll... và 1 ít từ ntdll.dll (core usermode API của Windows). Trên VBExxx.dll thì tui chỉ tập trung vào VBE6 của Office 2007, VBE7 của Office2010 32 và 64bit, các VBExxx.dll khác cũng sẽ gần như tương đượng, không khác nhau mấy.
 
Lần chỉnh sửa cuối:
Bạn @kieu manh hỏi bác @Nguyễn Duy Tuân ấy, dùng ra sao !?
Tiếp tục với hàm unsigned int __stdcall StrLenChk(unsigned int nLen) này, hay tức là hằng 0x3FFFFFFF (1073741823) này.
Trong các VBExxx.dll 32bit, hàm này là hàm riêng, còn trên các VBExxx.dll 64bit, hàm này được inline compiled vào trực tiếp hàm caller.
Có rất nhiều các hàm VBA đều phải dùng hàm StrLenChk này. Ví dụ các hàm sau:
1. String$ = rtcStringBstr
2. String = rctStringVar
3. InStr với param truyền vào là kiểu string = _vbaInStr
4. InStr với param truyền vào là kiểu Variant = __vbaInStrVar
5. 1 đống các hàm InStr với tham số truyền vào là các kiểu khác như Char, __vbaInStrVarB
6. Hàm VBA InStr gốc ở ngoài = rtcInStr
7. Các VBA Input statement
8. Các hàm VBA Mid, Mid$, statement Mid, Mid$
....
Và rất rất nhiều nữa, các hàm A gọi hàm B, B gọi C, C gọi StrLenChk, đều văng Err.Number 5 lên hết.
Nên thôi, viết ra quá dài dòng, nhiều không xuể, nên các bác cứ nhớ giúp cu anh tui là với VBA, cái nào mà đòi hỏi, nhận tham số là số ký tự hay truyền vào Len string thì luôn luôn phải nhỏ hơn 0x3FFF FFFFF (&H3FFF FFFF: VBA, $3FFFF FFFF: Delphi, hay 1073741823 decimal). Vậy thôi. Coder MS code cái VBA DLLs nó đã quy định như vậy rồi.

Hì hì, mà nó quy định vậy là đúng đó, không phải sai hay document của MS nó sai đâu. Đố ai tìm ra được tại sao có cái hằng 0x3FFFFFFF này ???? Tui cũng chợt nhớ ra tối qua thôi, lúc tắm :)

@Nguyễn Duy Tuân: nick tui không phải là Cù Anh, hay Cù Anh Thắng mà hồi xưa nhiều báo đăng, nó đọc bình dân, nhà quê là Thằng Cu Anh thôi :p
Với lại nếu bác mang code rtcTypeName cho Delphi vào Addin Tools của bác, bác check xem thử là ở những điều kiện nào VBE6/7.dll không được Excel load lên, như disable Macro, disable ActiveX... Mà tui cũng nghĩ, cái AddIn Tools của bác mà lên được thì 100% chắc chắn VBExxx.dll đã load lên rồi :)

Vâng, các hàm API trong VBAxxx mà bác khai thác cho các ứng dụng add-in là rất hay vì các hàm đó rất tốt hoặc đỡ cực nhọc viết lại. List ra danh dách các function thì có tool nhưng tìm được prototype thì rất khó lại "nội suy" từ Assempler ra C nữa thì có lẽ rất rất ít người làm được như bác @ThangCuAnh (Cu Anh) đó :) .

MS coder đưa ra cái giới hạn MAX_LEN=0x3FFFFFFF ( có lẽ đoán là StringType trong VB quy định độ đài tối đa là 2^31 (dec: 2147483648). Trong môi trường VBA ký tự đưa vào ở dạng ANSI - 1 byte vì thế nó đưa ra giới hạn 1073741823 để khi chuyển đổi sang unicode 2 byte cho 1 ký tự. Khi đó giải quyết với unicode tối đa số ký tự sẽ là 1073741823*2 = 2147483646, thiếu so với 2^31 là 2 byte, lý do trong C API nó tự thêm một ký tự ở cuối chuỗi CHR(0) gọi là NUL terminated. Vậy tính tất tần tật nó đùng bằng độ dài tối đa 2^31. Tài liệu MS nói là đúng :).

Trong VBA nó có hằng số định hướng biên dịch VBA7 với cách điều hướng #If VBA Then... và ta tùy ý đổi giữa VBA6xxx hoặc VBA7xxx. Vấn đề sử dụng API từ ngôn ngữ ngoài thì phải dùng LoadLibrary("file dll"). Và chúng ta kết hợp dùng GetProcAddress() để lấy con trỏ hàm. Như vậy chỉ càn biết mã phiên bản Application.Version là điều hướng được.

Từ vấn đề LoadLibrary("file dll") em muốn hỏi bác là, khi VBAxxx đã load rồi thì làm sao tìm được hMODULE của nó để đưa thẳng vào GetPrcAddress. Làm như vậy sẽ không cần phải check mã phiên bản ứng dụng mẹ là Excel. VBAxxx đã được Excel load khi khởi động nên ta có thể tận dụng cái này như thế nào?

Đề xuất thứ hai nhờ bác tìm cái prototype của hàm INSTR và INSTRREV để em "sờ" tiếp :) . Ah. cái sp của em là "Add-in A-Tools" (có chữ s cuối cùng bác a :p )
 
Upvote 0
Bác Tuân muốn trên 32 hay 64bit ?
Nhờ các bác test giùm cu anh tui file này, xem giới hạn của SysAllocStringLen API trên Windows và máy các bác là bao nhiêu.
Theo lý thuyết, MS document thì trên 32bit là MAX_UINT = 0xFFFFFFFF nhưng hoàn toàn không phải vậy, nhỏ hơn nhiều.
Có 2 sub Test_xxx, các bạn chạy và chịu khó chờ xem ra kết quả bao nhiêu nhé. Máy càng mạnh, càng bộ nhớ nhiều càng tốt.
Thông tin máy:

222130

Office 365
Kết quả test như sau:

 
Upvote 0
Cảm ơn bác @Hai Lúa Miền Tây, vậy là Win64 nó vượt qua ngưỡng SysAllocStringByLen 0x3FFFFFFF hết đó, nhẹ nhàng. Win32 thì may rủi, ì ạch thôi, đa số là gần 1 GB là văng.
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn bác @Hai Lúa Miền Tây, vậy là Win64 nó vượt qua ngưỡng SysAllocStringByLen 0x3FFFFFFF hết đó, nhẹ nhàng. Win32 thì may rủi, ì ạch thôi, đa số là cỡ 1 GB là văng.

Không hoàn toàn do Windows đâu. Windows 64-bit và đi cùng Excel 64-bit về cơ bản là đạt bộ nhớ tốt nhất. Tuy nhiên Excel có sự dịch chuyển về cấp pháp bộ nhớ tùy vào hiện trạng của nó. Em cũng Windows 64-bit, Excel 64-bit nhưng văng nhé. Vụ này em có kinh nghiệm vì vấp nhiều :) .
 
Upvote 0
Phiền admin xóa giùm topic này, vì nó nhiều tiểu tiết quá, phải chụp hình, post code, giải thích rất nhiều. Nên thôi. Để dịp khác, nhả tơ từ từ thôi.
Giờ quay lại cho xong cái patch VBExxx.dll đã. Chứ chưa cái nào xong cái nào.
Từ từ làm cũng được bạn, đề tài này cũng khá hay, được sự quan tâm của nhiều thành viên. Sao phải xóa? Cố gắng tiếp tục nhé bạn.
 
Upvote 0
Không hoàn toàn do Windows đâu. Windows 64-bit và đi cùng Excel 64-bit về cơ bản là đạt bộ nhớ tốt nhất. Tuy nhiên Excel có sự dịch chuyển về cấp pháp bộ nhớ tùy vào hiện trạng của nó. Em cũng Windows 64-bit, Excel 64-bit nhưng văng nhé. Vụ này em có kinh nghiệm vì vấp nhiều :) .
Thật ra khi chạy code đó đầu tiên trên máy của em nó bị văng ra và MS Office 365 đưa ra thông báo cập nhật phiên bản. Sau khi cập nhật xong thì chạy được kết quả như clip đăng ở trên.
 
Upvote 0
Các hàm Trim, LTrim, RTrim, Trim$, LTrim$, RTrim$ của VBA ngoài remove character space (0x20) còn remove luôn cả ký tự Unicode 0x3000. Chỉ 2 ký tự này.
 

File đính kèm

  • Untitled.png
    Untitled.png
    17.5 KB · Đọc: 18
Upvote 0
Sao giờ mới thấy post của bạn Tuân nhỉ. Dùng GetModuleHandle đó bạn. GetModuleHandle('vbe6.dll') không được, không phải Office 2007 trở xuống, lấy tiếp GetModuleHandle('vbe7.dll'). Chắc chắn phải return được HInstance của VBEx.dll thôi. 2019 của @befaint cũng VBE7.dll đó.

Chưa biết chừng nào tới VBE8.dll :p
Thôi can bác Tuân dùng hàm InStrRev, Delphi thắng chắc rồi. Nó có 1 hàm internal, không có function name, làm mọi việc phức tạp quá mức cần thiết.
Prototype nó đây:
Mã:
UINT __stdcall rtcInStrRev(LPWSTR pwszSrc, LPWSTR pwszFind, int nStart, UINT nCompareMode)
{
    LCID l_locale; // edi@1
    UINT l_nCompareMode; // ebx@1
    int nLenSrc; // esi@6
    UINT result; // eax@10

    l_locale = nCompareMode;
    l_nCompareMode = 1;
    if ( nCompareMode != 1 && nCompareMode )
    {
        if ( !CheckValidLocale(nCompareMode) )
        {
            EbRaiseExceptionCode(5);
        }
    }
    else
    {
        l_nCompareMode = nCompareMode;
        l_locale = rtUserDefaultLCID();
    }
    nLenSrc = nStart;
    if ( !nStart || nStart < -1 )
    {
        EbRaiseExceptionCode(5);
    }
    if ( !pwszSrc )
    {
        return 0;
    }
    if ( nStart == -1 )
    {
        nLenSrc = *((_DWORD *)pwszSrc - 1) >> 1;
    }
    else if ( (unsigned int)nStart > *((_DWORD *)pwszSrc - 1) >> 1 )
    {
        return 0;
    }
    if ( pwszFind )
    {
        result = InternalFunc_Unknown(pwszSrc, pwszFind, nLenSrc, l_locale, (void *)l_nCompareMode);
    }
    else
    {
        result = nLenSrc;
    }
    return result;
}
 
Lần chỉnh sửa cuối:
Upvote 0
Bác Tuân giải thích về vụ 0x3FFFFFFFF là đúng rồi đó.
Thử test hàm rtcInStrRev này với hàm Pos của Delphi và StrPos PChar của Delphi xem, xem thằng nào nhanh hơn, bao nhiêu %.
Và xem thử hàm Trim của Delphi nó có hơn VBA không ?

VBA vậy là không code multithread được hay code multithread không an toàn rồi. Nó dùng biến toàn cục cho các hàm rtcXXXVar nhiều quá.
Ví dụ biến này, share cho 180 hàm gọi. Kinh. Variant 0 đó.
 

File đính kèm

  • Untitled.png
    Untitled.png
    19.2 KB · Đọc: 10
Lần chỉnh sửa cuối:
Upvote 0
Sao giờ mới thấy post của bạn Tuân nhỉ. Dùng GetModuleHandle đó bạn. GetModuleHandle('vbe6.dll') không được, không phải Office 2007 trở xuống, lấy tiếp GetModuleHandle('vbe7.dll'). Chắc chắn phải return được HInstance của VBEx.dll thôi. 2019 của @befaint cũng VBE7.dll đó.

Chưa biết chừng nào tới VBE8.dll :p
Thôi can bác Tuân dùng hàm InStrRev, Delphi thắng chắc rồi. Nó có 1 hàm internal, không có function name, làm mọi việc phức tạp quá mức cần thiết.
Prototype nó đây:
Mã:
UINT __stdcall rtcInStrRev(LPWSTR pwszSrc, LPWSTR pwszFind, int nStart, UINT nCompareMode)
{
    LCID l_locale; // edi@1
    UINT l_nCompareMode; // ebx@1
    int nLenSrc; // esi@6
    UINT result; // eax@10

    l_locale = nCompareMode;
    l_nCompareMode = 1;
    if ( nCompareMode != 1 && nCompareMode )
    {
        if ( !CheckValidLocale(nCompareMode) )
        {
            EbRaiseExceptionCode(5);
        }
    }
    else
    {
        l_nCompareMode = nCompareMode;
        l_locale = rtUserDefaultLCID();
    }
    nLenSrc = nStart;
    if ( !nStart || nStart < -1 )
    {
        EbRaiseExceptionCode(5);
    }
    if ( !pwszSrc )
    {
        return 0;
    }
    if ( nStart == -1 )
    {
        nLenSrc = *((_DWORD *)pwszSrc - 1) >> 1;
    }
    else if ( (unsigned int)nStart > *((_DWORD *)pwszSrc - 1) >> 1 )
    {
        return 0;
    }
    if ( pwszFind )
    {
        result = InternalFunc_Unknown(pwszSrc, pwszFind, nLenSrc, l_locale, (void *)l_nCompareMode);
    }
    else
    {
        result = nLenSrc;
    }
    return result;
}

Việc gọi hModule với việc chỉ định tên DLL thì không khó, ý em là khi Excel đã load VBAxxx dll rồi thì có cách nào chộp nó trong đâu đó không :). Cái này có vẻ cá khoai.

Việc check VBA7 hay VBA6 em làm dựa theo version Excel đang chạy vì phiên bản DLL nó phải ăn theo ứng dụng mẹ mới chính xác. Vì có một số máy tính cài ít nhất 2 loại Excel. Ví dụ cả Excel 2003, 2016 :).

Với hàm InStrRev, theo prototype hai tham số đầu là LPWSTR. Trong Delphi, unit WinAPI.Windows định kiểu LPWSTR = PWideChar. Nếu khai báo theo y nguyên kiểu đó sang Delphi là sai mà bên Delphi phải chuyển sang WideString mới chạy đúng bác à. Không biết bác dịch ngược cái tên kiểu có hoàn toàn chính xác không?
 
Upvote 0
Bác Tuân cứ đúng theo prototype mà làm, vì nó code = C nên tất cả đều là Pointer. Thực ra hàm nó nhận vào parameter là kiểu BSTR đó. Nhưng viết vậy khó dùng cho bác và người khác, nên mình đổi thành PWideChar (LPWSTR).
 
Upvote 0
Bác Tuân giải thích về vụ 0x3FFFFFFFF là đúng rồi đó.
Thử test hàm rtcInStrRev này với hàm Pos của Delphi và StrPos PChar của Delphi xem, xem thằng nào nhanh hơn, bao nhiêu %.
Và xem thử hàm Trim của Delphi nó có hơn VBA không ?

VBA vậy là không code multithread được hay code multithread không an toàn rồi. Nó dùng biến toàn cục cho các hàm rtcXXXVar nhiều quá.
Ví dụ biến này, share cho 180 hàm gọi. Kinh. Variant 0 đó.

Em đã chuyển sang Delphi các hàm bâc gửi, em sẽ report tốc độ sau nhé. Thank bác.
Không viết được Multithread trong VBA bác à. Hoặc muốn viết để chạy dạng multithread trong VBA thì phải viết trong DLL ngoài và không dùng tới các hàm VBA.
Bài đã được tự động gộp:

Bác Tuân cứ đúng theo prototype mà làm, vì nó code = C nên tất cả đều là Pointer. Thực ra hàm nó nhận vào parameter là kiểu BSTR đó. Nhưng viết vậy khó dùng cho bác và người khác, nên mình đổi thành PWideChar (LPWSTR).

Em lập trình ứng dụng kết nối tới Application Server nên hiểu mấy kiển dữ liệu API này nên em mới biết và tự chuyển từ LPWSTR - > WideString (BSTR). Nên em hỏi bác là gốc trong C nó để kiểu gì mà sao lại không tương thích ở Delphi khi dùng tên nguyên vậy á.
 
Upvote 0
Hì hì, thấy bác Tuân nắm về Pointer hơi yếu đấy :)
Thực ra ở phương diện mã máy (Assembly) nó cũng không biết Pointer là gì đâu, nó chỉ đơn giản là số, là địa chỉ của vùng nhớ thôi. Truyền ULong (x32) hay ULongLong (64) vào cũng chả chết.
BSTR cũng là pointer tới 1 vùng nhớ WideChar NULL terminated, khác cái là trước vùng nhớ đó 4 bytes (x32) hay 8 bytes (x64) len thôi.
Bác xem source là biết, truyền gì cũng được, miễn là có xxx bytes len đằng trước, theo kiểu BSTR.
 
Upvote 0
Hì hì, thấy bác Tuân nắm về Pointer hơi yếu đấy :)
Thực ra ở phương diện mã máy (Assembly) nó cũng không biết Pointer là gì đâu, nó chỉ đơn giản là số, là địa chỉ của vùng nhớ thôi. Truyền ULong hay ULongLong (64) vào cũng chả chết.

ke ke. Bác cứ thử dùng PWideChar trong hàm rtcInStrRev sẽ ra kết quả sai ngay. Nhưng dùng sang WideString mới trả về kết quả đúng.

Mã:
type
  TFuncVBAPI_rtcInStrRev = function(StringCheck: LPWSTR ;
                                    StringMatch: LPWSTR ;
                                    const Start: Longint = -1;
                                    const Compare: Longint  = vbBinaryCompare): Longint; stdcall;

Hoặc
TFuncVBAPI_rtcInStrRev = function(StringCheck: PWideChar;
                                    StringMatch: PWideChar;
                                    const Start: Longint = -1;
                                    const Compare: Longint  = vbBinaryCompare): Longint; stdcall;

Đều cho ra kết quả sai.

Nhưng đưa về dạng này thì đúng

Mã:
type
  TFuncVBAPI_rtcInStrRev = function(StringCheck: WideString;
                                    StringMatch: WideString;
                                    const Start: Longint = -1;
                                    const Compare: Longint  = vbBinaryCompare): Longint; stdcall;

Bác giải thích sao về pointer ở trên?
 
Upvote 0
Lại ông nội Delphi chuyển kiểu ngầm nữa rồi. Bác chịu khó debug vào mã assembly của hàm rtcInStrRev đi, xem tại sao sai. Chứ tui không có cài Delphi ở đây nên không debug được.
Bác xem trong memory, biến truyền vào có theo cấu trúc BSTR không ? Nếu đúng thì truyền sao miễn đúng vậy là được (Pointer, UInt, Cardinal....)
Xem trong memory 1 biến kiểu WideString nó cấu trúc ra sao ?
Vì mình code C/C++ và Assembly nên cách nhìn của mình nó khác. Bạn Tuân cũng có thể khai báo StringCheck: Cardinal; StringMatch: Cardinal... cũng được, không sao cả, nhưng khi call thì @ vào, và vùng nhớ truyền điạ chỉ vào phải có cấu trúc của BSTR.
Pointer, PChar, PXXXX đều là diễn giải về mặt language cho coder thôi, chứ biên dịch ra mã máy rồi, nó chỉ đơn thuần là số.
 
Upvote 0
Tiếp tục với 2 hàm Upper và Lower, không có gì đặc biệt, chỉ là wrap cho SysAllocStringLen và CharUpper/CharLower API.
Hì hì, tìm ra điểm sai của VBA coder rồi. Và tìm ra lý do tại sao đụng tới tên file Unicode là VBA văng.
Lỗi do VBA code call các hàm API thuần Ansi cho các thao tác file, truyền vào parameter là Unicode string, convert = WideCharToMultiBytes nên sai bét.
Vd tui đang xem hàm VBA Kill = rtcKillFiles. Dùng toàn các hàm Ansi API và của char* của msvcrt.dll
Cái này bà con test thử đi nhé, gõ 1 tên file Unicode đã có vào 1 cell, truyền vào cho VBA, call hàm Kill. Nhớ bẫy lỗi On Error...
Các hàm về Directory cũng vậy, Ansi hết, chà chà....
Bài đã được tự động gộp:

Toàn bộ các hàm VBA về thao tác file, directory... đều là Ansi hết các bạn ơi. Đụng tới tên Unicode file/dir là văng hết đấy. Dùng Scripting thay thế đi.
Tai hại ghê nhỉ, tại sao VBA coder lại duy trì cái code này mà không port qua Unicode API nhỉ ?
 

File đính kèm

  • Untitled.png
    Untitled.png
    30.6 KB · Đọc: 14
Lần chỉnh sửa cuối:
Upvote 0
Mã:
type
  TFuncVBAPI_rtcInStrRev = function(StringCheck: LPWSTR ;
                                    StringMatch: LPWSTR ;
                                    const Start: Longint = -1;
                                    const Compare: Longint  = vbBinaryCompare): Longint; stdcall;

Hoặc
TFuncVBAPI_rtcInStrRev = function(StringCheck: PWideChar;
                                    StringMatch: PWideChar;
                                    const Start: Longint = -1;
                                    const Compare: Longint  = vbBinaryCompare): Longint; stdcall;
Đều cho ra kết quả sai.
Vẫn được.

Bạn thử xem
Mã:
type
  TFuncVBAPI_rtcInStrRev = function(StringCheck: PWideChar;
                                    StringMatch: PWideChar;
                                    const Start: Longint = -1;
                                    const Compare: Longint  = 0): Longint; stdcall;
...
a: Longint;
w1, w2: WideString;
..
w1 := 'hichic\hehe\hihi';
w2 := '\';
...
@pFunc := GetProcAddress(h, 'rtcInStrRev');
a := pFunc(PWideChar(w1),PWideChar(w2));
showmessage(inttostr(a));
Trong Delphi không có vbBinaryCompare :D
 
Upvote 0
Tiếp tục với 2 hàm Upper và Lower, không có gì đặc biệt, chỉ là wrap cho SysAllocStringLen và CharUpper/CharLower API.
Hì hì, tìm ra điểm sai của VBA coder rồi. Và tìm ra lý do tại sao đụng tới tên file Unicode là VBA văng.
Lỗi do VBA code call các hàm API thuần Ansi cho các thao tác file, truyền vào parameter là Unicode string, convert = WideCharToMultiBytes nên sai bét.
Vd tui đang xem hàm VBA Kill = rtcKillFiles. Dùng toàn các hàm Ansi API và của char* của msvcrt.dll
Cái này bà con test thử đi nhé, gõ 1 tên file Unicode đã có vào 1 cell, truyền vào cho VBA, call hàm Kill. Nhớ bẫy lỗi On Error...
Các hàm về Directory cũng vậy, Ansi hết, chà chà....
Bài đã được tự động gộp:

Toàn bộ các hàm VBA về thao tác file, directory... đều là Ansi hết các bạn ơi. Đụng tới tên Unicode file/dir là văng hết đấy. Dùng Scripting thay thế đi.
Tai hại ghê nhỉ, tại sao VBA coder lại duy trì cái code này mà không port qua Unicode API nhỉ ?

VBA chỉ hỗ trợ unicode với các hàm xử lý chuỗi - có quan hệ mật thiết với dữ liệu trên sheet. Các hàm tương tác ngoài thì gần như không hỗ trợ unicode như các hàm anh nói. Shell, Dir, ChDir, MkDir,... trong module VBA.FileSystem. Vấn đề MS không chuyển full unicode trong VBA chắc họ thích mối lái với các công nghệ ngoài của họ :D
Bài đã được tự động gộp:

Vẫn được.

Bạn thử xem
Mã:
type
  TFuncVBAPI_rtcInStrRev = function(StringCheck: PWideChar;
                                    StringMatch: PWideChar;
                                    const Start: Longint = -1;
                                    const Compare: Longint  = 0): Longint; stdcall;
...
a: Longint;
w1, w2: WideString;
..
w1 := 'hichic\hehe\hihi';
w2 := '\';
...
@pFunc := GetProcAddress(h, 'rtcInStrRev');
a := pFunc(PWideChar(w1),PWideChar(w2));
showmessage(inttostr(a));
Trong Delphi không có vbBinaryCompare :D

Em tự dò hằng số bên VBA để tạo bên Delphi với const vbBinaryCompare = 0 :D

Nếu khai báo theo đúng Prototype LPWSTR thì vẫn đúng với điều kiện khi truyền vào là biến kiểu WideString vào tham số bằng cách bao LPWSTR, em cũng test tình huống này ok. Nhưng nếu unit này mình viết sau đó dùng với kiểu điền giá trị không qua biến như sau sẽ bị sai

p := pFunc('hichic\hehe\hihi', '\') thì kết quả lại sai :D

Nên nếu Prototype em để WideString thay cho LPWSTR thì dùng kiểu gì cũng đúng :).
 
Lần chỉnh sửa cuối:
Upvote 0
Khổ ghê, kg như C, ép kiểu trong Dekphi, cũng 1 đống hàm internal được Delphi chèn vào đó.
Nên tui mới nói các bạn bật option build with dcu lên, và tập debug trên cửa sổ Assembly, xem tương quan 1 - 1 giữa code Delphi và ASM, xem Delphi compiler đã làm những gì với code của mình.
Tin tui đi. Nhớ kg lầm thì ép kiểu PWideChar(WideString biến) cũng phải qua hàm internal _UStrToPWChar đó. Hàm này được compiler chèn vào tự động.
Kiểu này phải cài RAD Studio lại quá.
 
Upvote 0
Khổ ghê, kg như C, ép kiểu trong Dekphi, cũng 1 đống hàm internal được Delphi chèn vào đó.
Nên tui mới nói các bạn bật option build with dcu lên, và tập debug trên cửa sổ Assembly, xem tương quan 1 - 1 giữa code Delphi và ASM, xem Delphi compiler đã làm những gì với code của mình.
Tin tui đi. Nhớ kg lầm thì ép kiểu PWideChar(WideString biến) cũng phải qua hàm internal _UStrToPWChar đó. Hàm này được compiler chèn vào tự động.
Kiểu này phải cài RAD Studio lại quá.

Bác chỉ nốt cái Prototype của hàm InStr để em test luôn nhé. Bác cài RAD Studio đi để ae dễ đối chiếu cùng :D
 
Upvote 0
Web KT
Back
Top Bottom