2012-07-16 7 views
6

Quindi sto lavorando su un progetto Excel che sta per caricare una DLL C++ utilizzando VBA. Quello che mi piacerebbe fare è essere in grado di passare un intervallo di Excel senza un tipo specifico (i dati possono essere numerici o categoriali) alla DLL C++ (il modo migliore in cui posso descrivere il mio intervallo di Excel è del tipo variant).Passare dati di tipo arbitrario tra VBA e dll

Così i passaggi probabilmente coinvolgono:

  1. caricare la DLL in VBA
  2. Invia la gamma di Excel per DLL (La gamma può contenere colonne di numeri e/o colonne di stringhe)
  3. manipolare il dati da excel nel file dll

Sto pensando di utilizzare la variante excel e la variante C++. Ma non è chiaro per me come usare la variante C++ in quanto non sono riuscito a trovare alcuna buona documentazione su di esso.

Un altro suggerimento che ho ricevuto è stata la programmazione COM.

Le mie domande:

  • potrebbe un animo gentile, eventualmente, fornire indicazioni per me su come procedere? (ad esempio fornendo il prototipo C++ e un semplice esempio di come gestire la variante)
  • Qualcuno conosce una buona documentazione/esercitazione sull'utilizzo di Varianti C++ (e forse in collaborazione con VBA)?
  • L'utilizzo di COM è preferibile all'utilizzo di VARIANTI se la velocità è un problema?
  • Si sta utilizzando l'API C un'opzione?

UPDATE:

  • La dimensione delle gamme ho bisogno di manipolare può essere di grandi dimensioni (~ 500.000 righe).
  • La velocità è un fattore, quindi, vorrei evitare di copiare inutilmente il più possibile.

risposta

2

A condizione desideri solo per passare i dati alla DLL (e non puntatori a oggetti reali di Excel come il Range), si hanno due opzioni fondamentali:

  1. Hai enormi insiemi di dati e si desidera evitare di copiare il più possibile.
    In questo caso, è possibile passare lo stesso array Variant ricevuto chiamando lo Range.Value. Per fare ciò, dovrai scrivere un piccolo TLB come riferimento da VB, in cui descriveresti la tua funzione C++ esportata come in attesa di un SAFEARRAY(VARIANT)*. Questo perché l'operatore Declare non ti consente di passare effettivamente SAFEARRAY *.
    La funzione sarà simile a questa:

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

    E il descripion TLB sarà simile a quanto segue:

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

    E il progetto C++ sarà ovviamente includere un file def:

    LIBRARY "TestSafearray" 
    
    EXPORTS 
        ReturnArrLowerBound 
    
  2. I tuoi set di dati sono di dimensioni ragionevoli e non ti importa un po 'di copia.
    Quindi rendere la funzione C++ accettata solo int[] e dichiararla in VB come accettante arr() as Long. Sul lato VB, allocare un array su Long s e copiare gli elementi in esso dall'array .

+0

Grazie! Se non sbaglio, scrivere il TLB coinvolge la programmazione COM, giusto? E allora ciò limita la portabilità dell'applicazione (in particolare sulle macchine Linux)? – SMir

+1

@SMir No, non implica la programmazione COM di per sé. Si scrive TLB solo per consentire a VB di comprendere la firma della funzione C++. Oltre a ciò, la funzione è una semplice funzione esportata in stile classico non COM. – GSerg

+0

Grazie per la pronta risposta. L'utilizzo di 'Variant' mi consente di passare tipi misti alla DLL? Oppure consente solo di avere un singolo tipo (che si tratti di stringhe o numeri, ecc.). – SMir