Ngoài khai báo variant cho mảng thì còn cách khai báo nào nữa không ạ?

Liên hệ QC

ilvba

Thành viên mới
Tham gia
24/6/19
Bài viết
32
Được thích
7
Ngoài cách khai báo variant như dưới đây, cho em hỏi là có cách khai báo nào cụ thể rõ ràng hơn không ạ?
Mã:
[1]Sub Array_mang()
[2]  Dim myArray As Variant
[3]  Dim i As Integer
[4]  myArray = Array("conghoa", "xahoi", "chunghia", "Venezuela", "Alibaba")
[5]  For i = 0 To UBound(myArray)
[6]    Cells(i + 1, 2) = myArray(i)
[7]  Next
[8]End Sub
Chú yaf vào dòng code thứ 4 là cái em muốn dùng để nạp giá trị cho mảng cho nó nhanh ạ.
Nhưng ở dòng code thứ 2, em không biết nên khai báo như nào ngoài Variant.
Ai biết xin chỉ cho em với ạ.
 
Ngoài cách khai báo variant như dưới đây, cho em hỏi là có cách khai báo nào cụ thể rõ ràng hơn không ạ?
Mã:
[1]Sub Array_mang()
[2]  Dim myArray As Variant
[3]  Dim i As Integer
[4]  myArray = Array("conghoa", "xahoi", "chunghia", "Venezuela", "Alibaba")
[5]  For i = 0 To UBound(myArray)
[6]    Cells(i + 1, 2) = myArray(i)
[7]  Next
[8]End Sub
Chú yaf vào dòng code thứ 4 là cái em muốn dùng để nạp giá trị cho mảng cho nó nhanh ạ.
Nhưng ở dòng code thứ 2, em không biết nên khai báo như nào ngoài Variant.
Ai biết xin chỉ cho em với ạ.
Cái Variant chỉ là kiểu dữ liệu thôi bạn à.Còn mảng nó có 2 loại khai báo 1 là mảng tĩnh thứ 2 là mảng động.Bạn đọc cái này xem.
 
Upvote 0
Hàm Array của VBA (rtcArray trong VBEx.dll) là hàm trả về Variant. Variant này là array của các variant con.
Bạn bắt buộc phải khai báo myArray là Variant thôi, hoặc là myArray() As Variant (array của Variant)
Bạn chạy thử đoạn code này:
Mã:
Option Explicit

Sub Array_mang()
    Dim myArray As Variant
    Dim I As Integer
    
    Debug.Print TypeName(myArray)
    Debug.Print VarType(myArray)

    myArray = Array("conghoa", "xahoi", "chunghia", "Venezuela", "Alibaba", 1, True, 3.5)
    
    Debug.Print "TypeName = " & TypeName(myArray)
    Debug.Print "VarType = " & VarType(myArray)
    Debug.Print "Address = " & Hex$(VarPtr(myArray))
    
    For I = LBound(myArray) To UBound(myArray)
        Debug.Print vbTab & "TypeName = " & TypeName(myArray(I))
        Debug.Print vbTab & "VarType = " & VarType(myArray(I))
        Debug.Print vbTab & "Size = " & Len(myArray(I))
        Debug.Print vbTab & "Size in bytes = " & LenB(myArray(I))
        Debug.Print vbTab & "Address = " & Hex$(VarPtr(myArray(I))) & vbCrLf
        
        Cells(I + 1, 2) = myArray(I)
    Next
End Sub
Sau đó sữa lại Dim myArray() as Variant thành Dim myArray as Variant, chạy xem khác nhau gì không ?

Kiểu Variant trong VB/VBA là kiểu dữ liệu rất phức tạp, lùng bùng. Internal của nó là struct C/C++ VARIANT của OLE của Windows API. Nếu muốn hiểu sâu hơn chút chút thì đọc các link sau:
 
Lần chỉnh sửa cuối:
Upvote 0
Để bà con cô bác tìm hiểu về internal của array, bà con chạy đoạn code trên, mở cữa sổ Immediate Window ra coi kết quả.
Vd trên máy tui, nó chạy ra như sau:
Mã:
TypeName = String
    VarType = 8
    Size = 7
    Size in bytes = 14
    Address = 44FEB0

    TypeName = String
    VarType = 8
    Size = 5
    Size in bytes = 10
    Address = 44FEC0

    TypeName = String
    VarType = 8
    Size = 8
    Size in bytes = 16
    Address = 44FED0

    TypeName = String
    VarType = 8
    Size = 9
    Size in bytes = 18
    Address = 44FEE0

    TypeName = String
    VarType = 8
    Size = 7
    Size in bytes = 14
    Address = 44FEF0

    TypeName = Integer
    VarType = 2
    Size = 1
    Size in bytes = 2
    Address = 44FF00

    TypeName = Boolean
    VarType = 11
    Size = 4
    Size in bytes = 8
    Address = 44FF10

    TypeName = Double
    VarType = 5
    Size = 3
    Size in bytes = 6
    Address = 44FF20
