0 / 0 / 0
Регистрация: 26.10.2013
Сообщений: 3
1

Ошибка COM (Excel) без использования MFC, ATL

26.10.2013, 13:36. Показов 2029. Ответов 4
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Доброго времени суток!
Я занимаюсь разработкой приложения, которое выгружает определенные данные из БД в файл XLS (уже отформатирован, используется в качестве шаблона для заполнения).
Пользуюсь Code::Blocks (приложение использует wxWidgets для прорисовки GUI), соответственно использовать возможности MFC, ATL и иже с ними не получилось (по крайней мере не нашел как их подружить с Code::Blocks+MinGW). Для работы с OLE объектами используется враппер от Microsoft (код был найден где-то на MSDN).
Кликните здесь для просмотра всего текста

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
HRESULT xls_tuned::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];
    strcpy(buf,(char*)ptName);
 
    // 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;
}


Собственно получается открыть приложение Excel

Кликните здесь для просмотра всего текста
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Constructor
xls_tuned::xls_tuned(bool visible)
{
 
    pXlApp = pXlBooks = pXlBook = pXlSheet = pXlRange = 0;
    for(int i = 0;i<5;i++) IDispatch_pointers[i]=0;
 
    // Initialize COM for this thread...
   CoInitialize(NULL);
 
   // Get CLSID for our server...
   hr = CLSIDFromProgID(L"Excel.Application", &clsid);
 
   if(FAILED(hr)) {
      //::MessageBox(NULL, "CLSIDFromProgID() failed", "Error", 0x10010);
   }
 
   // Start server and get IDispatch...
 
   hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pXlApp);
   if(FAILED(hr)) {
      //::MessageBox(NULL, "Excel not registered properly", "Error", 0x10010);
   }
 
   // Make it visible (i.e. app.visible = 1)
   {
 
      VARIANT x;
      x.vt = VT_I4;
      x.lVal = visible;
      AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"Visible", 1, x);
      IDispatch_pointers[0] = 1;
   }
}


создать/открыть книгу
Кликните здесь для просмотра всего текста
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Activate Workbooks function
int xls_tuned::Workbooks()
{
    // Get Workbooks collection
   {
      VARIANT result;
      VariantInit(&result);
      AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"Workbooks", 0);
      pXlBooks = result.pdispVal;
      IDispatch_pointers[1] = 1;
   }
   return 0;
}
 
// Add new workbook
int xls_tuned::Addworkbook()
{
    // Call Workbooks.Add() to get a new workbook...
   {
      VARIANT result;
      VariantInit(&result);
      AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Add", 0);
      pXlBook = result.pdispVal;
      IDispatch_pointers[2] = 1;
   }
   return 0;
}
 
// Open local file
int xls_tuned::Open(std::string filename)
{
    // Call Workbooks.Add() to get a new workbook...
   {
      LPOLESTR pszFileNameW;
      AnsiToUnicode(filename.c_str(), &pszFileNameW);
 
      VARIANT parm;
      parm.vt = VT_BSTR;
      parm.bstrVal = ::SysAllocString(pszFileNameW);
 
      VARIANT result;
      VariantInit(&result);
      AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Open", 1, parm);
      pXlBook = result.pdispVal;
      CoTaskMemFree(pszFileNameW);
      IDispatch_pointers[2] = 1;
   }
   return 0;
}


писать в нее данные

Кликните здесь для просмотра всего текста
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int xls_tuned::Range(std::string range_sel)
{
    // Get Range object for the Range A1:O15...
 
    LPOLESTR pszRangeW;
    AnsiToUnicode(range_sel.c_str(), &pszRangeW);
 
    VARIANT parm;
    parm.vt = VT_BSTR;
    parm.bstrVal = SysAllocString(pszRangeW);
    //::MessageBox(NULL, (CHAR *) pszRangeW, "Notice", 0x10000);
 
    VARIANT result;
    VariantInit(&result);
    AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);
    VariantClear(&parm);
 
    pXlRange = result.pdispVal;
    CoTaskMemFree(pszRangeW);
    IDispatch_pointers[4] = 1;
}
 
int xls_tuned::Write2Range(VARIANT data)
{
    // Set range with our safearray...
   AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, L"Value", 1, data);
}


Однако возникла проблема с выбором листа

Кликните здесь для просмотра всего текста
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Activate sheet
int xls_tuned::Activatesheet(int sheet)
{
    // Get ActiveSheet object
 
    VARIANT x;
      x.vt = VT_I4;
      x.lVal = sheet;
 
      {
      VARIANT result;
      VariantInit(&result);
   if (sheet) {
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBook, L"Sheets", 1, x);
        pXlSheet = result.pdispVal;
        AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlSheet, L"Activate", NULL);
        //pXlSheet = result.pdispVal;
      } else {
    AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"ActiveSheet", 0);
        pXlSheet = result.pdispVal;
      }
      IDispatch_pointers[3] = 1;
   }
   return 0;
}

