Vous êtes actuellement hors ligne, en attente de reconnexion à Internet.

Comment faire pour automatiser Excel à partir de C++ sans utiliser MFC ou #import

Le support d'Office 2003 a pris fin

Microsoft a mis fin au support d'Office 2003 le 8 avril 2014. Cette modification a affecté vos mises à jour logicielles et options de sécurité. Découvrez les implications de ce changement à votre niveau et la marche à suivre pour rester protégé.

Cet article peut contenir des liens vers des informations en langue anglaise (pas encore traduites).
Résumé
Il existe de nombreux avantages liés à l'écriture du code Automation en langage C++ direct. Tout d'abord, vous pouvez faire exactement ce que vous voulez. Ensuite, votre code sera plus petit, plus rapide et plus facile à déboguer. Enfin, vous ne dépendrez d'aucune bibliothèque. Même en cas d'usage dédié des classes wrapper MFC ou de la prise en charge COM native de Visual C++ (#import), il se peut que vous deviez creuser dans IDispatch et automation COM pour contourner les bogues et limitations les plus courants avec ces structures.
Plus d'informations
Suivez la procédure suivante pour créer une application console Visual C++ 6.0 simple qui automatise Excel simplement à l'aide de C++ :
  1. Démarrez Visual C++ 6.0, et créez une nouvelle application console Win32 intitulée XlCpp. Choisissez une application « Hello, World! » et cliquez sur Terminer.
  2. Ouvrez le fichier XlCpp.cpp généré et ajoutez le code suivant avant la fonction main() :
    #include <ole2.h> // OLE2 Definitions// AutoWrap() - Automation helper function...    HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...) {    // Begin variable-argument list...    va_list marker;    va_start(marker, cArgs);    if(!pDisp) {        MessageBox(NULL, "NULL IDispatch passed to AutoWrap()", "Error", 0x10010);        _exit(0);    }    // Variables used...    DISPPARAMS dp = { NULL, NULL, 0, 0 };    DISPID dispidNamed = DISPID_PROPERTYPUT;    DISPID dispID;    HRESULT hr;    char buf[200];    char szName[200];        // Convert down to ANSI    WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);        // Get DISPID for name passed...    hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);    if(FAILED(hr)) {        sprintf(buf, "IDispatch::GetIDsOfNames(\"%s\") failed w/err 0x%08lx", szName, hr);        MessageBox(NULL, buf, "AutoWrap()", 0x10010);        _exit(0);        return hr;    }        // Allocate memory for arguments...    VARIANT *pArgs = new VARIANT[cArgs+1];    // Extract arguments...    for(int i=0; i<cArgs; i++) {        pArgs[i] = va_arg(marker, VARIANT);    }        // Build DISPPARAMS    dp.cArgs = cArgs;    dp.rgvarg = pArgs;        // Handle special-case for property-puts!    if(autoType & DISPATCH_PROPERTYPUT) {        dp.cNamedArgs = 1;        dp.rgdispidNamedArgs = &dispidNamed;    }        // Make the call!    hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, autoType, &dp, pvResult, NULL, NULL);    if(FAILED(hr)) {        sprintf(buf, "IDispatch::Invoke(\"%s\"=%08lx) failed w/err 0x%08lx", szName, dispID, hr);        MessageBox(NULL, buf, "AutoWrap()", 0x10010);        _exit(0);        return hr;    }    // End variable-argument section...    va_end(marker);        delete [] pArgs;        return hr;}						
  3. Dans la fonction main(), remplacez la ligne printf() par le code suivant :
       // Initialize COM for this thread...   CoInitialize(NULL);   // Get CLSID for our server...   CLSID clsid;   HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid);   if(FAILED(hr)) {      ::MessageBox(NULL, "CLSIDFromProgID() failed", "Error", 0x10010);      return -1;   }   // Start server and get IDispatch...   IDispatch *pXlApp;   hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pXlApp);   if(FAILED(hr)) {      ::MessageBox(NULL, "Excel not registered properly", "Error", 0x10010);      return -2;   }   // Make it visible (i.e. app.visible = 1)   {      VARIANT x;      x.vt = VT_I4;      x.lVal = 1;      AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"Visible", 1, x);   }   // Get Workbooks collection   IDispatch *pXlBooks;   {      VARIANT result;      VariantInit(&result);      AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"Workbooks", 0);      pXlBooks = result.pdispVal;   }   // Call Workbooks.Add() to get a new workbook...   IDispatch *pXlBook;   {      VARIANT result;      VariantInit(&result);      AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Add", 0);      pXlBook = result.pdispVal;   }   // Create a 15x15 safearray of variants...   VARIANT arr;   arr.vt = VT_ARRAY | VT_VARIANT;   {      SAFEARRAYBOUND sab[2];      sab[0].lLbound = 1; sab[0].cElements = 15;      sab[1].lLbound = 1; sab[1].cElements = 15;      arr.parray = SafeArrayCreate(VT_VARIANT, 2, sab);   }   // Fill safearray with some values...   for(int i=1; i<=15; i++) {      for(int j=1; j<=15; j++) {         // Create entry value for (i,j)         VARIANT tmp;         tmp.vt = VT_I4;         tmp.lVal = i*j;         // Add to safearray...         long indices[] = {i,j};         SafeArrayPutElement(arr.parray, indices, (void *)&tmp);      }   }   // Get ActiveSheet object   IDispatch *pXlSheet;   {      VARIANT result;      VariantInit(&result);      AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"ActiveSheet", 0);      pXlSheet = result.pdispVal;   }   // Get Range object for the Range A1:O15...   IDispatch *pXlRange;   {      VARIANT parm;      parm.vt = VT_BSTR;      parm.bstrVal = ::SysAllocString(L"A1:O15");      VARIANT result;      VariantInit(&result);      AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);      VariantClear(&parm);      pXlRange = result.pdispVal;   }   // Set range with our safearray...   AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, L"Value", 1, arr);   // Wait for user...   ::MessageBox(NULL, "All done.", "Notice", 0x10000);   // Set .Saved property of workbook to TRUE so we aren't prompted   // to save when we tell Excel to quit...   {      VARIANT x;      x.vt = VT_I4;      x.lVal = 1;      AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlBook, L"Saved", 1, x);   }   // Tell Excel to quit (i.e. App.Quit)   AutoWrap(DISPATCH_METHOD, NULL, pXlApp, L"Quit", 0);   // Release references...   pXlRange->Release();   pXlSheet->Release();   pXlBook->Release();   pXlBooks->Release();   pXlApp->Release();   VariantClear(&arr);   // Uninitialize COM for this thread...   CoUninitialize();						
  4. Compilez et exécutez.
La fonction AutoWrap() simplifie la plupart des détails de bas niveau impliqués dans l'utilisation directe d'IDispatch. N'hésitez pas à l'utiliser dans vos propres implémentations. Toutefois, si vous transmettez plusieurs paramètres, vous devez le faire dans l'ordre inverse. Par exemple :
    VARIANT parm[3];    parm[0].vt = VT_I4; parm[0].lVal = 1;    parm[1].vt = VT_I4; parm[1].lVal = 2;    parm[2].vt = VT_I4; parm[2].lVal = 3;    AutoWrap(DISPATCH_METHOD, NULL, pDisp, L"call", 3, parm[2], parm[1], parm[0]);				
Références
Pour plus d'informations sur l'automatisation de Microsoft Office à l'aide de Visual C++, cliquez sur le numéro ci-dessous pour afficher l'article correspondant dans la Base de connaissances Microsoft.
196776 Automation Office à l'aide de Visual C++
216388 FICHIER : B2CSE.exe convertit le code Automation Visual Basic en Visual C++
(c) Microsoft Corporation 1999, Tous droits réservés. Contributions de Joe Crump, Microsoft Corporation.

_com_ptr_t CComPtr
Propriétés

ID d'article : 216686 - Dernière mise à jour : 02/20/2006 14:25:00 - Révision : 4.1

Microsoft Office Excel 2003, Microsoft Excel 2002, Microsoft Excel 2000 Standard, Microsoft Excel 97 Standard, Microsoft Visual C++ 5.0 Édition Entreprise, Microsoft Visual C++ 6.0 Édition Entreprise, Microsoft Visual C++ 5.0 Édition Professionnelle, Microsoft Visual C++ 6.0 Édition Professionnelle, Microsoft Visual C++, 32-bit Learning Edition 6.0

  • kbhowto kbautomation KB216686
Commentaires