Các bác có để ý không, các address trong VA (Virtual Memory) của các phần tử trong myArray đều liền kề nhau, cách nhau 0x10 byte (16 byte), chính là size của struct VARIANT trong khai báo C/C++ Windows API.
Giờ xem thử tại address nào đó, nó có cái gì, các bác đừng tắt Excel nhé, mở WinHex (www.winhex.com) lên, vào menu Tools, Open Memory... Duyệt tìm Excel, chọn, bấm dấu +, chọn Entire memory.
Xong, nhấn Alt-G, nhập vào 1 điạ chỉ nào đó ở trên, WinHex sẽ nhảy tới VA address đó.

Còn nhiều nữa mà đột nhiêu tui lại "nười" rồi, kỳ sau viết tiếp. Mời các bạn chờ đọc "hầu sau sẽ rõ" ;)
 
Lần chỉnh sửa cuối:
Upvote 0
Về Variant và ý nghĩa 16 bai tôi cũng đã nói chút ở đây


Nguyễn Duy Tuân cũng từng tặng mọi người FastArray. Đọc bài của Tuân thì cũng sẽ hiểu thêm nhiều về Variant.


Cấu trúc của Variant thì có thể đọc ở nhiều nơi. Nếu tôi có trí nhớ tốt thì trong Delphi có TVarData. Dễ đọc cho những người biết Delphi (Object Pascal) mà không biết C gì đó.
 
Upvote 0
Kiểu SAFEARRAY và VARIANT của người ta mà các bác dám dùng VBA, CopyMemory tá lã, phá hủy hết internal data của người ta, đúng là gan thiệt
 
Upvote 0
CopyMemory chỉ là hàm dùng để copy "một chuỗi bai" một vùng bộ nhớ này sang một vùng khác. Mọi vùng trong bộ nhớ chỉ là chuỗi các bai, cho dù ở đấy có trụ sở của số, chuỗi hay object hay array hay safearray gì gì đó. Nếu dùng CopyMemory để copy nhưng lại chọn nguồn không chính xác thì sẽ nhận được kết quả không chính xác. Thế thôi. CopyMemory không chỉnh sửa, xóa, thêm ở vùng nguồn thì sao lại có thể nói là phá hủy cái gì đó tanh bành? Thao tác đọc (read) chứ đâu có là thao tác ghi (write) đâu mà nói nó làm cái gì đó tanh bành? Cùng lắm đọc nhầm vùng thì nhận kết quả sai. Sai với nghĩa là kết quả không như mong đợi chứ đâu phải là "chết đột ngột" mà nói là phá hủy cái gì đó tanh bành?
Không hiểu ý lắm, khó mà tranh luận với một cái gì đó chung chung.

Tôi trót đề xuất quà tặng của Tuân mà ThangCuAnh lại dùng từ "các bác" nên có thể nói tới cả Tuân chăng? Hoặc chỉ nói về Tuân chăng? Thế thì Tuân cũng được gọi lên bảng rồi nhé. Xin lỗi vì đã làm liên lụy. :D
-------------
Tất nhiên ở đây tôi nói về code của tôi vì nó chỉ copy sang đích là một chỗ không phải "vùng cấm". Vì nếu copy sang vùng nào đó để "đè lên" để "thay đổi" cái safearray đang nghị trị ở vùng đó thì mới có thể nói là phá hủy nó. Code của tôi không copy vào một safearray nào nên không thể nói là nó phá cái gì đó.
 
Lần chỉnh sửa cuối:
Upvote 0
Hì hì, giải thích ra dài dòng, lòng vòng nữa. Mắc công phải copy hình diassembly, decompiler C/C++ code của VBA, API của oleaut32.dll, ole32.dll... Tá lã âm binh. Nên thôi. "Nười nắm", khó quá bỏ qua ;)
Mà tiêu chí của GPE là code mà chạy được là tốt rồi, mừng húm, cần gì quan tâm tới nó đúng sai, memory leak, handle leak hay crash, nhanh chậm...
Nói chung là điếc không sợ súng, chắc ăn là cứ on error resume netxt, ủi, càn qua hết. Khi nào Excel nó crash thì hẳn tính, la làng lên sao nó chết cũng chưa muộn mà ;)