Если не задаем номер листа, то все работает (как в примере от Microsoft) и по умолчанию выбирается активный лист. Но когда я хочу явно задать, какой лист активировать, получаю ошибку
IDispatch::Invoke("Activate"=00000130) failed w|err 0x80070057
.

Если кто-то понимает, как побороть проблему, или подскажет куда копать - буду премного благодарен.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
26.10.2013, 13:36
Ответы с готовыми решениями:

примеры работы с компонентом TreeView, без использования MFC
TreeView Есть примеры работы с данным компонентом, без использования MFC? поделитесь, очень надо.

ATL Project. Как подключить использование MFC и ADO?
Добрый день! Переписываю dll, которую до меня писал другой программист. В Readme проекта в самом...

Отсортировать массив в excel без использования VBA
Отсортировать по возрастанию первую меньшую половину массива a , размерностью n . Первая меньшая...

Запись значения в ячейку Excel без использования строкового обозначения ячейки
Всё ясно и работает, если: Ap := CreateOleObject('Excel.Application'); ...

4
Модератор
3401 / 2172 / 353
Регистрация: 13.01.2012
Сообщений: 8,413
28.10.2013, 19:17 2
Цитата Сообщение от Zlatstalker Посмотреть сообщение
Но когда я хочу явно задать, какой лист активировать
а какое значение вы устанавливаете для свойства Activate?
0
0 / 0 / 0
Регистрация: 26.10.2013
Сообщений: 3
31.10.2013, 17:43  [ТС] 3
Цитата Сообщение от vxg Посмотреть сообщение
а какое значение вы устанавливаете для свойства Activate?
vxg, я передаю нулевое значение для Activate (вернее не нулевое значение, а не передаю аргумент вообще).

C++
1
AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlSheet, L"Activate", NULL);
На VB (когда пишем макрос в Excel), для этого используется конструкция, вроде Worksheets(sheet).Activate.
Соответственно
C++
1
2
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBook, L"Sheets", 1, x);
        pXlSheet = result.pdispVal;
насколько я понимаю создает указатель на нужный нам лист (передается переменная Variant x с указанием листа), после чего нужно этот лист активировать. Опять же обращаясь к макросу на VB для Activate параметры не задаются.

Пробовал передать тот же параметр x
C++
1
AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlSheet, L"Activate", 1, x);
но успеха это не принесло... Ощущение, что чего-то не улавливаю в логике работы, но не пойму что именно(
0
Модератор
3401 / 2172 / 353
Регистрация: 13.01.2012
Сообщений: 8,413
31.10.2013, 18:16 4
Цитата Сообщение от Zlatstalker Посмотреть сообщение
Ощущение
у меня ощущение что Activate это не свойство, а метод

Добавлено через 46 секунд
если делать на свойствах тогда нужно что то вроде Active и соответственно TRUE
1
0 / 0 / 0
Регистрация: 26.10.2013
Сообщений: 3
31.10.2013, 19:08  [ТС] 5
Цитата Сообщение от vxg Посмотреть сообщение
если делать на свойствах тогда нужно что то вроде Active и соответственно TRUE
Валится с той же ошибкой, но при этом во вновь созданной книге лист переключает... Т.е. параметр передается, но как-то активация некорректно срабатывает...

Добавлено через 1 минуту
vxg, а вот по поводу метода интересно... Попробую загуглить в этом направлении

Добавлено через 23 минуты
vxg, огромное человеческое спасибо! Действительно это было не свойство, а метод. Проблему решил.
C++
1
2
3
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBook, L"Sheets", 1, x);
pXlSheet = result.pdispVal;
AutoWrap(DISPATCH_METHOD, NULL, pXlSheet, L"Activate", NULL);
0
31.10.2013, 19:08
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
31.10.2013, 19:08
Помогаю со студенческими работами здесь

VS 2010 Express Edition && (MFC && ATL(WTL)) ???
Здравствуйте Смогу ли я воспользоваться Легально MFC и ATL(WTL) библиатеками в VS 2010 Express...

VC++6.0/ATL - ошибка сборки в режиме Release при исп.функций из math.h
В проекте созданным ATL COM AppWizard обязательно без поддержки MFC при использовании функций,...

я вот написала код без использования функции, но не знаю где ошибка, т.к. счатает верно только для первоначального значения. Код C#
всем приветик) возникла проблема с заданием: Заливайте файлы на форум. я вот написала код...

Как определить время без MFC
Мне нужно чтобы определенная функция запускалась в определенное время (Чтоб шла определенная...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru