PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Visual Studio 2008/CppAutomateExcel/Solution1.cpp

#
C++ | 253 lines | 85 code | 41 blank | 127 comment | 2 complexity | 34e11c716aa4943194e5e9a57a8f210f MD5 | raw file
  1. /****************************** Module Header ******************************\
  2. * Module Name: Solution1.cpp
  3. * Project: CppAutomateExcel
  4. * Copyright (c) Microsoft Corporation.
  5. *
  6. * The code in Solution1.h/cpp demonstrates the use of #import to automate
  7. * Excel. #import (http://msdn.microsoft.com/en-us/library/8etzzkb6.aspx),
  8. * a new directive that became available with Visual C++ 5.0, creates VC++
  9. * "smart pointers" from a specified type library. It is very powerful, but
  10. * often not recommended because of reference-counting problems that typically
  11. * occur when used with the Microsoft Office applications. Unlike the direct
  12. * API approach in Solution2.h/cpp, smart pointers enable us to benefit from
  13. * the type info to early/late bind the object. #import takes care of adding
  14. * the messy guids to the project and the COM APIs are encapsulated in custom
  15. * classes that the #import directive generates.
  16. *
  17. * This source is subject to the Microsoft Public License.
  18. * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
  19. * All other rights reserved.
  20. *
  21. * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  22. * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
  23. * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  24. \***************************************************************************/
  25. #pragma region Includes
  26. #include <stdio.h>
  27. #include <windows.h>
  28. #include "Solution1.h"
  29. #pragma endregion
  30. #pragma region Import the type libraries
  31. #import "libid:2DF8D04C-5BFA-101B-BDE5-00AA0044DE52" \
  32. rename("RGB", "MSORGB") \
  33. rename("DocumentProperties", "MSODocumentProperties")
  34. // [-or-]
  35. //#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL" \
  36. // rename("RGB", "MSORGB") \
  37. // rename("DocumentProperties", "MSODocumentProperties")
  38. using namespace Office;
  39. #import "libid:0002E157-0000-0000-C000-000000000046"
  40. // [-or-]
  41. //#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.OLB"
  42. using namespace VBIDE;
  43. #import "libid:00020813-0000-0000-C000-000000000046" \
  44. rename("DialogBox", "ExcelDialogBox") \
  45. rename("RGB", "ExcelRGB") \
  46. rename("CopyFile", "ExcelCopyFile") \
  47. rename("ReplaceText", "ExcelReplaceText") \
  48. no_auto_exclude
  49. // [-or-]
  50. //#import "C:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" \
  51. // rename("DialogBox", "ExcelDialogBox") \
  52. // rename("RGB", "ExcelRGB") \
  53. // rename("CopyFile", "ExcelCopyFile") \
  54. // rename("ReplaceText", "ExcelReplaceText") \
  55. // no_auto_exclude
  56. #pragma endregion
  57. //
  58. // FUNCTION: GetModuleDirectory(LPWSTR, DWORD);
  59. //
  60. // PURPOSE: This is a helper function in this sample. It retrieves the
  61. // fully-qualified path for the directory that contains the executable
  62. // file of the current process. For example, "D:\Samples\".
  63. //
  64. // PARAMETERS:
  65. // * pszDir - A pointer to a buffer that receives the fully-qualified
  66. // path for the directory taht contains the executable file of the
  67. // current process. If the length of the path is less than the size that
  68. // the nSize parameter specifies, the function succeeds and the path is
  69. // returned as a null-terminated string.
  70. // * nSize - The size of the lpFilename buffer, in characters.
  71. //
  72. // RETURN VALUE: If the function succeeds, the return value is the length
  73. // of the string that is copied to the buffer, in characters, not
  74. // including the terminating null character. If the buffer is too small
  75. // to hold the directory name, the function returns 0 and sets the last
  76. // error to ERROR_INSUFFICIENT_BUFFER. If the function fails, the return
  77. // value is 0 (zero). To get extended error information, call
  78. // GetLastError.
  79. //
  80. DWORD GetModuleDirectory(LPWSTR pszDir, DWORD nSize);
  81. //
  82. // FUNCTION: SafeArrayPutName(SAFEARRAY*, long, PCWSTR, PCWSTR);
  83. //
  84. // PURPOSE: This is a helper function in the sample. It puts a user name
  85. // (first name, last name) into a 2D safe array. The array is in this
  86. // form:
  87. //
  88. // John Smith
  89. // Tom Brown
  90. // Sue Thomas
  91. //
  92. // Value in the first column is specified by pszFirstName. Value in the
  93. // second column is specified by pszLastName. SafeArrayPutName is used
  94. // add one entry (pszFirstName pszLastName) to the array on the row
  95. // indicated by the index parameter.
  96. //
  97. // PARAMETERS:
  98. // * psa - Pointer to an array descriptor created by SafeArrayCreate.
  99. // * index - The index of the name (first name, last name) in the array.
  100. // i.e. the first dimension of the 2D array.
  101. // * pszFirstName - The first name.
  102. // * pszLastName - The last name.
  103. //
  104. // RETURN VALUE: An HRESULT value indicating whether the function succeeds
  105. // or not.
  106. //
  107. HRESULT SafeArrayPutName(SAFEARRAY* psa, long index, PCWSTR pszFirstName,
  108. PCWSTR pszLastName);
  109. //
  110. // FUNCTION: AutomateExcelByImport(LPVOID)
  111. //
  112. // PURPOSE: Automate Microsoft Excel using the #import directive and smart
  113. // pointers.
  114. //
  115. DWORD WINAPI AutomateExcelByImport(LPVOID lpParam)
  116. {
  117. // Initializes the COM library on the current thread and identifies the
  118. // concurrency model as single-thread apartment (STA).
  119. // [-or-] CoInitialize(NULL);
  120. // [-or-] CoCreateInstance(NULL);
  121. CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  122. try
  123. {
  124. // Create the Excel.Application COM object using the #import
  125. // directive and smart pointers.
  126. // Option 1) Create the object using the smart pointer's constructor
  127. // _ApplicationPtr is the original interface name, _Application, with
  128. // a "Ptr" suffix.
  129. //Excel::_ApplicationPtr spXlApp(
  130. // __uuidof(Excel::Application) // CLSID of the component
  131. // );
  132. // [-or-]
  133. // Option 2) Create the object using the smart pointer's function,
  134. // CreateInstance
  135. Excel::_ApplicationPtr spXlApp;
  136. HRESULT hr = spXlApp.CreateInstance(__uuidof(Excel::Application));
  137. if (FAILED(hr))
  138. {
  139. wprintf(L"CreateInstance failed w/err 0x%08lx\n", hr);
  140. return 1;
  141. }
  142. _putws(L"Excel.Application is started");
  143. // Make Excel invisible. (i.e. Application.Visible = 0)
  144. spXlApp->Visible[0] = VARIANT_FALSE;
  145. // Create a new Workbook. (i.e. Application.Workbooks.Add)
  146. Excel::WorkbooksPtr spXlBooks = spXlApp->Workbooks;
  147. Excel::_WorkbookPtr spXlBook = spXlBooks->Add();
  148. _putws(L"A new workbook is created");
  149. // Get the active Worksheet and set its name.
  150. Excel::_WorksheetPtr spXlSheet = spXlBook->ActiveSheet;
  151. spXlSheet->Name = _bstr_t(L"Report");
  152. _putws(L"The active worksheet is renamed as Report");
  153. // Fill data into the worksheet's cells.
  154. _putws(L"Filling data into the worksheet ...");
  155. // Construct a 5 x 2 safearray of user names
  156. VARIANT saNames;
  157. saNames.vt = VT_ARRAY | VT_VARIANT;
  158. {
  159. SAFEARRAYBOUND sab[2];
  160. sab[0].lLbound = 1; sab[0].cElements = 5;
  161. sab[1].lLbound = 1; sab[1].cElements = 2;
  162. saNames.parray = SafeArrayCreate(VT_VARIANT, 2, sab);
  163. SafeArrayPutName(saNames.parray, 1, L"John", L"Smith");
  164. SafeArrayPutName(saNames.parray, 2, L"Tom", L"Brown");
  165. SafeArrayPutName(saNames.parray, 3, L"Sue", L"Thomas");
  166. SafeArrayPutName(saNames.parray, 4, L"Jane", L"Jones");
  167. SafeArrayPutName(saNames.parray, 5, L"Adam", L"Johnson");
  168. }
  169. // Fill A2:B6 with the array of values (First and Last Names).
  170. // Get Range object for the Range A2:B6
  171. VARIANT param;
  172. param.vt = VT_BSTR;
  173. param.bstrVal = SysAllocString(L"A2:B6");
  174. Excel::RangePtr spXlRange = spXlSheet->Range[param];
  175. spXlRange->Value2 = saNames;
  176. // Clear the safearray
  177. VariantClear(&saNames);
  178. // Save the workbook as a xlsx file and close it.
  179. _putws(L"Save and close the workbook");
  180. // Make the file name:
  181. // Get the directory of the current exe.
  182. wchar_t szFileName[MAX_PATH];
  183. if (!GetModuleDirectory(szFileName, ARRAYSIZE(szFileName)))
  184. {
  185. _putws(L"GetModuleDirectory failed");
  186. return 1;
  187. }
  188. // Concat "Sample1.xlsx" to the directory
  189. wcsncat_s(szFileName, ARRAYSIZE(szFileName), L"Sample1.xlsx", 12);
  190. // Convert the NULL-terminated string to BSTR
  191. variant_t vtFileName(szFileName);
  192. spXlBook->SaveAs(vtFileName, Excel::xlOpenXMLWorkbook, vtMissing,
  193. vtMissing, vtMissing, vtMissing, Excel::xlNoChange);
  194. spXlBook->Close();
  195. // Quit the Excel application. (i.e. Application.Quit)
  196. _putws(L"Quit the Excel application");
  197. spXlApp->Quit();
  198. // Release the COM objects.
  199. // Releasing the references is not necessary for the smart pointers
  200. // ...
  201. // spXlApp.Release();
  202. // ...
  203. }
  204. catch (_com_error &err)
  205. {
  206. wprintf(L"Excel throws the error: %s\n", err.ErrorMessage());
  207. wprintf(L"Description: %s\n", (LPCWSTR) err.Description());
  208. }
  209. // Uninitialize COM for this thread.
  210. CoUninitialize();
  211. return 0;
  212. }