@kieu manh Có thêm hàm cho Delphi VB Library của bác đây. Bác port hết mấy hàm fastArray gì đó của bác Tuân qua Delphi nhé. Phải code sao không leak, không crash, nhanh hơn For của VB nhé.
Để code được, bác Mạnh cố gắng đọc kỹ, nghiền ngẫm các articles sau nhé. Nó code = C/C++ nhưng port qua Delphi cũng tương đương thôi.

Tác giả Bruce McKinney này tui có nói 1 lần, tác giả của sách Hardcored VB. Người này là coder của MS, guru về VB và internal của VB đó. Hồi còn code VB tôi ngưỡng mộ ông này lắm, cầu thủ bóng chày đấy.
Dựa trên cái Vb5dll mà hồi xưa tôi có code các hàm cho VB dùng VC++, build Dll.
 
Lần chỉnh sửa cuối:
Upvote 0
Không ai có thể tranh luận được theo kiểu đó. Anh kia chơi xấu quá. Tôi biết nhưng tôi không nói, tôi không có thời gian, không có hứng. Toàn kiểu phán một câu rồi dùng chiêu "nói chung chung", "nói bừa cho sướng miệng". Ai mà tranh luận được kiểu ấy, tranh luận với ý gì, vấn đề gì? Tung mấy ole, safe ra người không biết gì, chưa bao giờ nghe thấy lại tưởng là anh ta giỏi lắm. Bó tay.

Nhắc lại.
Nếu CopyMemory chỉ dùng để copy chuỗi bai trong memory từ source sang dest thì:

- rõ ràng nó không chỉnh sửa, thêm, xóa source. Vậy không thể phá hủy source tanh bành được.
- nếu ở dest không có bất cứ safearray nào thì rõ ràng CopyMemory không thể ghi đè lên bất cứ safearray nào được, không thể phá hủy bất cứ safearray nào tanh bành được.

Mang mấy cái tool ra hù họa người yếu tim thì được. Kiểu đuối lý im ỉm đánh bài chuồn không phải là tranh luận.

Nhân đây nhắc lại một chân lý:
- Nếu văn bản ghi sai, không đúng là unicode, thì dù không có BOM hay thêm 1000 BOM ở đầu thì "ruột" vẫn không là unicode, và khi hiển thị sẽ có "đầu trâu mặt ngựa".

- Nếu biết cách ghi văn bản sao cho nội dung đúng là unicode thì không có BOM hay thêm BOM thì ruột nó vẫn là unicode, và sẽ hiển thị chuẩn.

- BOM chỉ là để dễ nhận biết. Nhưng không phải thiếu BOM là nội dung không đọc được. Dễ kiểm chứng thôi mà, chỉ cần chút suy nghĩ. Mở notepad -> viết đoạn tiếng Việt -> lưu lại với encode là unicode -> mở tập tin vừa lưu trong Hex Editor -> xóa BOM = FFFE -> lưu lại -> mở tập tin lại trong notepad -> chắc chắn vẫn là nội dung tiếng Việt đẹp đẽ. Đâu phải không có BOM là nội dung nó khác. BOM không quyết định nội dung. Cách ghi, cách tạo văn bản mới quyết định nội dung.
 
Upvote 0
Hì hì, tui không thích tranh luận ra lẽ thôi, được cái gì đâu. Chứ không phải đuối lý. Chả ai rãnh hơi đâu mà lên đây cãi, tranh luận hơn thua.
Bác cứ đọc mấy cái link tui gởi đi đã rồi hãy cãi.
Hì hì, bác này để bụng ghê nhỉ, cái vụ BOM lâu lắt rồi giờ còn lôi ra.
 
Upvote 0
Hãy đọc bài của tôi rồi tranh luận nhé. Tôi bao giờ cũng viết ra tất cả các ý, để người khác dễ tranh luận với điều này hay điều kia. Tôi không nói chung chung.

Tất nhiên tôi nói về code ví dụ của tôi chứ không nói về code của ai khác. Code của tôi thì có trong link bài #5 rồi. Vậy chỗ nào sẽ làm tanh bành safearray? Một câu hỏi quá cụ thể
 
