Applies ToOffice Products

現象

GetObject (Microsoft Visual Basic) または GetActiveObject (Microsoft Visual C++) を使用して Microsoft Office アプリケーションを自動化しようとすると、Office アプリケーションが実行されている場合でも、次のいずれかのエラー メッセージが表示されます。

エラー メッセージ 1

実行時エラー '429': ActiveX コンポーネントでオブジェクトを作成できない

エラー メッセージ 2

エラー: 0x800401e3 "操作を使用できません"

原因

Office アプリケーションは実行中ですが、実行中のオブジェクト テーブル (ROT) に登録されていない可能性があります。 Office アプリケーションの実行中のインスタンスは、GetObject (Visual Basic) または GetActiveObject (Visual C++) を使用してにアタッチする前に、ROT に登録する必要があります。Office アプリケーションが起動しても、実行中のオブジェクトはすぐには登録されません。 これにより、アプリケーションの起動プロセスが最適化されます。 Office アプリケーションは、起動時に登録する代わりに、フォーカスが失われると、実行中のオブジェクトを ROT に登録します。 そのため、GetObject または GetActiveObject を使用して、アプリケーションがフォーカスを失う前に、実行中の Office アプリケーションのインスタンスにアタッチしようとすると、上記のいずれかのエラーが発生する可能性があります。

解決方法

コードを使用すると、Office アプリケーションから独自のアプリケーション (または他のアプリケーション) にフォーカスを変更して、ROT に自身を登録できます。 さらに、コードが Office アプリケーションの exe ファイルを起動している場合は、実行中のインスタンスにアタッチする前に、Office アプリケーションの読み込みが完了するまで待つ必要がある場合があります。 「詳細情報」セクションの回避策として、コード サンプルが提供されています。

状態

この動作は仕様です。

詳細情報

ほとんどの場合、Office アプリケーションを自動化する開発者は、CreateObject (Visual Basic) または CoCreateInstance (Visual C++) を使用して Office アプリケーションの新しいインスタンスを起動する必要があります。ただし、既に実行されている Office アプリケーションを自動化する場合があります。たとえば、ユーザーが以前に Office アプリケーションを開始した場合などです。 または、コードを使用して Office アプリケーションの実行可能ファイルを起動した場合は、アプリケーションのコマンド ライン スイッチを指定できます。 実行中の Office アプリケーションを自動化するには、GetObject または GetActiveObject を使用する必要があります。

動作を再現する手順

  1. Microsoft Visual Basic を起動し、新しい Standard EXE プロジェクトを作成します。 Form1 は既定で作成されます。

  2. CommandButton コントロールを Form1 に追加します。

  3. フォームのコード モジュールに次のコードを追加します。

    Private Sub Command1_Click()
        Dim oExcel As Object
        ' Launch a new instance of Microsoft Excel:
        Shell "C:\Program Files\Microsoft Office\Office\Excel.EXE", _
           vbMinimizedNoFocus
        ' An error 429 occurs on the following line:
        Set oExcel = GetObject(, "Excel.Application")
        MsgBox oExcel.Name
        Set oExcel = Nothing
    End Sub
    
  4. コード サンプルで、Excel.exe の場所が正しいことを確認します。

  5. 既に実行されている場合は、Microsoft Excel を終了します。

  6. F5 キーを押してプロジェクトを実行し、[Command1] をクリックします。

回避策 

この問題を回避するには、次の操作を行います。

  • Shell 関数の 2 番目の引数を vbMinimizedFocus、vbMaximizedFocus、または vbNormalFocus のいずれかに変更して、Office アプリケーションにフォーカスを設定します。

  • Visual Basic にフォーカスを設定します。

  • Office アプリケーションの読み込み時間を計算しながら GetObject を試行します。

次の改訂コードは、この回避策を示しています。

Private Declare Sub Sleep Lib "kernel32" _
    (ByVal dwMilliseconds As Long)

