SQL Server プロセスの外部で DLL ベースの COM オブジェクトを実行する

この記事では、SQL Server プロセスの外部で DLL ベースの COM オブジェクトを実行する方法について説明します。

元の製品バージョン: SQL Server
元の KB 番号: 198891

概要

Microsoft SQL Server は、OLE オートメーション ストアド プロシージャのセットまたは拡張ストアド プロシージャを使用して、カスタム コンポーネント オブジェクト モデル (COM) オブジェクトを読み込んで実行する機能を提供します。 既定では、DLL ベースの COM オブジェクトはプロセス サーバーと同様に読み込まれます。つまり、COM オブジェクトは、SQL Serverプロセス メモリ アドレス空間内に読み込まれるだけでなく、このメモリ アドレス空間へのフル アクセスも可能です。 したがって、SQL Server プロセス空間に読み込まれた COM オブジェクトは、任意の DLL ファイルと同じ規則に従う必要があります。 COM オブジェクトが、SQL Server プロセス内のメモリを上書きしたり、リソースをリークしたりして不安定になる可能性があります。

COM オブジェクトがSQL Server プロセスの堅牢性に影響を与える可能性がある場合は、この記事の手順を使用して、SQL Server プロセス領域の外部で COM オブジェクトをインスタンス化できます。 オペレーティング システムへの場所の透過性に関する分散コンポーネント オブジェクト モデル (DCOM) 仕様の実装により、SQL Server プロセス領域の外部で DLL ベースの COM オブジェクトを実行する機能が提供されました。

メイン アプリケーションのアドレス空間の外部で DLL ベースの COM オブジェクトを実行するプロセスは、リモート処理と呼ばれます。 リモート処理では、別の実行可能ファイルが、SQL Server実行可能ファイルの代わりに代理プロセスである必要があります。 DCOM Service Control Manager (rpcss.exe) で使用される既定の実行可能ファイルの名前は 、dllhost.exeです。 DCOM サポート構造では、dllhost.exe ファイルを使用して DLL をプロセス空間に読み込み、プロキシとスタブのペアを使用して、要求されたインターフェイスをクライアントに透過的にマーシャリングします。この場合はSQL Serverです。 この実行可能ファイルは、複数のインターフェイス/メソッド要求を同時に受け入れることができます。 インターフェイスの使用が完了すると、DCOM Service Control Manager (SCM) によって 、dllhost.exe ファイルのクリーンアップとアンロードが管理されます。 COM オブジェクトは、インスタンス化の間に状態情報を保持することは想定しないでください。

次の手順は、SQL Server プロセス空間で作成される DLL ベースの COM オブジェクト (インスタンス化sp_OACreateされる場合も拡張ストアド プロシージャでも) に適用できます。

詳細

COM オブジェクトをプロセス外でインスタンス化するために使用できる 2 つの基本的なメソッドに関する情報を次に示します。

COM クライアントがオブジェクトのリモート処理を要求する

COM オブジェクトを呼び出す方法を変更することで、SQL Server アドレス空間の外部にオブジェクトを作成することを要求できます。

  • COM オブジェクトがプロシージャを使用して sp_OACreate 読み込まれる場合、既定ではプロセスで読み込まれます。 ただし、このプロシージャには、オブジェクトを作成する場所のコンテキストを示すために使用できるオプションの 3 番目のパラメーターがあります。 このパラメーターを指定しない場合、既定の 5 つの設定 (5) が使用されます。これは、プロセスの内部または外部でオブジェクトを実行することを意味します。 パラメーターを 4 に変更する必要があります。これは、このコンポーネントがローカル実行可能ファイルとして実行されることを DCOM に示します。 次の例のような構文を使用して、ストアド プロシージャを使用して COM オブジェクトを プロセス外で 実行するように DCOM に明示的に sp_OACreate 通知します。

    DECLARE @object int
    DECLARE @hr int
    EXEC @hr = sp_OACreate 'SQLOLE.SQLServer', @object OUT, 4
    
  • COM オブジェクトが拡張ストアド プロシージャ内に作成された場合は、 または の 3 番目のCoCreateInstanceCoCreateInstanceExパラメーターを にCLSCTX_LOCAL_SERVER変更できます。 これは、 を使用 CoCreateInstanceした次のコード サンプルに示されています。

    HRESULT hr = CoCreateInstance(CLSID_Test, NULL, CLSCTX_LOCAL_SERVER,
    IID_IUnknown, (void**)&piunknown);
    

オブジェクトのリモート処理を強制するようにレジストリを変更する

COM クライアントを変更して、オブジェクトをプロセス外で作成するように要求できない場合は、オブジェクトを強制的にプロセス外に作成する 2 つの異なるメソッドが存在します。

  • Visual C++ に付属する OLE/COM オブジェクト ビューアー (oleview.exe) を使用し、[ すべてのオブジェクト] の形式OLEComponent.Objectで ProgID を見つけます。 COM オブジェクトを選択し、[ オブジェクト ] メニューから [フラグ] を選択 CoCreateInstance します。 が CLSCTX_LOCAL_SERVER 選択されていることを確認します。 次に、[ 実装 ] タブと [Inproc Server ] タブの [ サロゲート プロセスの使用 ] を選択し、[ カスタム サロゲートへのパス ] を空白のままにします。これにより、 dllhost.exe ファイルを読み込み、そのプロセス空間内に COM DLL を読み込むことができます。

  • レジストリを手動で更新するには、次の手順に従います。

    警告

    レジストリ エディタや他の方法を使用してレジストリを変更する際、適切に変更しないと重大な問題を引き起こす可能性があります。 このような問題が発生した場合は、オペレーティング システムの再インストールが必要になることがあります。 マイクロソフトは、このような問題の解決に関して、一切責任を負わないものとします。 レジストリの変更はユーザー自身の責任において行ってください。

    1. COM オブジェクトのクラス識別子 (CLSID) を取得します。 CLSID は 128 ビットの数値であり、この COM オブジェクトを含むコンポーネント、モジュール、またはファイルを一意に識別するために使用されるグローバル一意識別子 (GUID) と見なされます。 OLE オートメーション ストアド プロシージャを使用して COM オブジェクトを作成する場合、ストアド プロシージャの最初のパラメーターはプログラム識別子であるか、OLE オブジェクトの ProgID を使用して CLSID を派生させます。 この文字列は OLE オブジェクトのクラスを表し、次の形式を持ちます。

      OLEComponent.Object
      
    2. プログラム識別子を使用して、COM オブジェクトのクラス識別子を見つけることができます。

      レジストリ エディター (regedit.exe) を開き、キーのHKEY_CLASSES_ROOT下で メソッドをFind使用して、OLEComponent.Object> の名前を持つキーを<見つけます。 他のレベルで見つかりますが、 の直下のレベルに配置する HKEY_CLASSES_ROOT必要があります。 キーを見つけたら、キー名のフォルダーを展開すると、CLSID という名前のサブキーが表示されます。 そのフォルダーを選択すると、そのキー内の値が表示されます。 画面の右側には、Default という名前のタイトルがあります。 そのキーのデータは、次の形式にする必要があります。

      {59F929A0-74D8-11D2-8CBC-08005A390B09}

      この値をメモするか、メモ帳にコピーします。 角かっこを含めます。

    3. キーの下に HKEY_CLASSES_ROOT\CLSID 移動し、この GUID 番号を持つサブキーを見つけます。 キーをHKEY_CLASSES_ROOT\CLSID強調表示した後、[レジストリ] エディター ([編集] メニューの下) で [検索] 関数を使用し、[検索] ダイアログ ボックスに GUID を貼り付けることができます。 このキーの下にある InprocServer32 サブキーを調べて、適切なインターフェイスが見つかったことを確認します。これは、COM DLL ファイルの場所を指します。 TypeLib キーがある場合は、この GUID 値をチェックします。 これは、手順 1 で説明した内容とは異なる必要があります。 それ以外の場合は、COM オブジェクトの GUID ではなく TypeLib GUID があります。 ProgID サブキーの値 OLEComponent.Object.1は になります。 最後の 1 つは、このサンプル専用であり、バージョン管理情報に使用されます。

    4. GUID の InprocServer32 サブキーの下で、値がThreadingModel存在し、[両方] または [Free] に設定されていることを確認して、マーシャリングが COM オブジェクトのスレッド モデルを理解して、プロセス領域外での COM の実行SQL Server有効にします。 値がない ThreadingModel 場合、または Apartment に設定されている場合、COM オブジェクトのインスタンス化に一貫性がない可能性があります。

      注:

      値を追加する ThreadingModel 場合は、実装する前に COM オブジェクトをテストしてください。

    5. キーの下にある GUID 番号/サブキーを HKEY_CLASSES_ROOT\CLSID 強調表示します。 [ 編集 ] メニューの [ 新規] を選択し、[ 文字列値] を選択します。 [ 名前 ] 列に「 AppID」と入力します。

    6. Enter キーを押し、手順 1 で指定したクラス識別子または GUID 番号を値として挿入します。 GUID は、次の例のように中かっこ内に配置する必要があります。

      {59F929A0-74D8-11D2-8CBC-08005A390B09}
      

      アプリケーション識別子 AppID は、DLL を実行可能ファイルに関連付けるために DCOM によって使用されます。

    7. の下に新しいサブキーを HKEY_CLASSES_ROOT\AppID 追加し、前の手順で挿入したのと同じクラス識別子または GUID 番号に角かっこを付けて名前を設定します。

    8. GUID 名を強調表示します。 [ 編集 ] メニューの [ 新規] を選択し、[ 文字列値] を選択します。 [ 名前 ] 列に 「dllSurrogate」と入力します。

      この値の [データ] 列は空白のままにします。 データ列が空白であるため、既定の実行可能ファイル (dllhost.exe) を実行し、そのプロセス空間内で COM オブジェクトを読み込むよう DCOM に通知します。

    9. レジストリ エディタを閉じます。 [スタート] ボタンをクリックし、[ファイル名を指定して実行] をクリックします。 [ 実行 ] ダイアログ ボックスに「 DCOMCNFG」と入力します。

      Enter キーを押して、[分散 COM 構成プロパティ] ダイアログ ボックスを開きます。 [ 既定のプロパティ ] タブをクリックし、[このコンピューターで 分散 COM を有効にする] が選択されていることを確認します。 そうでない場合は、選択し、[ 適用] を選択します。

    10. SQL Serverが実行されているWindows NT ユーザー アカウントに、このオブジェクトのレジストリ キーに対するフル コントロールアクセス許可があることを確認します。 アクセス許可が十分でない場合、またはレジストリ キーが正しく入力されていない場合は、COM オブジェクトを作成するときに次のエラーが発生する可能性があります。

      OLE オートメーション エラー情報
      HRESULT: 0x80040154
      ソース: ODSOLE 拡張プロシージャ
      説明: クラスが登録されていません

      OLE オートメーション エラー情報
      HRESULT: 0x80070005
      ソース: ODSOLE 拡張プロシージャ
      説明: アクセスが拒否されます。

      OLE オートメーション エラー情報
      HRESULT: 0x80080005
      ソース: ODSOLE 拡張プロシージャ
      説明: サーバーの実行に失敗しました

    11. これがdllhost.exe ファイルを実行し、そのプロセス空間に COM オブジェクトを読み込むかどうかをテストして確認します。 これには、Windows NT リソース キットが、SQL Serverが実行されているWindows NT コンピューター上にある必要があります。 コマンド プロンプトを開き、コマンド プロンプトから tlist.exe ファイルを実行します。このファイルには、すべてのプロセスとそれに関連付けられているプロセス識別子(PID)が表示されます。 が実行され、その呼び出しが実行された後の Transact-SQL スクリプト sp_OACreate で、スクリプトが終了する前に、次のコマンドを使用して、スクリプトの完了をさらに 20 秒間遅延します。

      WAITFOR DELAY '000:00:20'
      

      スクリプトを実行し、すぐにコマンド プロンプトに移動し、 tlist.exe ファイルを実行します。 dllhost.exe PID をメモします。 tlist.exe 再実行し、PID をパラメーターとして渡します。 これは、dllhost.exe プロセス空間内に読み込まれる DLL を示しています。 DLL ベースの COM オブジェクトは、このプロセス内で実行中として一覧表示する必要があります。 スクリプトが戻ると、 tlist.exe をもう一度実行すると、 dllhost.exe プロセスが実行されなくなったことが明らかになります。

      次の出力例では、ADODB です。 接続オブジェクトは、SQL Serverプロセス領域の外部に作成されます。 このスナップショットtlist.exeを使用して、COM オブジェクトが dllhost.exe プロセス空間に存在している間に実行されました。 モジュール msado15.dll、COM オブジェクトを含むモジュールが読み込まれていることに注意してください。

      C:\>tlist dllhost
      275 dllhost.exe
      CWD: C:\NT40\system32\
      CmdLine: C:\NT40\System32\dllhost.exe {00000514-0000-0010-8000-00AA006D2EA4}
      -Embedding
      VirtualSize: 19180 KB PeakVirtualSize: 19180 KB WorkingSetSize: 1780 KB
      PeakWorkingSetSize: 1780 KB
      NumberOfThreads: 3
      278 Win32StartAddr:0x01001920 LastErr:0x00000000 State:Waiting
      215 Win32StartAddr:0x00001b5e LastErr:0x00000000 State:Waiting
      253 Win32StartAddr:0x00001b60 LastErr:0x000000cb State:Waiting
      4.0.1381.105 shp 0x01000000 dllhost.exe
      4.0.1381.130 shp 0x77f60000 ntdll.dll
      4.0.1381.121 shp 0x77dc0000 ADVAPI32.dll
      4.0.1381.133 shp 0x77f00000 KERNEL32.dll
      4.0.1381.133 shp 0x77e70000 USER32.dll
      4.0.1381.115 shp 0x77ed0000 GDI32.dll
      4.0.1381.131 shp 0x77e10000 RPCRT4.dll
      4.0.1381.117 shp 0x77b20000 ole32.dll
        6.0.8267.0 shp 0x78000000 MSVCRT.dll
                       0x1f310000 msado15.dll
       2.30.4265.1 shp 0x766f0000 OLEAUT32.dll
       4.0.1381.72 shp 0x77bf0000 rpcltc1.dll
      

関連情報

OLE オートメーション ストアド プロシージャ (Transact-SQL)