Upvote 0
Hì hì, vậy bác batman1 xóa BOM đi rồi lấy Wordpad, Microsoft Word có sẵn trong mấy bác, mở lên thử xem nó ra cái gì ? ;)
Mã:
       IUnknown      *punkVal;    // VT_UNKNOWN
        IDispatch     *pdispVal;   // VT_DISPATCH          ByVal Object
        SAFEARRAY     *parray;     // VT_ARRAY|*           ByVal array
        // A bunch of other types that don't matter here...
        VARIANT       *pvarVal;    // VT_BYREF|VT_VARIANT  ByRef Variant
        void          * byref;     // Generic ByRef
Mấy bác may là chưa đụng tới các item trong Variant array (là những pointer) này đấy, không là nó sụm bà chè, die cả Excel luôn rồi, ở đó mà CopyMemory.
Mấy coder MS không có rảnh, ở không mà ngồi đó code ra 1 đống SafeArray API, Variantxxx API, sao không dùng quách memcpy của C RTL, CopyMemory trong kernel32 (forwad to RtlMoveMemory trong ntdll.dll)
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi viết 1 code ví dụ. Bạn nói là nó làm tanh bành safearray. Bây giờ bạn lại nói là
Mấy bác may là chưa đụng tới các item trong Variant array (là những pointer) này đấy.
Thôi thì lần sau hãy góp ý với những gì người khác đã làm. Đừng suy ra là người ta sẽ làm những gì mình nghĩ để rồi chỉ trích người ta.
 
Upvote 0
Cái bộ hàm xử lý mảng "modFastArrays" dưới đây mình dùng CopyMemory bản chấy là copy byes trong bộ nhớ như là đi "cưa sau" nên không liên quan đến leak memory. Khi nào bạn @ThangCuAnh rảnh kiểm tra bên đó giúp xem leak chỗ nào?
Bài đã được tự động gộp:

Hì hì, vậy bác batman1 xóa BOM đi rồi lấy Wordpad, Microsoft Word có sẵn trong mấy bác, mở lên thử xem nó ra cái gì ? ;)
Mã:
       IUnknown      *punkVal;    // VT_UNKNOWN
        IDispatch     *pdispVal;   // VT_DISPATCH          ByVal Object
        SAFEARRAY     *parray;     // VT_ARRAY|*           ByVal array
        // A bunch of other types that don't matter here...
        VARIANT       *pvarVal;    // VT_BYREF|VT_VARIANT  ByRef Variant
        void          * byref;     // Generic ByRef
Mấy bác may là chưa đụng tới các item trong Variant array (là những pointer) này đấy, không là nó sụm bà chè, die cả Excel luôn rồi, ở đó mà CopyMemory.
Mấy coder MS không có rảnh, ở không mà ngồi đó code ra 1 đống SafeArray API, Variantxxx API, sao không dùng quách memcpy của C RTL, CopyMemory trong kernel32 (forwad to RtlMoveMemory trong ntdll.dll)

Trong thành phần SafeArray chứa Pointer - IDispatch, IUnknow và kiểu user define vì thế mình chỉ nên CopyMemoy chỉ hướng đến các array chưa dữ liệu thôi chứ không làm việc với object.
 
Lần chỉnh sửa cuối:
Upvote 0
Hì hì, giải thích ra dài dòng, lòng vòng nữa. Mắc công phải copy hình diassembly, decompiler C/C++ code của VBA, API của oleaut32.dll, ole32.dll... Tá lã âm binh. Nên thôi. "Nười nắm", khó quá bỏ qua ;)
Mà tiêu chí của GPE là code mà chạy được là tốt rồi, mừng húm, cần gì quan tâm tới nó đúng sai, memory leak, handle leak hay crash, nhanh chậm...
Nói chung là điếc không sợ súng, chắc ăn là cứ on error resume netxt, ủi, càn qua hết. Khi nào Excel nó crash thì hẳn tính, la làng lên sao nó chết cũng chưa muộn mà ;)

@kieu manh Có thêm hàm cho Delphi VB Library của bác đây. Bác port hết mấy hàm fastArray gì đó của bác Tuân qua Delphi nhé. Phải code sao không leak, không crash, nhanh hơn For của VB nhé.
Để code được, bác Mạnh cố gắng đọc kỹ, nghiền ngẫm các articles sau nhé. Nó code = C/C++ nhưng port qua Delphi cũng tương đương thôi.

