2012-07-16 40 views
6

Vì vậy, tôi đang làm việc trên một Dự án Excel sẽ tải một dll C++ bằng VBA. Những gì tôi muốn làm là để có thể vượt qua một phạm vi Excel không có loại cụ thể (dữ liệu có thể là số hoặc phân loại) vào dll C++ (Cách tốt nhất tôi có thể mô tả phạm vi Excel của tôi là loại variant).Vượt qua dữ liệu kiểu tùy ý giữa VBA và dll

Vì vậy, các bước có thể bao gồm:

  1. tải dll trong VBA
  2. Gửi dải excel để dll (Phạm vi có thể chứa các cột các số và/hoặc cột dây)
  3. thao tác dữ liệu từ excel trong tệp dll

Tôi đang nghĩ đến việc sử dụng biến thể excel và biến thể C++. Nhưng nó không rõ ràng đối với tôi làm thế nào để sử dụng các biến thể C + + như tôi không thể tìm thấy bất kỳ tài liệu tốt về nó.

Một đề xuất khác mà tôi nhận được là lập trình COM.

Câu hỏi của tôi:

  • thể một loại linh hồn có thể cung cấp gợi ý cho tôi về cách tiến hành? (ví dụ: bằng cách cung cấp nguyên mẫu C++ và một ví dụ đơn giản về cách xử lý biến thể)
  • Có ai biết bất kỳ tài liệu/hướng dẫn tốt nào về việc sử dụng Biến thể C++ (và có lẽ cùng với VBA) không?
  • Có sử dụng COM thích hợp hơn khi sử dụng VARIANTS nếu tốc độ là vấn đề không?
  • Có sử dụng tùy chọn API của C không?

UPDATE:

  • Kích thước của dãy Tôi cần phải thao tác có thể lớn (~ 500.000 hàng).
  • Tốc độ là một yếu tố, do đó, tôi muốn tránh việc sao chép không cần thiết càng nhiều càng tốt.

Trả lời

2

Miễn là bạn chỉ muốn để truyền dữ liệu đến các dll (và không phải con trỏ tới các đối tượng Excel thực tế như Range), bạn có hai lựa chọn cơ bản:

  1. Bạn có bộ dữ liệu khổng lồ và muốn tránh sao chép càng nhiều càng tốt.
    Trong trường hợp này, bạn có thể muốn chuyển cùng một mảng Variant mà bạn nhận được bằng cách gọi Range.Value. Để làm điều đó, bạn sẽ phải viết một TLB nhỏ để tham chiếu từ VB, trong đó bạn sẽ mô tả hàm C++ đã xuất của bạn như mong đợi một SAFEARRAY(VARIANT)*. Điều này là do nhà điều hành Declare sẽ không cho phép bạn thực sự vượt qua SAFEARRAY *.
    Các chức năng sẽ giống như thế này:

    LONG __stdcall ReturnArrLowerBound(SAFEARRAY** ppArr) 
    { 
        if (ppArr == NULL) return -1; 
        SAFEARRAY* pArr = (*ppArr); 
    
        LONG res = 0; 
        SafeArrayGetLBound(pArr, 1, &res); 
    
        return res; 
    } 
    

    Và descripion TLB sẽ trông như thế:

    [ 
        uuid(A686B138-D8CE-462e-AEF2-75DA4DBF1C75) 
    ] 
    library foo 
    { 
        [ 
         dllname("TestSafearray.dll") 
        ] 
        module vb 
        { 
         [entry("ReturnArrLowerBound")] 
         LONG __stdcall ReturnArrLowerBound(SAFEARRAY(VARIANT)* ppArr); 
        } 
    } 
    

    Và ++ Dự án C của bạn sẽ rõ ràng bao gồm một file def:

    LIBRARY "TestSafearray" 
    
    EXPORTS 
        ReturnArrLowerBound 
    
  2. Tập dữ liệu của bạn có kích thước hợp lý và bạn không ngại sao chép một chút.
    Sau đó, hãy thực hiện hàm C++ của bạn để chỉ chấp nhận int[] và khai báo nó trong VB là chấp nhận arr() as Long. Về phía VB, phân bổ một mảng trên Long s và sao chép các phần tử vào nó từ mảng Range.Value.

+0

Cảm ơn! Nếu tôi không nhầm, viết TLB liên quan đến lập trình COM, phải không? Và sau đó không giới hạn tính di động của ứng dụng (đặc biệt là trên các máy linux)? – SMir

+1

@SMir Không, nó không liên quan đến chương trình COM. Bạn chỉ viết TLB để VB hiểu chữ ký hàm C++ của bạn. Khác hơn thế, hàm này là hàm xuất thô, không phải COM, kiểu cổ điển. – GSerg

+0

Cảm ơn bạn đã trả lời nhanh chóng. Có sử dụng 'Biến thể' cho phép tôi để vượt qua các loại hỗn hợp để DLL? Hoặc nó chỉ cho phép có một loại duy nhất (có thể là chuỗi hoặc số, v.v.). – SMir

Các vấn đề liên quan