1. 程式人生 > >VS2010/MFC 利用OLE讀寫excel操作時,手動開啟其他excel文件程式崩掉的問題解決

VS2010/MFC 利用OLE讀寫excel操作時,手動開啟其他excel文件程式崩掉的問題解決

 問題點:

(1)我是利用excel儲存程式過程資料,300ms儲存一次。在程式執行過程中,如果手動開啟其他excel檔案,則程式建立的那個excel檔案也會被同時開啟。此時 如果把二者都關閉了,則程式崩潰。為了程式繼續執行,必須保持程式建立的那個excel開啟;

(2)如果在程式執行前,先開啟一個excel檔案然後關閉,再開啟程式則不會出現(1)的情況。


問題分析:

   “出現上述問題的原因是,當程式新建一個Excel.Application物件時,實際上在程序中新建了一個系統已經安裝的Excel程式的例項(此時程序中會有一個EXCEL.EXE),這其實與手動啟動Excel程式(注意,是啟動Excel程式,不是開啟xls檔案)是沒有分別的。只不過在程式中可以將Excel 物件設定為不可見。

  運行了一個EXCEL.EXE之後,就可以開啟xls檔案了。在程式中,可以使用xlApp.Workbooks.Open來指定使用哪一個Excel 物件來開啟xls檔案;而在手動開啟xls檔案時,系統總是自動查詢現有的EXCEL.EXE程序中最後建立的那個,並用它來開啟xls檔案。如果當前還沒有EXCEL.EXE程序執行,系統就會新建一個EXCEL.EXE程序,這就是我們一般雙擊開啟xls檔案時的情況。

   這裡需要提到EXCEL.EXE程式的一個特性:一個EXCEL.EXE可以開啟多個xls檔案。(不信你可以手動開啟很多xls檔案,然後看看工作管理員裡是不是隻有一個EXCEL.EXE程序。)有意思的是,當一個EXCEL.EXE開啟多個xls檔案時,這些xls檔案會各自獨立出現在工作列,好像它們源自不同的程序似的,容易給人錯覺。”

解決方法:

         (1)在建立程式使用的excel之前,先呼叫EXCEL.EXE建立一個供開啟其他excel檔案的excel_application_fake_,然後再呼叫EXCEL.EXE建立一個供程式使用的excel_application_。
BOOL OperationExcelFile::InitExcel()
{

	CoUninitialize();
	if(CoInitialize(NULL)==S_FALSE) 
	{ 
		AfxMessageBox(_T("初始化COM支援庫失敗!")); 
		return FALSE; 
	}

	//建立偽裝EXCEL伺服器yu20160813
	//防止程式使用過程中人為開啟其他excel造成程式崩潰
    if (!excel_application_fake_.CreateDispatch(_T("Excel.Application"),NULL)) 
    { 
        AfxMessageBox(_T("建立偽裝Excel服務失敗,你可能沒有安裝EXCEL,請檢查!")); 
        return FALSE;
    }
	excel_application_fake_.put_DisplayAlerts(FALSE); 
	excel_books_fake_.AttachDispatch(excel_application_fake_.get_Workbooks(),true); 

    //建立Excel 2000伺服器(啟動Excel) 
    if (!excel_application_.CreateDispatch(_T("Excel.Application"),NULL)) 
    { 
        AfxMessageBox(_T("建立Excel服務失敗,你可能沒有安裝EXCEL,請檢查!")); 
        return FALSE;
    }
    excel_application_.put_DisplayAlerts(FALSE); 

    return TRUE;
}

      (2)在程式退出時,要檢視是否有其他excel開啟。因為這些excel檔案使用excel_application_fake_開啟的,如果直接關閉程式這些excel檔案也會退出。

void OperationExcelFile::ReleaseExcel()
{
    excel_application_.Quit();
    excel_application_.ReleaseDispatch();
    excel_application_=NULL;

	//偽裝excel服務退出
	if( !excel_books_fake_.get_Count() )
	{
		excel_application_fake_.Quit();
		excel_application_fake_.ReleaseDispatch();
		excel_application_fake_=NULL;
	}
}