Запись данных в открытый Excel файл с помощью COM OLE C++

118
11 сентября 2019, 22:00

Подскажите пожалуйста, есть ли у кого пример кода чтения и записи данных из/в открытый ексель файл с помощью COM/OLE на чистом С++.

Есть микрософтовский пример: https://support.microsoft.com/en-us/help/216686/how-to-automate-excel-from-c-without-using-mfc-or-import

Он создает ексель файл и записывает в него данные, но как записать данные в уже в Открытый ексель файл, как этот ексель файл отловить, такого примера нет, а доработать/изменить микрософтовский примера под свою задачу, для меня на данный момент, к сожалению совершенно не возможно, настолько там все сложно.

Может кто нибудь делал нечто подобное.

Answer 1

Для подключения к запущенному экземпляру Excel необходимо использовать вызов GetActiveObject вместо CoCreateInstance. Далее, для получения доступа к открытому документу нужно заменить вызов метода Add на вызов свойства Item с индексом 1. Получаем такой код:

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#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) {
        MessageBoxA(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)) {
        printf("IDispatch::GetIDsOfNames(\"%s\") failed w/err 0x%08lx", szName, hr);        
        getchar();
        _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)) {
        printf("IDispatch::Invoke(\"%s\"=%08lx) failed w/err 0x%08lx", szName, dispID, hr);     
        getchar();
        _exit(0);
        return hr;
    }
    // End variable-argument section...
    va_end(marker);
    delete[] pArgs;
    return hr;
}
int  main(int argc, char **argv)
{
    // Initialize COM for this thread...
    CoInitialize(NULL);
    // Get CLSID for our server...
    CLSID clsid;
    HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid);
    if (FAILED(hr)) {
        ::MessageBoxA(NULL, "CLSIDFromProgID() failed", "Error", 0x10010);
        return -1;
    }
    IUnknown* pUnk;
    hr = GetActiveObject(clsid, NULL, &pUnk);
    if (FAILED(hr)) {
        ::MessageBoxA(NULL, "GetActiveObject failed!", "Error", 0x10010);
        return -2;
    }
    IDispatch *pXlApp;
    hr = pUnk->QueryInterface(IID_IDispatch, (void**)&pXlApp);
    if (FAILED(hr)) {
        ::MessageBoxA(NULL, "QueryInterface failed!", "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, (LPOLESTR)L"Visible", 1, x);
    }
    // Get Workbooks collection
    IDispatch *pXlBooks;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, (LPOLESTR)L"Workbooks", 0);
        pXlBooks = result.pdispVal;
    }   
    //Open workbook
    IDispatch *pXlBook;
    {
        VARIANT result;
        VariantInit(&result);
        VARIANT index;
        VariantInit(&index);
        index.vt = VT_INT;
        index.intVal = 1;       
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, (LPOLESTR)L"Item",1, index);
        pXlBook = result.pdispVal;
        VariantClear(&index);
    }   
    // 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, (LPOLESTR)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, (LPOLESTR)L"Range", 1, parm);
        VariantClear(&parm);
        pXlRange = result.pdispVal;
    }
    // Set range with our safearray...
    AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, (LPOLESTR)L"Value", 1, arr);
    // Save workbook
    VARIANT var_result;
    VariantInit(&var_result);
    AutoWrap(DISPATCH_METHOD, &var_result, pXlBook, (LPOLESTR)L"Save", 0);
    VariantClear(&var_result);
    // Release references...
    pUnk->Release();
    pXlRange->Release();
    pXlSheet->Release();
    pXlBook->Release();
    pXlBooks->Release();
    pXlApp->Release();
    VariantClear(&arr);
    printf("All done! Press any key to exit\n");
    getchar();
    // Uninitialize COM for this thread...
    CoUninitialize();
    return 0;
}
READ ALSO
Удаление папок Windows Kits

Удаление папок Windows Kits

Столкнулся с интересным вопросом, причем ничего явно отвечающего на него в интернете не нашелСобственно, есть папка Program Files (x86)\Windows Kits/10/Include...

136
Variadic templates C++

Variadic templates C++

есть следующий код:

133
С++ ссылка на временный объект

С++ ссылка на временный объект

Хочу разобраться в двух следующих вопросах:

156