Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Доступ к серверу Excel в MVS 2005 с помощью диспетчерского интерфейса
Последовательность действий для подключения Excel практически такая же, как и для сервера Word. Шаг 1. Создание каркаса приложения. Создадим с помощью мастера Win32 Console Application заготовку обычного консольного приложения с поддержкой MFC. Предполагается, что проекту присвоено имя UseExcel. Шаг 2. Инициализация OLE. Как и в случае с Word, добавим в приложение класс OleInit для инициализации служб СОМ. С учетом этого файл реализации консольного приложения UseExcel.cpp будет иметь вид, приведенный в следующем листинге. #include "stdafx.h" #include "UseExcel.h" // …
CWinApp theApp;
using namespace std; struct OleInit { OleInit() { CoInitialize(NULL); TRACE("CoInitialize(NULL) executed\n"); } ~OleInit() { CoUninitialize(); TRACE("CoUninitialize() executed\n"); } } Init;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { int nRetCode = 0; if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { _tprintf(_T("Fatal Error: MFC initialization failed\n")); return nRetCode = 1; }
return nRetCode; } Если такую программу запустить на выполнение в режиме отладки, то в окне Debug мы увидим сообщения «CoInitialize(NULL) executed» и «CoUninitialize() executed». Рекомендую это проделать практически, следуя концепции RAD (быстрой разработки программ). Шаг 3. Генерация классов-оболочек для интерфейсов сервера Excel. Для использования диспетчерских интерфейсов Excel надо получить доступ к их объявлениям, которые находятся, как положено в библиотеке типов, ну а сама библиотека типов, в отличие от Word, размещается в файле Excel.exe. Для получения описаний интерфейсов и методов Excel надо выполнить команду ProjectèAdd Class, в появившемся окне выбрать Categories==MFC и Templates==MFC Class From TypeLib. Нажимаем кнопку Add и в новом появившемся окне открываем список Available type libraries (доступные библиотеки типов). В этом списке перечислены все библиотеки типов, зарегистрированные в реестре. Выбираем в выпадающем списке элемент Microsoft Excel 11.0 Object Library <1.5> (рис.1), а в списке Interfaces мы можем выбирать любые интерфейсы и включать их в список Generated classes с помощью кнопки >. Можно поступить решительно и с помощью кнопика >> сгенерировать классы для всех интерфейсов без разбору. Обратите внимание на то, что в элементах Class и File мастер показывает имена классов и заголовочных файлов, которые он будет генерировать. Закончите работу по генерации объявлений классов нажатием кнопки Finish.
Рис. 1. Выбор библиотеки типов и интерфейсов
Шаг 4. Запуск сервера Excel. Теперь модифицируем файл UseExcel.cpp, добавив в него код запуска Excel. Не забудьте в начало файла добавить, для начала, директиву подключения заголовочного файла CApplication.h, необходимого для запуска Excel, а также файлов comdef.h и conio.h. Кстати, вы наверное заметили на вкладке Solution Explorer в папке Header Files великое множество файлов, сгенерированных мастером. // UseWord.cpp : Иллюстрация запуска приложения MS Word // #include "stdafx.h" #include "UseWord.h" #include <ComDef.h> // объявление класса _com_error #include "CApplication.h" #include <ConIO.h>
#ifdef _DEBUG #define new DEBUG_NEW #endif CWinApp theApp; using namespace std;
char Buf[1024]; char * Rus(char * Str) { CharToOemA(Str,Buf); return Buf; } struct OleInit { OleInit() { CoInitialize(NULL); TRACE("CoInitialize(NULL) executed\n"); } ~OleInit() { CoUninitialize(); TRACE("CoUninitialize() executed\n"); } } Init;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { int nRetCode = 0; if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { _tprintf(_T("Fatal Error: MFC initialization failed\n")); return nRetCode = 1; } try { LPDISPATCH pDisp; LPUNKNOWN pUnk; CLSID clsid; CApplication m_app; /*Получение GUID приложения Word по его внешнему имени Word.Application, под которым Word зарегистрирован в реестре*/ CLSIDFromProgID(L"Word.Application",&clsid); /*GetActiveObject позволяет получить интерфейс запущенного экземпляра сервера, если таковой есть, по его clsid*/ if(GetActiveObject(clsid,NULL,&pUnk)==S_OK) { VERIFY(pUnk->QueryInterface(IID_IDispatch, (void **)&pDisp)==S_OK); m_app.AttachDispatch(pDisp); pUnk->Release(); TRACE("Подключение к запущенному экземпляру” “ Word выполнено успешно\n"); } else // самостоятельно запускаем приложение Word if(!m_app.CreateDispatch(clsid)) throw "Не найдено приложение Word"; /* В этой точке мы либо подключились к уже запущенному экземпляру Word, либо запустили свой экземпляр приложения */ m_app.put_Visible(true); TRACE("Окно Word должно быть видимо\n"); cout<<Rus("Нажми любую клавишу для завершения работы")<<endl; _getch(); // Готовим параметры для метода Quit() VARIANT SaveChanges, DocumentFormat, Empty; SaveChanges.vt=VT_BOOL; SaveChanges.boolVal=VARIANT_TRUE; DocumentFormat.vt=VT_I4; DocumentFormat.intVal=1; Empty.vt=VT_EMPTY; m_app.Quit(&SaveChanges,&DocumentFormat,&Empty); } catch(_com_error &ex) // обработка СОМ ошибок { AfxMessageBox(ex.ErrorMessage()); } catch(char * msg) { AfxMessageBox(CString(msg)); } _getch(); return nRetCode; }
Закомментировать import vbcmn98.chm – справка по ActiveX для Visual Basic с примерами кода. C:\Program Files\Microsoft Office\OFFICE11\1049\VBA*.chm (VBAAC10.chm, VBAOF11.chm, VBAOWS10.chm) Некоторые комментарии к программе. В файле CApplication.h нет ни одного GUID! И вообще здесь в программе используется только clsid сервера Word, который мы получаем с помощью функции CLSIDFromProgID(), и еще GUID диспетчерского интерфейса IID_IDispatch, определенный где-то в другом месте. Функция void COleDispatchDriver::AttachDispatch( LPDISPATCH lpDispatch, BOOL bAutoRelease = TRUE );
подключает интерфейс lpDispatch к объекту класса COleDispatchDriver (класс CApplication является наследником этого класса). Параметр bAutoRelease указывает, должен ли интерфейс освобождаться при выходе объекта из сферы видимости. В нашем случае мы прикрепили полученный с помощью функции QueryInterface() интерфейс pDisp к объекту m_app. После этого мы сможем вызывать методы объекта m_app. Вот пример реализации одного из методов интерфейса _Application, который мы используем как метод объекта m_app:
LPDISPATCH _Application::GetDocuments() { LPDISPATCH result; InvokeHelper(0x6, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result, NULL); return result; }
Объявление этого метода содержится в файле CApplication.h. Вспомогательная функция InvokeHelper(), реализация которой содержится в файле OleDisp2.cpp, подготавливает параметры для вызова функции IDispatch::Invoke(), вызывает ее и возвращает результат. Мы бы могли не добавлять в наш проект класс-оболочку CApplication, а после получения интерфейса pDisp с помощью функции QueryInterface() непосредственно вызывать метод IDispatch::Invoke(), предварительно подготовив его параметры. Но это стоило бы очень больших усилий, так как подготовка параметров является очень непростой задачей. Чтобы убедиться в этом, посмотрите на объявление метода IDispatch::Invoke(): virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( /* [in] */ DISPID dispIdMember, /* [in] */ REFIID riid, /* [in] */ LCID lcid, /* [in] */ WORD wFlags, /* [out][in] */ DISPPARAMS *pDispParams, /* [out] */ VARIANT *pVarResult, /* [out] */ EXCEPINFO *pExcepInfo, /* [out] */ UINT *puArgErr) = 0;
Главную трудность представляет собой параметр pDispParams, посредством которого конкретному методу с номером dispIdMember передаются входные параметры и, после его выполнения, возвращается результат. При желании можно в режиме трассировки посмотреть на код метода COleDispatchDriver::InvokeHelper(), чтобы не хотелось этого делать «вручную». С другой стороны, можно воспользоваться функцией InvokeHelper(), для того, чтобы «облегчить себе жизнь». Вот ее прототип: virtual void AFX_CDECL InvokeHelper( DISPID dwDispID, WORD wFlags, VARTYPE vtRet, void* pvRet, const BYTE* pbParamInfo, ... );
Параметры:
Функция COleDispatchDriver::InvokeHelper() на самом деле вызывает функцию COleDispatchDriver::InvokeHelperV(), которая подготавливает параметры для вызова «настоящего» метода IDispatch::Invoke() и делает его. Если обнаруживается, что сервер Word в данное время не запущен, то это можно сделать с помощью функции COleDispatchDriver::CreateDispatch(), которая инициирует создание СОМ объекта, идентифицируемого переданным ей параметром clsid, и прикрепление к нему интерфейса нашего объекта m_app. Если функция COleDispatchDriver::CreateDispatch() выполнится успешно, то процесс WinWord.exe будет запущен, но окно приложения Word отображаться не будет и приложения Word Вы не увидите ни в списке приложений менеджера задач, ни в строке панели задач (но в списке процессов менеджера задач он будет присутствовать). Можно работать с приложением Word и в таком состоянии, а если нужно сделать его видимым, то вызовите метод put_Visible(true) сервера Word, что и сделано в приведенном выше тексте программы. Завершить работу сервера Word может пользователь (если окно Word мы сделали видимым) или наша программа с помощью метода Quit(). Если первый параметр этого метода имеет значение true, то перед завершением Word будет выполнено автоматическое сохранение открытых в редакторе документов.
Так как многие методы серверов имеют тип VARIANT, который введен, в частности, для совместимости с Visual Basic, то необходимо ознакомиться с этим типом по подразделу конспекта. Вместо типа VARIANT в программе можно было использовать класс CComVariant, производный от tagVARIANT и являющийся классом-оболочкой для типа VARIANT. Так как этот класс имеет, в частности, несколько конструкторов, то его использование существенно упрощает текст программы: CComVariant SaveChanges(VARIANT_TRUE),DocumentFormat(1,VT_I4), Empty(VT_EMPTY);
Вот текст функции COleDispatchDriver::CreateDispatch(), обеспечивающей запуск сервера и получение диспетчерского интерфейса IDispatch:
BOOL COleDispatchDriver::CreateDispatch(REFCLSID clsid, COleException* pError) { ASSERT(m_lpDispatch == NULL); m_bAutoRelease = TRUE; /* good default is to auto-release create an instance of the object */ LPUNKNOWN lpUnknown = NULL; SCODE sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL | CLSCTX_REMOTE_SERVER, IID_IUnknown, (LPLP)&lpUnknown); if (sc == E_INVALIDARG) { // may not support CLSCTX_REMOTE_SERVER, so try without sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL & ~CLSCTX_REMOTE_SERVER, IID_IUnknown, (LPLP)&lpUnknown); } if (FAILED(sc)) goto Failed;
// make sure it is running sc = OleRun(lpUnknown); if (FAILED(sc)) goto Failed;
// query for IDispatch interface m_lpDispatch = QUERYINTERFACE(lpUnknown, IDispatch); if (m_lpDispatch == NULL) goto Failed;
lpUnknown->Release(); ASSERT(m_lpDispatch != NULL); return TRUE;
Failed: RELEASE(lpUnknown); if (pError != NULL) pError->m_sc = sc; return FALSE; }
Как найти информацию по объектам, предоставляемым серверами MS Office? Во-первых, это документация MSDN. Путь к нужному разделу справки в MSDN для MVS-2005 показан на рис. 2. В справочной системе описаны как объектные модели приложений MS Office, так и приведены примеры использования методов классов на языке VBA. Во-вторых, можно использовать такой сервис приложений MS Office, как запись макросов. Например, чтобы воспользоваться этим средством в MS Word, надо проделать такие операции: 4. Запустить на выполнение MS Word и включить запись макроса – Сервис/Макрос/Начать запись. В появившемся диалоговом окне можно изменить имя макроса и сферу его применения 5. Выполнить «вручную» те операции, которые необходимо запрограммировать. При этом возможно с помощью кнопок панели управления макроса приостановить или отменить его запись 6. После завершения всех операций остановить запись и открыть текст макроса, например, с помощью команды Сервис/Макрос/Редактор Visual Basic. Сгенерированный текст макроса можно использовать как шаблон для записи текста программы.
Рис. 2. Путь к разделу справки по программированию доступа к сервисам MSWord |
|||||||||||||||||||||
Последнее изменение этой страницы: 2018-04-12; просмотров: 411. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |