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