我正在编写一个C++应用程序,从Excel文件中读取一些数据。我把它修好了,但有一部分我搞不懂。下面是代码(简化为只读取第一个单元格)。
//Mostly copied from http://www.codeproject.com/KB/wtl/WTLExcel.aspx
#import "c:\Program Files\Common Files\Microsoft Shared\OFFICE11\MSO.DLL"
#import "c:\Program Files\Common Files\Microsoft Shared\VBA\VBA6\VBE6EXT.OLB"
#import "C:\Program Files\Microsoft Office\Office11\excel.exe" rename ("DialogBox","ExcelDialogBox") rename("RGB","ExcelRGB") rename("CopyFile", "ExcelCopyFile") rename("ReplaceText", "ExcelReplaceText") exclude("IFont", "IPicture")
_variant_t varOption((long) DISP_E_PARAMNOTFOUND, VT_ERROR);
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwCoInit = 0;
CoInitializeEx(NULL, dwCoInit);
Excel::_ApplicationPtr pExcel;
pExcel.CreateInstance(_T("Excel.Application"));
Excel::_WorkbookPtr pBook;
pBook = pExcel->Workbooks->Open("c:\\test.xls", varOption, varOption, varOption, varOption, varOption, varOption, varOption, varOption, varOption, varOption, varOption, varOption);
Excel::_WorksheetPtr pSheet = pBook->Sheets->Item[1];
Excel::RangePtr pRange = pSheet->GetRange(_bstr_t(_T("A1")));
_variant_t vItem = pRange->Value2;
printf(_bstr_t(vItem.bstrVal));
pBook->Close(VARIANT_FALSE);
pExcel->Quit();
//CoUninitialize();
return 0;
}
字符串
我不得不注解掉对CoUninitialize的调用,以使程序正常工作。当CoUninitialize被取消注解时,我在程序退出时在comip. h中的_Release函数中得到一个访问冲突。
下面是comip.h的代码,这是值得的。
void _Release() throw()
{
if (m_pInterface != NULL) {
m_pInterface->Release();
}
}
型
我对COM编程不是很有经验,所以可能有一些明显的东西我错过了。
1.为什么调用CoUninitialize会导致异常?
1.不调用CoUninitialize的后果是什么?
1.我做错什么了吗?
4条答案
按热度按时间eqfvzcg81#
你遇到的问题是范围问题。简短的答案是将CoInit和CoUninit从Ptrs移动到外部范围。举例来说:
字符串
较长的答案是Ptrs析构函数(调用Release)在退出main时被调用。这是在CoUnit之后,它基本上关闭了应用程序和COM对象之间的通信通道。
不调用CoUnit的后果是什么?对于短寿命的进程内COM服务器,实际上没有任何负面影响。
f0ofjuux2#
一个优雅的解决方案是将CoInitializeEx和CoUninitialize放在它们自己的类中。看这个Raymond Chen article。
holgip5t3#
CoInitialize
的意思是将你的线程输入到一个单元中;CoUninitialize
从公寓中删除线程。当您不在单元中时使用接口指针会导致问题,因为您只被允许在创建它的单元中使用原始接口指针。(您可以封送指向另一个单元的接口指针,以便在另一个单元中使用它)。
当您通过接口指针进行调用时,对象驻留在另一个单元中(在本例中为真),您的接口指针将调用单元中的代理对象,然后该代理对象通过RPC与目标单元中的存根进行通信。如果你已经离开了公寓(通过执行
CoUninitialize
),那么这个传输将不再可用,导致你的错误。如果偶尔使用进程内服务器,您可以在调用Release之前执行CoUninitialize,因为不涉及传输层,但这不是一个好主意。
顺便说一句,
CoInitialize
的第二个参数指定您是否要输入STA(即你的线将是你公寓里唯一的线;这样做时会创建一个新单元)或MTA(每个进程都有一个MTA)。选项分别为
COINIT_APARTMENTTHREADED
和COINIT_MULTITHREADED
;你指定的0
实际上是COINIT_MULTITHREADED
。恕我直言,在代码中使用符号名称比使用一个神奇的数字更清楚。6ioyuze24#
0不是
COINIT_MULTITHREADED
。0是COINIT_APARTMENTTHREADED
。参考https://learn.microsoft.com/en-us/windows/win32/api/objbase/ne-objbase-coinit