Private Sub Command1_Click()
    Dim intSection As Integer
    Dim intTries As Integer
    Dim oExcel As Object

    ' Enable error handler for this procedure:
    On Error GoTo ErrorHandler

    ' Launch Microsoft Excel, giving it focus:
    Shell "C:\Program Files\Microsoft Office\Office\Excel.EXE", _
        vbMinimizedFocus 'other options for starting with
        'focus: vbMaximizedFocus and vbNormalFocus

    ' Move focus back to this form. (This ensures the Office
    '  application registers itself in the ROT, allowing
    '  GetObject to find it.)
    Me.SetFocus

    ' Attempt to use GetObject to reference the running
    '  Office application:
    intSection = 1 'attempting GetObject...
    Set oExcel = GetObject(, "Excel.Application")
    intSection = 0 'resume normal error handling

    ' Now you can automate Microsoft Excel:
    MsgBox oExcel.Name & ": able to GetObject after " & _
        intTries + 1 & " tries.", vbMsgBoxSetForeground

    ' Finished with automation so release your reference:
    Set oExcel = Nothing

    ' Exit procedure:
    Exit Sub

ErrorHandler:
    If intSection = 1 Then 'GetObject may have failed because the
    'Shell function is asynchronous; enough time has not elapsed
    'for GetObject to find the running Office application. Wait
    'wait 1/2 seconds and retry the GetObject. If you try 20 times
    'and GetObject still fails, assume some other reason
    'for GetObject failing and exit the procedure.
        intTries = intTries + 1
        If intTries < 20 Then
            Sleep 500 ' wait 1/2 seconds
            Resume 'resume code at the GetObject line
        Else
            MsgBox "GetObject still failing. Process ended.", _
                vbMsgBoxSetForeground
        End If
    Else 'intSection = 0 so use normal error handling:
        MsgBox Error$
    End If
End Sub

C++ の回避策

C++ でプログラミングする場合、次のコード サンプルは、上記の Visual Basic サンプルに示されているのと同様の回避策を示しています。 SetForegroundWindow は Excel からフォーカスを移動するために使用され、実行中のオブジェクトを登録できます。

//Store the handle of the currently active window...
HWND hwndCurrent = ::GetForegroundWindow();

//Launch Excel and wait until it is waiting for
//user input...
STARTUPINFO Start;
PROCESS_INFORMATION ProcInfo;
ZeroMemory(&Start,sizeof(STARTUPINFO));
Start.cb=sizeof(Start);
Start.dwFlags = STARTF_USESHOWWINDOW;
Start.wShowWindow = SW_SHOWMINIMIZED;

//Change the path to Excel as needed...
LPSTR pszExcelPath = 
      "c:\\program files\\microsoft office\\office\\excel.exe";

::CreateProcess(NULL, pszExcelPath, 0, 0, 1,
       NORMAL_PRIORITY_CLASS, 0, NULL, &Start, &ProcInfo);


if((::WaitForInputIdle(ProcInfo.hProcess, 10000))==WAIT_TIMEOUT)
{
    ::MessageBox(NULL, "Timed out waiting for Excel.", NULL,  
                 MB_OK);
}

//Restore the active window to the foreground...
//  NOTE: If you comment out this line, the code will fail!
::SetForegroundWindow(hwndCurrent);

//Initialize COM library...
::CoInitialize(NULL);

//Attach to the running instance...
CLSID clsid;
CLSIDFromProgID(L"Excel.Application", &clsid);  
IUnknown *pUnk = NULL;
IDispatch *pDisp = NULL;

for(int i=1;i<=5;i++) //try attaching for up to 5 attempts
{
   HRESULT hr = GetActiveObject(clsid, NULL, (IUnknown**)&pUnk);
   if(SUCCEEDED(hr)) 
   {
       hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDisp);
       break;
   }
   ::Sleep(1000);
}

if (!pDisp) {
    ::MessageBox(NULL, "Failed to find instance!!", "Error", 
                 MB_ICONHAND);
}
else {
    ::MessageBox(NULL, "Got instance of Excel!", "Success", MB_OK);
}

//Release the no-longer-needed IUnknown...
if (pUnk) 
    pUnk->Release();

//... Add your automation code for Excel here ...

//Release pDisp when no longer needed...
if (pDisp)
    pDisp->Release();

//Cleanup COM...
CoUninitialize();

関連情報

詳細については、次の記事番号をクリックして記事を表示します。

Office アプリケーションのインストール パスを見つける方法

ヘルプを表示

その他のオプションが必要ですか?

サブスクリプションの特典の参照、トレーニング コースの閲覧、デバイスのセキュリティ保護方法などについて説明します。

コミュニティは、質問をしたり質問の答えを得たり、フィードバックを提供したり、豊富な知識を持つ専門家の意見を聞いたりするのに役立ちます。