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 オブジェクトは、インスタンス化の間に状態情報を保持することは想定しないでください。
次の手順は、
詳細
プロセス外で COM オブジェクトをインスタンス化するために使用できる 2 つの基本的なメソッドに関する情報を次に示します。
COM クライアントがオブジェクトのリモート処理を要求する
COM オブジェクトを呼び出す方法を変更することで、SQL Server アドレス空間の外部でオブジェクトを作成することを要求できます。
sp_OACreate
プロシージャを使用して COM オブジェクトを読み込む場合、既定ではプロセスで読み込まれます。 ただし、このプロシージャには、オブジェクトを作成する場所のコンテキストを示すために使用できるオプションの 3 番目のパラメーターがあります。 このパラメーターを指定しない場合は、既定の設定 5 が使用されます。これは、プロセスの内部または外部でオブジェクトを実行することを意味します。 パラメーターを 4 に変更する必要があります。これは、このコンポーネントがローカル実行可能ファイルとして実行されることを DCOM に示します。 次の例のような構文を使用して、sp_OACreate
ストアド プロシージャを使用して、プロセスから COM オブジェクトを実行するように DCOM に明示的に通知します。 DECLARE @object int DECLARE @hr int EXEC @hr = sp_OACreate 'SQLOLE.SQLServer', @object OUT, 4
拡張ストアド プロシージャ内に COM オブジェクトを作成する場合は、
CoCreateInstance
またはCoCreateInstanceEx
の 3 番目のパラメーターを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) を使用し、ProgID を All Objects の下の
OLEComponent.Object
の形式で見つけます。 COM オブジェクトを選択し、 Object メニューからCoCreateInstance
Flags を選択します。CLSCTX_LOCAL_SERVER
のみが選択されていることを確認します。 次に、[実装と Inproc Server] タブで、[代理処理の使用] 選択しPath to Custom Surrogate を空白のままにします。これにより、dllhost.exe ファイルを読み込み、COM DLL をプロセス空間内に取り込むことができます。レジストリを手動で更新するには、次の手順に従います。
警告
レジストリ エディターまたは別の方法を使用してレジストリを不適切に変更すると、深刻な問題が発生する可能性があります。 このような問題が発生した場合は、オペレーティング システムの再インストールが必要になることがあります。 マイクロソフトは、このような問題の解決に関して、一切責任を負わないものとします。 レジストリの変更はユーザー自身の責任において行ってください。
COM オブジェクトのクラス識別子 (CLSID) を取得します。 CLSID は 128 ビットの数値であり、この COM オブジェクトを含むコンポーネント、モジュール、またはファイルを一意に識別するために使用されるグローバル一意識別子 (GUID) と見なされます。 OLE オートメーション ストアド プロシージャを使用して COM オブジェクトを作成する場合、ストアド プロシージャの最初のパラメーターはプログラム識別子か、OLE オブジェクトの ProgID を使用して CLSID を派生させます。 この文字列は、OLE オブジェクトのクラスを表し、次の形式を持ちます。
OLEComponent.Object
プログラム識別子を使用して、COM オブジェクトのクラス識別子を検索できます。
レジストリ エディター (regedit.exe) を開き、
HKEY_CLASSES_ROOT
キーの下でFind
メソッドを使用して、 <OLEComponent.Object> の名前を持つキーを検索します。 他のレベルで見つかりますが、HKEY_CLASSES_ROOT
のすぐ下のレベルに配置する必要があります。 キーを見つけたら、キー名のフォルダーを展開すると、CLSID という名前のサブキーが表示されます。 そのフォルダーを選択すると、そのキー内の値が表示されます。 画面の右側には、Default という名前のタイトルがあります。 そのキーのデータは、次の形式である必要があります。{59F929A0-74D8-11D2-8CBC-08005A390B09}
この値をメモするか、メモ帳にコピーします。 角かっこを含めます。
HKEY_CLASSES_ROOT\CLSID
キーの下に移動し、この GUID 番号のサブキーを見つけます。HKEY_CLASSES_ROOT\CLSID
キーを強調表示した後、レジストリ エディターの [検索] 関数 ([Edit] メニューの下) を使用して、GUID を [Find] ダイアログ ボックスに貼り付けることができます。 COM DLL ファイルの場所を指すこのキーの下にある InprocServer32 サブキーを調べることで、適切なインターフェイスが見つかったことを確認します。 TypeLib キーがある場合は、この GUID 値を確認します。 これは、手順 1 で説明した内容とは異なる必要があります。 それ以外の場合は、COM オブジェクトの GUID ではなく TypeLib GUID があります。 ProgID サブキーの値はOLEComponent.Object.1
になります。 最後の 1 つは、このサンプル専用であり、バージョン情報に使用されます。GUID の InprocServer32 サブキーの下で、
ThreadingModel
値が存在し、両方または Free に設定されていることを確認して、マーシャリングが COM オブジェクトのスレッド モデルを理解して、SQL Server プロセス領域から COM を実行できるようにします。ThreadingModel
値がない場合、または Apartment に設定されている場合、COM オブジェクトのインスタンス化に一貫性がない可能性があります。Note
ThreadingModel
値を追加する場合は、実装する前に必ず COM オブジェクトをテストしてください。HKEY_CLASSES_ROOT\CLSID
キーの下にある GUID 番号/サブキーを強調表示します。 Edit メニューの [New] を選択し、[文字列値選択します。 Name 列に「AppID」と入力します。ENTER キーを押し手順 1 で書き込んだクラス識別子または GUID 番号を値として挿入します。 GUID は、次の例のように中かっこ内に配置する必要があります。
{59F929A0-74D8-11D2-8CBC-08005A390B09}
アプリケーション識別子 AppID は、DLL を実行可能ファイルに関連付けるために DCOM によって使用されます。
HKEY_CLASSES_ROOT\AppID
の下に新しいサブキーを追加し、前の手順で挿入したのと同じクラス識別子または GUID 番号に角かっこで囲んで名前を設定します。GUID 名を強調表示します。 Edit メニューの [New] を選択し、[文字列値選択します。 Name列に「dllSurrogate」と入力します。
この値の [データ] 列は空白のままにします。 データ列が空白であるため、既定の実行可能ファイルを実行し、 dllhost.exeし、そのプロセス空間内で COM オブジェクトを読み込むように DCOM に通知します。
レジストリ エディターを閉じます。 Start をクリックし、Run を選択します。 [ Run ] ダイアログ ボックスに「 DCOMCNFG」と入力します。
ENTER キーを押して、Distributed COM 構成プロパティダイアログ ボックスを開きます。 [既定のプロパティ] タブをクリックし、このコンピューターの Enable Distributed COM が選択されていることを確認します。 そうでない場合は、それを選択し、 Applyを選択します。
SQL Server が実行されている Windows NT ユーザー アカウントに、このオブジェクトのレジストリ キーに対する Full Control アクセス許可があることを確認します。 アクセス許可が十分でない場合、またはレジストリ キーが正しく入力されていない場合は、COM オブジェクトを作成するときに次のエラーが発生する可能性があります。
OLE オートメーションのエラー情報
HRESULT: 0x80040154
ソース: ODSOLE 拡張プロシージャ
説明: クラスが登録されていませんOLE オートメーションのエラー情報
HRESULT: 0x80070005
ソース: ODSOLE 拡張プロシージャ
説明: アクセスが拒否されました。OLE オートメーションのエラー情報
HRESULT: 0x80080005
ソース: ODSOLE 拡張プロシージャ
説明: サーバーの実行に失敗しましたこれが dllhost.exe ファイルを実行し、そのプロセス空間に COM オブジェクトを読み込むかどうかをテストして確認します。 これには、SQL Server が実行されている Windows NT コンピューター上に Windows NT リソース キットが存在する必要があります。 コマンド プロンプトを開き、コマンド プロンプトから tlist.exe ファイルを実行します。このファイルには、すべてのプロセスとそれに関連付けられているプロセス識別子またはプロセス識別子 (PID) が表示されます。
sp_OACreate
が実行され、その呼び出しが実行された後、スクリプトが終了する前に Transact-SQL スクリプトで、スクリプトの完了をさらに 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 プロセス空間に存在している間に実行されました。 COM オブジェクトを含むモジュールであるモジュール msado15.dllが読み込まれていることに注意してください。
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