PageRenderTime 68ms CodeModel.GetById 17ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

/Visual Studio 2008/CppAutomatePowerPoint/Solution2.cpp

#
C++ | 417 lines | 218 code | 68 blank | 131 comment | 26 complexity | 3e8ea483f0f0bf46b272e72372ba3cad MD5 | raw file
  1/****************************** Module Header ******************************\
  2* Module Name:  Solution2.cpp
  3* Project:      CppAutomatePowerPoint
  4* Copyright (c) Microsoft Corporation.
  5* 
  6* The code in Solution2.h/cpp demontrates the use of C/C++ and the COM APIs 
  7* to automate PowerPoint. The raw automation is much more difficult, but it 
  8* is sometimes necessary to avoid the overhead with MFC, or problems with 
  9* #import. Basically, you work with such APIs as CoCreateInstance(), and COM 
 10* interfaces such as IDispatch and IUnknown.
 11* 
 12* This source is subject to the Microsoft Public License.
 13* See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
 14* All other rights reserved.
 15* 
 16* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 17* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 18* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 19\***************************************************************************/
 20
 21#pragma region Includes
 22#include <stdio.h>
 23#include <windows.h>
 24#include "Solution2.h"
 25#pragma endregion
 26
 27
 28//
 29//   FUNCTION: AutoWrap(int, VARIANT*, IDispatch*, LPOLESTR, int,...)
 30//
 31//   PURPOSE: Automation helper function. It simplifies most of the low-level 
 32//      details involved with using IDispatch directly. Feel free to use it 
 33//      in your own implementations. One caveat is that if you pass multiple 
 34//      parameters, they need to be passed in reverse-order.
 35//
 36//   PARAMETERS:
 37//      * autoType - Could be one of these values: DISPATCH_PROPERTYGET, 
 38//      DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF, DISPATCH_METHOD.
 39//      * pvResult - Holds the return value in a VARIANT.
 40//      * pDisp - The IDispatch interface.
 41//      * ptName - The property/method name exposed by the interface.
 42//      * cArgs - The count of the arguments.
 43//
 44//   RETURN VALUE: An HRESULT value indicating whether the function succeeds 
 45//      or not. 
 46//
 47//   EXAMPLE: 
 48//      AutoWrap(DISPATCH_METHOD, NULL, pDisp, L"call", 2, parm[1], parm[0]);
 49//
 50HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, 
 51				 LPOLESTR ptName, int cArgs...) 
 52{
 53	// Begin variable-argument list
 54	va_list marker;
 55	va_start(marker, cArgs);
 56
 57	if (!pDisp) 
 58	{
 59		_putws(L"NULL IDispatch passed to AutoWrap()");
 60		_exit(0);
 61		return E_INVALIDARG;
 62	}
 63
 64	// Variables used
 65	DISPPARAMS dp = { NULL, NULL, 0, 0 };
 66	DISPID dispidNamed = DISPID_PROPERTYPUT;
 67	DISPID dispID;
 68	HRESULT hr;
 69
 70	// Get DISPID for name passed
 71	hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
 72	if (FAILED(hr))
 73	{
 74		wprintf(L"IDispatch::GetIDsOfNames(\"%s\") failed w/err 0x%08lx\n", 
 75			ptName, hr);
 76		_exit(0);
 77		return hr;
 78	}
 79
 80	// Allocate memory for arguments
 81	VARIANT *pArgs = new VARIANT[cArgs + 1];
 82	// Extract arguments...
 83	for(int i=0; i < cArgs; i++) 
 84	{
 85		pArgs[i] = va_arg(marker, VARIANT);
 86	}
 87
 88	// Build DISPPARAMS
 89	dp.cArgs = cArgs;
 90	dp.rgvarg = pArgs;
 91
 92	// Handle special-case for property-puts
 93	if (autoType & DISPATCH_PROPERTYPUT)
 94	{
 95		dp.cNamedArgs = 1;
 96		dp.rgdispidNamedArgs = &dispidNamed;
 97	}
 98
 99	// Make the call
100	hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
101		autoType, &dp, pvResult, NULL, NULL);
102	if (FAILED(hr)) 
103	{
104		wprintf(L"IDispatch::Invoke(\"%s\"=%08lx) failed w/err 0x%08lx\n", 
105			ptName, dispID, hr);
106		_exit(0);
107		return hr;
108	}
109
110	// End variable-argument section
111	va_end(marker);
112
113	delete[] pArgs;
114
115	return hr;
116}
117
118
119//
120//   FUNCTION: GetModuleDirectory(LPWSTR, DWORD);
121//
122//   PURPOSE: This is a helper function in this sample. It retrieves the 
123//      fully-qualified path for the directory that contains the executable 
124//      file of the current process. For example, "D:\Samples\".
125//
126//   PARAMETERS:
127//      * pszDir - A pointer to a buffer that receives the fully-qualified 
128//      path for the directory taht contains the executable file of the 
129//      current process. If the length of the path is less than the size that 
130//      the nSize parameter specifies, the function succeeds and the path is 
131//      returned as a null-terminated string.
132//      * nSize - The size of the lpFilename buffer, in characters.
133//
134//   RETURN VALUE: If the function succeeds, the return value is the length 
135//      of the string that is copied to the buffer, in characters, not 
136//      including the terminating null character. If the buffer is too small 
137//      to hold the directory name, the function returns 0 and sets the last 
138//      error to ERROR_INSUFFICIENT_BUFFER. If the function fails, the return 
139//      value is 0 (zero). To get extended error information, call 
140//      GetLastError.
141//
142DWORD GetModuleDirectory(LPWSTR pszDir, DWORD nSize);
143
144
145//
146//   FUNCTION: AutomatePowerPointByCOMAPI(LPVOID)
147//
148//   PURPOSE: Automate Microsoft PowerPoint using C++ and the COM APIs.
149//
150DWORD WINAPI AutomatePowerPointByCOMAPI(LPVOID lpParam)
151{
152	// Initializes the COM library on the current thread and identifies 
153	// the concurrency model as single-thread apartment (STA). 
154	// [-or-] CoInitialize(NULL);
155	// [-or-] CoCreateInstance(NULL);
156	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
157
158
159	/////////////////////////////////////////////////////////////////////////
160	// Create the PowerPoint.Application COM object using C++ and COM APIs.
161	// 
162
163	// Get CLSID of the server
164	
165	CLSID clsid;
166	HRESULT hr;
167	
168	// Option 1. Get CLSID from ProgID using CLSIDFromProgID.
169	LPCOLESTR progID = L"PowerPoint.Application";
170	hr = CLSIDFromProgID(progID, &clsid);
171	if (FAILED(hr))
172	{
173		wprintf(L"CLSIDFromProgID(\"%s\") failed w/err 0x%08lx\n", progID, hr);
174		return 1;
175	}
176	// Option 2. Build the CLSID directly.
177	/*const IID CLSID_Application = 
178	{0x91493441,0x5A91,0x11CF,{0x87,0x00,0x00,0xAA,0x00,0x60,0x26,0x3B}};
179	clsid = CLSID_Application;*/
180
181	// Start the server and get the IDispatch interface
182
183	IDispatch *pPpApp = NULL;
184	hr = CoCreateInstance(		// [-or-] CoCreateInstanceEx, CoGetObject
185		clsid,					// CLSID of the server
186		NULL,
187		CLSCTX_LOCAL_SERVER,	// PowerPoint.Application is a local server
188		IID_IDispatch,			// Query the IDispatch interface
189		(void **)&pPpApp);		// Output
190
191	if (FAILED(hr))
192	{
193		wprintf(L"PowerPoint is not registered properly w/err 0x%08lx\n", hr);
194		return 1;
195	}
196
197	_putws(L"PowerPoint.Application is started");
198
199
200	/////////////////////////////////////////////////////////////////////////
201	// Make PowerPoint invisible. (i.e. Application.Visible = 0)
202	// 
203
204	// By default PowerPoint is invisible, till you make it visible:
205	//{
206	//	VARIANT x;
207	//	x.vt = VT_I4;
208	//	x.lVal = 0;	// Office::MsoTriState::msoFalse
209	//	hr = AutoWrap(DISPATCH_PROPERTYPUT, NULL, pPpApp, L"Visible", 1, x);
210	//}
211
212
213	/////////////////////////////////////////////////////////////////////////
214	// Create a new Presentation. (i.e. Application.Presentations.Add)
215	// 
216
217	// Get the Presentations collection
218	IDispatch *pPres = NULL;
219	{
220		VARIANT result;
221		VariantInit(&result);
222		AutoWrap(DISPATCH_PROPERTYGET, &result, pPpApp, L"Presentations", 0);
223		pPres = result.pdispVal;
224	}
225
226	// Call Presentations.Add to create a new presentation
227	IDispatch *pPre = NULL;
228	{
229		VARIANT result;
230		VariantInit(&result);
231		AutoWrap(DISPATCH_METHOD, &result, pPres, L"Add", 0);
232		pPre = result.pdispVal;
233	}
234
235	_putws(L"A new presentation is created");
236
237
238	/////////////////////////////////////////////////////////////////////////
239	// Insert a new Slide and add some text to it.
240	// 
241
242	// Get the Slides collection
243	IDispatch *pSlides = NULL;
244	{
245		VARIANT result;
246		VariantInit(&result);
247		AutoWrap(DISPATCH_PROPERTYGET, &result, pPre, L"Slides", 0);
248		pSlides = result.pdispVal;
249	}
250
251	// Insert a new slide
252	_putws(L"Insert a slide");
253
254	IDispatch *pSlide = NULL;
255	{
256		VARIANT vtIndex;
257		vtIndex.vt = VT_I4;
258		vtIndex.lVal = 1;
259		
260		VARIANT vtLayout;
261		vtLayout.vt = VT_I4;
262		vtLayout.lVal = 2;	// PowerPoint::PpSlideLayout::ppLayoutText
263
264		VARIANT result;
265		VariantInit(&result);
266		// If there are more than 1 parameters passed, they MUST be pass in 
267		// reversed order. Otherwise, you may get the error 0x80020009.
268		AutoWrap(DISPATCH_METHOD, &result, pSlides, L"Add", 2, vtLayout, vtIndex);
269		pSlide = result.pdispVal;
270	}
271
272	// Add some texts to the slide
273	_putws(L"Add some texts");
274
275	IDispatch *pShapes = NULL;		// pSlide->Shapes
276	{
277		VARIANT result;
278		VariantInit(&result);
279		AutoWrap(DISPATCH_PROPERTYGET, &result, pSlide, L"Shapes", 0);
280		pShapes = result.pdispVal;
281	}
282
283	IDispatch *pShape = NULL;		// pShapes->Item(1)
284	{
285		VARIANT vtIndex;
286		vtIndex.vt = VT_I4;
287		vtIndex.lVal = 1;
288
289		VARIANT result;
290		VariantInit(&result);
291		AutoWrap(DISPATCH_METHOD, &result, pShapes, L"Item", 1, vtIndex);
292		pShape = result.pdispVal;
293	}
294
295	IDispatch *pTxtFrame = NULL;	// pShape->TextFrame
296	{
297		VARIANT result;
298		VariantInit(&result);
299		hr = AutoWrap(DISPATCH_PROPERTYGET, &result, pShape, L"TextFrame", 0);
300		pTxtFrame = result.pdispVal;
301	}
302
303	IDispatch *pTxtRange = NULL;	// pTxtFrame->TextRange
304	{
305		VARIANT result;
306		VariantInit(&result);
307		AutoWrap(DISPATCH_PROPERTYGET, &result, pTxtFrame, L"TextRange", 0);
308		pTxtRange = result.pdispVal;
309	}
310
311	{
312		VARIANT x;
313		x.vt = VT_BSTR;
314		x.bstrVal = SysAllocString(L"All-In-One Code Framework");
315		AutoWrap(DISPATCH_PROPERTYPUT, NULL, pTxtRange, L"Text", 1, x);
316		VariantClear(&x);
317	}
318
319
320	/////////////////////////////////////////////////////////////////////////
321	// Save the presentation as a pptx file and close it.
322	// 
323
324	_putws(L"Save and close the presentation");
325
326	{
327		// Make the file name
328
329		// Get the directory of the current exe.
330		wchar_t szFileName[MAX_PATH];
331		if (!GetModuleDirectory(szFileName, ARRAYSIZE(szFileName)))
332		{
333			_putws(L"GetModuleDirectory failed");
334			return 1;
335		}
336
337		// Concat "Sample2.pptx" to the directory
338		wcsncat_s(szFileName, ARRAYSIZE(szFileName), L"Sample2.pptx", 12);
339
340		VARIANT vtFileName;
341		vtFileName.vt = VT_BSTR;
342		vtFileName.bstrVal = SysAllocString(szFileName);
343
344		VARIANT vtFormat;
345		vtFormat.vt = VT_I4;
346		vtFormat.lVal = 24;	// PpSaveAsFileType::ppSaveAsOpenXMLPresentation
347
348		VARIANT vtEmbedFont;
349		vtEmbedFont.vt = VT_I4;
350		vtEmbedFont.lVal = -2;	// MsoTriState::msoTriStateMixed
351
352		// If there are more than 1 parameters passed, they MUST be pass in 
353		// reversed order. Otherwise, you may get the error 0x80020009.
354		AutoWrap(DISPATCH_METHOD, NULL, pPre, L"SaveAs", 3, vtEmbedFont, 
355			vtFormat, vtFileName);
356
357		VariantClear(&vtFileName);
358	}
359
360	// pPre->Close()
361	AutoWrap(DISPATCH_METHOD, NULL, pPre, L"Close", 0);
362
363
364	/////////////////////////////////////////////////////////////////////////
365	// Quit the PowerPoint application. (i.e. Application.Quit())
366	// 
367
368	_putws(L"Quit the PowerPoint application");
369	AutoWrap(DISPATCH_METHOD, NULL, pPpApp, L"Quit", 0);
370
371
372	/////////////////////////////////////////////////////////////////////////
373	// Release the COM objects.
374	// 
375
376	if (pTxtRange != NULL)
377	{
378		pTxtRange->Release();
379	}
380	if (pTxtFrame != NULL)
381	{
382		pTxtFrame->Release();
383	}
384	if (pShape != NULL)
385	{
386		pShape->Release();
387	}
388	if (pShapes != NULL)
389	{
390		pShapes->Release();
391	}
392	if (pSlide != NULL)
393	{
394		pSlide->Release();
395	}
396	if (pSlides != NULL)
397	{
398		pSlides->Release();
399	}
400	if (pPre != NULL)
401	{
402		pPre->Release();
403	}
404	if (pPres != NULL)
405	{
406		pPres->Release();
407	}
408	if (pPpApp != NULL)
409	{
410		pPpApp->Release();
411	}
412
413	// Uninitialize COM for this thread
414	CoUninitialize();
415
416	return 0;
417}