11

私はExcelファイルからいくつかのデータを読み取るためにC++アプリケーションに取り組んでいます。私はそれを機能させましたが、私は一部について混乱しています。これがコードです(最初のセルのみを読み取るように簡略化されています)。

//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を呼び出すと例外が発生するのはなぜですか?

  2. CoUninitializeを呼び出さなかった場合の結果は何ですか?

  3. 私はここで完全に間違ったことをしていますか?

4

4 に答える 4

17

あなたが抱えている問題は範囲の1つです。簡単な答えは、CoInitとCoUninitをPtrから外部スコープに移動することです。例えば:

//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;
}

より長い答えは、Ptrsデストラクタ(Releaseを呼び出す)がmainの終了時に呼び出されているということです。これは、基本的に、アプリとCOMオブジェクト間の通信チャネルをシャットダウンするCoUnitの後です。

CoUnitを呼び出さなかった場合の結果は何ですか?短命のインプロセスCOMサーバーの場合、実際には悪影響はありません。

于 2010-04-16T15:09:02.013 に答える
5

洗練されたソリューションは、CoInitializeExとCoUninitializeを独自のクラスに配置することです。このレイモンドチェンの記事を参照してください。

于 2010-10-09T23:54:40.347 に答える
2

の意味はCoInitializeあなたのスレッドをアパートに入れることです。そしてCoUninitializeアパートからあなたの糸を取り除きます。

アパートにいないときにインターフェイスポインターを使用すると、作成されたアパートでのみ生のインターフェイスポインターを使用できるため、問題が発生します(別のアパートで使用するために、別のアパートにインターフェイスポインターをマーシャリングできます)。アパート)。

インターフェイスポインタを介して呼び出しを行い、オブジェクトが別のアパートメントに存在する場合(この場合はこれが当てはまります)、インターフェイスポインタは、アパートメント内のプロキシオブジェクトを呼び出し、RPCを介して宛先アパートメントのスタブと通信します。 。(を行うことによって)アパートを離れた場合CoUninitialize、この交通機関は利用できなくなり、エラーが発生します。

インプロセスサーバーを使用する場合は、トランスポート層が含まれていないため、Releaseを呼び出す前にCoUninitializeを実行する必要がない場合がありますが、これはお勧めできません。

ところで、CoInitializeSTAを入力するかどうかを指定する2番目の引数(つまり、スレッドがアパートメント内の唯一のスレッドになります。これを行うと、新しいアパートメントが作成されます)、またはMTA(プロセスごとに1つあります) )。

オプションはそれぞれCOINIT_APARTMENTTHREADEDとです。どちらが実際にあるCOINIT_MULTITHREADEDかを指定しました。私見では、マジックナンバーではなく、コードで記号名を使用する方が明確です。0COINIT_MULTITHREADED

于 2014-08-25T23:25:00.860 に答える
0

0はではありませんCOINIT_MULTITHREADED。0はCOINIT_APARTMENTTHREADEDhttps://docs.microsoft.com/en-us/windows/win32/api/objbase/ne-objbase-coinitを参照してください

于 2020-09-30T10:31:16.023 に答える