Tác giả Bruce McKinney này tui có nói 1 lần, tác giả của sách Hardcored VB. Người này là coder của MS, guru về VB và internal của VB đó. Hồi còn code VB tôi ngưỡng mộ ông này lắm, cầu thủ bóng chày đấy.
Dựa trên cái Vb5dll mà hồi xưa tôi có code các hàm cho VB dùng VC++, build Dll.
Mạnh đọc cũng ham lắm nhưng code két có học hành bài bản mô toàn mò học là chính .... tiếng Anh và tiếng việt viết sai tè le

nếu thật sự muốn chỉ Mạnh học với thì viết dùm cho 1 VD mẫu rất cơ bản kiểu như: 1 +1 = 2 ấy thì mạnh hình dung ra được và vận dụng học rất nhanh .... còn cứ lý thuyết 9 tầng mây ấy thấy nó cứ bay bay ko biết về đâu hết là thua may ra sau này hội đủ kiếm thức đọc lại thì mới hiểu và khi hiểu được nó thì công nghệ nó lại tiến xa vượt bậc

Nhắc lại là nếu thật sự giúp mạnh học được thì cho Mạnh xin code mẫu như 1 + 1 = 2 ấy là học và vận dụng nhanh lắm

cảm ơn rất nhiều
 
Upvote 0
Về nguyên tắc API, đụng tới SafeArray và Variant, thì trước tiên muốn đụng tới pvData của SafeArray phải call SafeArrayLock đã, rồi SafeArrayGetData để lấy pointer pvData, thao tác xong SafeArrayUnlock. Bác Tuân search SAFEARRAY API đi, hay xem mấy articles tui vừa post đấy.
Còn Variant cũng vậy, muốn đụng tới nó thì phải dùng đúng hàm API như VariantCopy, VariantClear....
Các hàm API này trong OleAut32.dll. VBAxxx.dll call các hàm API này cho các hàm, các thao tác trên kiểu Array, Variant, string của VBA.
Vì bác test với array chứa data thuần nên không sao, chứ đụng tới variant của variant item, hay array trong variant item, hay Object trong variant item, thì cu anh tui không biết sẽ "như thế lào" ;) Ví dụ nếu có chứa pointer, CopyMemory xong, Erase thằng source, Erase luôn thằng Dest, không chết là may mắn lắm rồi đấy.
2 kieu manh: Hàm Sum bác viết rồi mà ;)
 
Lần chỉnh sửa cuối:
Upvote 0
Sorry, post nhầm.
 
Upvote 0
Về nguyên tắc API, đụng tới SafeArray và Variant, thì trước tiên muốn đụng tới pvData của SafeArray phải call SafeArrayLock đã, rồi SafeArrayGetData để lấy pointer pvData, thao tác xong SafeArrayUnlock. Bác Tuân search SAFEARRAY API đi, hay xem mấy articles tui vừa post đấy.
Còn Variant cũng vậy, muốn đụng tới nó thì phải dùng đúng hàm API như VariantCopy, VariantClear....

Mình làm trên Delphi nhiều nên vấn đề hàm API về SAFEARRAY đọc rất kỹ. Add-in mình viết để giao tiếp với Excel chủ yếu là RANGE.Value - SafeArray 2D nên nếu không nắm được thì teo héo ngay :).
 
Upvote 0
Hì hì, tui biết chứ, nghĩ trong đầu là chắc hồi code cái modFastArray gì đó, bác chưa nghiên cứu hay lường trước, test kỹ hết về SAFEAARRAY, modFastArray.
Bác @kieu manh vào xin bác Tuân mấy cái source Delphi về thao tác SafeArray về ngâm cứu đi nè :)
 
Upvote 0
Hì hì, vậy bác batman1 xóa BOM đi rồi lấy Wordpad, Microsoft Word có sẵn trong mấy bác, mở lên thử xem nó ra cái gì ? ;)
Thế thì không biết mở rồi.

Hãy mở tập tin đính kèm ở bài #7 nhưng không nhấn 2 nút trên sheet vì đó là code của chủ chủ đề không có BOM và chỉ thêm BOM. Hãy vào VBE và chạy sub code_batman1 là code của tôi ở bài #3. Không có BOM gì cả.

Mặc định code sẽ tạo test.txt trong thư mục C:\. Hãy phải chuột trên tập tin -> Open With -> duyệt tới và chọn Word -> sẽ có cửa sổ "File Conversion" -> hãy chọn như trên hình. Trên hình cũng đã nhìn thấy đẹp - "sướng". Sau khi nhấn OK thì sẽ thấy "sướng"anh test.JPG
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom