void CreateExcelSpreadsheet(std::map<std::wstring, std::wstring> &mapProperties)
{
	CoInitialize(nullptr);
	auto aShutdown = std::experimental::make_scope_exit([]() ->void
	{
		CoUninitialize();
	});

	//
	// Make sure Excel is present...
	CLSID clsid;
	HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid);
	if(FAILED(hr))
	{
		MessageBoxW(HWND_TOP, L"Unable to find Excel.Application's CLSID.", L"Excel unavailable...", MB_TOPMOST | MB_ICONERROR);
		return;
	}

	Excel::_ApplicationPtr pXLApp;
	hr = pXLApp.CreateInstance(__uuidof(Excel::Application));
	if(FAILED(hr))
	{
		MessageBoxW(HWND_TOP, L"Unable to connect with Excel.", L"Excel unavailable...", MB_TOPMOST | MB_ICONERROR);
		return;
	}

	std::vector<std::wstring> vwstrInputFiles;
	if(false == ObtainInputFiles(vwstrInputFiles))
	{
		return;
	}

	//
	// Sort input files by nozzle diameter
	SortInputFiles(vwstrInputFiles);

	// Make Excel invisible. (i.e. Application.Visible = 0)
	pXLApp->Visible[0] = VARIANT_TRUE;

	// Create a new Excel Workbook. (i.e. Application.Workbooks.Add)
	Excel::WorkbooksPtr pXLBooks = pXLApp->Workbooks;
	_ASSERT(pXLBooks);
	if(nullptr == pXLBooks)
	{
		return;
	}

	Excel::_WorkbookPtr pXLBook = pXLBooks->Add();
	_ASSERT(pXLBook);
	if(nullptr == pXLBook)
	{
		return;
	}
	pXLApp->ActiveWindow->PutWindowState(Excel::xlMaximized);

	std::vector<std::wstring> vTabnames;
	bool bFirst = true;
	for(auto wstrFile : vwstrInputFiles)
	{
		std::array<wchar_t, 1024> wzFilename;
		_wsplitpath_s(wstrFile.c_str(), nullptr, 0, nullptr, 0, &wzFilename[0], wzFilename.size(), nullptr, 0);

		boost::property_tree::ptree tree;
		std::filebuf file;
		if(false == file.open(wstrFile.c_str(), std::ios::in))
		{
			continue;
		}
		std::istream inputStream(&file);
		boost::property_tree::xml_parser::read_xml(inputStream, tree);
		std::string strPropellantName(tree.get("Document.MotorData.Propellant", "-"));
		printf("NAME: %hs\n", strPropellantName.c_str());

		const std::string strMetric(tree.get("Document.MotorData.Metric", "False"));
		bool bMetric = (strMetric == "True");

		double dSelectedAvgStartTime = tree.get("Document.MotorData.SelectedAvgStartTime", 0.0f);
		double dSelectedAvgEndTime = tree.get("Document.MotorData.SelectedAvgEndTime", 0.0f);

		auto motorData = tree.get_child("Document.MotorData");
		std::vector<std::tuple<double, double, double, double, double> > vReadings;
		double dLastTime = dSelectedAvgStartTime;

		for(auto data : motorData)
		{
			if(data.first != "Item")
			{
				continue;
			}
			double dTime = data.second.get<double>("Time", -1.0f);
			double dThrust = data.second.get<double>("Thrust", -1.0f);
			double dPressure = data.second.get<double>("Pressure", -1.0f);
			//
			// Skip readings that were "selected" out in the TC Logger program
			// Useful for example to skip over an ignition spike...
			if(dSelectedAvgEndTime > 0.0f)
			{
				if(dTime < dSelectedAvgStartTime ||
					dTime > dSelectedAvgEndTime)
				{
					continue;
				}
			}
			double dTimeDelta = dTime - dLastTime;
			dLastTime = dTime;
			double dThrustElementN = bMetric ? (dTimeDelta * dThrust) : (dTimeDelta * (dThrust * g_dNewtonsPerPound));
			vReadings.push_back(std::make_tuple(dTime, dThrust, dPressure, dTimeDelta, dThrustElementN));
		}

		if(bFirst)
		{
			bFirst = false;
		}
		else
		{
			//
			// Create a new worksheet
			Excel::SheetsPtr pWorksheets = pXLBook->Worksheets;
			pWorksheets->Add();		// Becomes the active sheet...
		}

		//
		// Generate a workbook with data and a chart marking the 10% line, etc.
		// If successful and there are at least 3 files we will generate a sheet with a & n and average ISP
		std::wstring sanitizedFilename(&wzFilename[0]);
		SanitizeStringName(sanitizedFilename);
		if(true == ProduceExcelWorkbook(pXLBook, sanitizedFilename, strPropellantName, bMetric, tree, vReadings, mapProperties))
		{
			vTabnames.push_back(sanitizedFilename);
		}
	}

	//
	// If we have three or more sets of data we can generate an a & n:
	if(vTabnames.size() > 2)
	{
		Excel::SheetsPtr pWorksheets = pXLBook->Worksheets;
		pWorksheets->Add();		// Becomes the active sheet...
		ProduceAandNTab(pXLBook, vTabnames);
	}
	return;
}
Beispiel #2
0
DWORD WINAPI AutomateExcelByImport(LPVOID lpParam)
{
	// 在当前线程上初始化COM类库并通过调用CoInitializeEx或CoInitialize方法确认
    // 并发模型为单线程单元(STA)。
	// [-或者-] CoInitialize(NULL);
	// [-或者-] CoCreateInstance(NULL);
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

	try
	{

		/////////////////////////////////////////////////////////////////////
	    // 使用#import指令和智能指针创建Excel.Application COM对象

		// 选择1) 使用智能指针构造函数创建对象。
		// _ApplicationPtr 为原接口名称, _Application加上"Ptr"后缀。

		// Excel::_ApplicationPtr spXlApp(
		//	__uuidof(Excel::Application)	// 组件的CLSID 
		//	);

		// [-或者-]

		// 选择2) 使用智能指针函数CreateInstance创建对象
		Excel::_ApplicationPtr spXlApp;
		HRESULT hr = spXlApp.CreateInstance(__uuidof(Excel::Application));
		if (FAILED(hr))
		{
			wprintf(L"CreateInstance failed w/err 0x%08lx\n", hr);
			return 1;
		}

		_putws(L"Excel.Application is started");


		/////////////////////////////////////////////////////////////////////
		// 令Excel不可见(如: Application.Visible = 0)

		spXlApp->Visible[0] = VARIANT_FALSE;


		/////////////////////////////////////////////////////////////////////
		// 创建一个新的工作簿 (如: Application.Workbooks.Add)

		Excel::WorkbooksPtr spXlBooks = spXlApp->Workbooks;
		Excel::_WorkbookPtr spXlBook = spXlBooks->Add();

		_putws(L"A new workbook is created");


		/////////////////////////////////////////////////////////////////////
		// 获取处于活动状态的工作表并为其设置名称

		Excel::_WorksheetPtr spXlSheet = spXlBook->ActiveSheet;
		spXlSheet->Name = _bstr_t(L"Report");
		_putws(L"The active worksheet is renamed as Report");


		/////////////////////////////////////////////////////////////////////
		// 填充数据到工作表单元

		_putws(L"Filling data into the worksheet ...");

		// 为用户姓名构建一个5*2的安全数组
		VARIANT saNames;
		saNames.vt = VT_ARRAY | VT_VARIANT;
		{
			SAFEARRAYBOUND sab[2];
			sab[0].lLbound = 1; sab[0].cElements = 5;
			sab[1].lLbound = 1; sab[1].cElements = 2;
			saNames.parray = SafeArrayCreate(VT_VARIANT, 2, sab);

			SafeArrayPutName(saNames.parray, 1, L"John", L"Smith");
			SafeArrayPutName(saNames.parray, 2, L"Tom", L"Brown");
			SafeArrayPutName(saNames.parray, 3, L"Sue", L"Thomas");
			SafeArrayPutName(saNames.parray, 4, L"Jane", L"Jones");
			SafeArrayPutName(saNames.parray, 5, L"Adam", L"Johnson");
		}

		 // 将数组值填充到A2:B6区域(姓与名)
		// 获取区域A2:B6的Range对象

		param.vt = VT_BSTR;
		param.bstrVal = SysAllocString(L"A2:B6");
		Excel::RangePtr spXlRange = spXlSheet->Range[param];

		spXlRange->Value2 = saNames;

		// 清除数组
		VariantClear(&saNames);


		/////////////////////////////////////////////////////////////////////
		// 将工作簿保存为xlsx文件并关闭
		

		_putws(L"Save and close the workbook");

		// 确定文件名

		// 获取当前exe的目录
		wchar_t szFileName[MAX_PATH];
		if (!GetModuleDirectory(szFileName, ARRAYSIZE(szFileName)))
		{
			_putws(L"GetModuleDirectory failed");
			return 1;
		}

		// 将"Sample1.xlsx" 合并到目录
		wcsncat_s(szFileName, ARRAYSIZE(szFileName), L"Sample1.xlsx", 12);

		// 将空终止字符串转换为BSTR
		variant_t vtFileName(szFileName);

		spXlBook->SaveAs(vtFileName, Excel::xlOpenXMLWorkbook, vtMissing, 
			vtMissing, vtMissing, vtMissing, Excel::xlNoChange);

		spXlBook->Close();


		/////////////////////////////////////////////////////////////////////
		// 退出Excel应用程序(如:Application.Quit)
		 

		_putws(L"Quit the Excel application");
		spXlApp->Quit();


		/////////////////////////////////////////////////////////////////////
		// 释放COM对象
		// 

		// 为智能指针释放不必要的引用
		// ...
		// spXlApp.Release();
		// ...

	}
	catch (_com_error &err)
	{
		wprintf(L"Excel throws the error: %s\n", err.ErrorMessage());
		wprintf(L"Description: %s\n", (LPCWSTR) err.Description());
	}

	// 为该线程撤销COM
	CoUninitialize();

	return 0;
}