私は現在、OutputDebugStringメッセージ(Windows Sysinternals DbgViewまたはDBMon.NETに似ています)をキャプチャするための簡単なアプリケーションを開発中です。ローカルセッション(Local \ DBWIN_BUFFER_READY、ローカル\ DBWIN_DATA_READY、ローカル\ DBWIN_BUFFER)からOutputDebugStringメッセージにアクセスするときは、すべてが期待通りに機能しています。問題Win32 API経由でグローバル(セッション0)OutputDebugStringメッセージをキャプチャしますか?
しかし、セッション0(つまり、グローバル\ DBWIN_BUFFER_READYなど)からの出力にアクセスしようとすると、出力は受信されません。 DbgViewの動作に基づいて、私はあるレベルの管理者権限でアプリケーションを実行する必要があるという前提で動作しています。私はSecurityDescriptorを正しく設定していないと思っています。あるいは、Global OutputDebugStringメッセージにアクセスするために何かが完全に欠けています。
私は以下のコードのスニペットを強調しているが、完全なソースはCodePlex
でいただければ幸い問題上の任意のヘルプや洞察力を見つけることができます。前もって感謝します!
セキュリティ記述子の構成
私はいくつかの異なる構成を試してみましたが、次のようにコミットされたコードは、現在見えます。
[DllImport("advapi32.dll", SetLastError = true)]
private static extern Boolean InitializeSecurityDescriptor(ref SecurityDescriptor sd, UInt32 dwRevision);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern Boolean SetSecurityDescriptorDacl(ref SecurityDescriptor sd, Boolean daclPresent, IntPtr dacl, Boolean daclDefaulted);
public SecurityDescriptor InitializeSecurityDescriptor()
{
const Int32 securityDescriptorRevision = 1;
var securityDescriptor = new SecurityDescriptor();
// Initialize the security descriptor.
if (!InitializeSecurityDescriptor(ref securityDescriptor, securityDescriptorRevision))
throw new Win32Exception(Marshal.GetLastWin32Error());
// Set information in a discretionary access control list
if (!SetSecurityDescriptorDacl(ref securityDescriptor, true, IntPtr.Zero, false))
throw new Win32Exception(Marshal.GetLastWin32Error());
return securityDescriptor;
}
このコードは、最終的にあなたが期待するように私DbWinMessageSourceクラスの設定で呼び出される...
_windowsApi.Advanced.InitializeSecurityDescriptor();
SecurityAttributesとイベント現在のCodePlexにコミットしたコードを使用している
Local \ **という接頭辞ですが、唯一の違いはLocal \ **がGlobal \ **に置き換えられていることです。しかし、これは期待どおりに出力をキャプチャしていないようです。ここでも、関連するコードスニペット...
public const Int32 ErrorAlreadyExists = 183;
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateEvent(ref SecurityAttributes sa, Boolean bManualReset, Boolean bInitialState, String lpName);
public Handle CreateLocalEvent(ref SecurityAttributes securityAttributes, String objectName)
{
Verify.NotWhitespace(objectName);
return CreateEvent(ref securityAttributes, "Local", objectName);
}
public Handle CreateGlobalEvent(ref SecurityAttributes securityAttributes, String objectName)
{
Verify.NotWhitespace(objectName);
return CreateEvent(ref securityAttributes, "Global", objectName);
}
private static Handle CreateEvent(ref SecurityAttributes securityAttributes, String objectNamePrefix, String objectName)
{
IntPtr handle = CreateEvent(ref securityAttributes, false, false, String.Format(@"{0}\{1}", objectNamePrefix, objectName));
if(Marshal.GetLastWin32Error() == ErrorAlreadyExists)
throw new Win32Exception(ErrorAlreadyExists);
if (handle == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
return new Handle(handle, CloseHandle);
}
ここでも、最終的にDbWinMessageSourceのセットアップに呼び出され、次のように:
_dbwinBufferReadyEvent = _windowsApi.Basic.CreateGlobalEvent(ref securityAttributes, "DBWIN_BUFFER_READY");
_dbwinDataReadyEvent = _windowsApi.Basic.CreateGlobalEvent(ref securityAttributes, "DBWIN_DATA_READY");
_dbwinBufferFile = _windowsApi.Basic.CreateGlobalFileMapping(ref securityAttributes, "DBWIN_BUFFER");
私はのOutputDebugStringアペンダでlog4netのを使用して簡単なWebアプリケーションをテストしてい設定されます。 Visual Studioでアプリケーションを実行しているときに、すべてのローカル出力を期待どおりにキャプチャします。アプリケーションをIISに移動して、グローバルセッションで何かを取得するようにコードを構成すると、私は何も得られない。 DbgViewがIISからの出力をキャプチャしていることを確認しました(間違いなく間違いありません)。
うまくいけば十分な文脈ですが、より多くの情報や詳細が必要な場合は、お知らせ下さい。
注:Windows 7 Professionalで開発することで違いがあります。
EDIT Tyranid(ルーク)で指摘したように
は、必要とされなければならないことすべては、管理者priviledges、およびSE_CREATE_GLOBAL_NAMEです。私はいくつかのテストを実行し、上のコード設定は実際にはをキャプチャしています。グローバルメッセージ(たとえば、IISRESET中)。上記のコードは、アプリケーションがIISの内部(VSセッション中にLocal \ **を経由してルーティングされる)で実行されているとき、Log4Net OutputDebugStringアペンダからのデータをキャプチャしていません。すべてのWin32 API呼び出しが正常に返されているか、Marshal.GetLastWin32Error().
呼び出し時にエラーが返されていません。現在のWindowsトークンにSE_CREATE_GLOBAL_NAMEがあることを確認するコードを追加しました。コードの荒さは次のようになります。
using (var identity = WindowsIdentity.GetCurrent())
{
if (identity == null)
return;
TokenPrivilege tp;
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValue(null, SE_CREATE_GLOBAL_NAME, ref tp.Luid))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!AdjustTokenPrivileges(identity.Token, false, ref tp, Marshal.SizeOf(tp), IntPtr.Zero, IntPtr.Zero))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
これ以上の洞察があれば幸いです。
正確には動作しません。オブジェクトは正常に作成されていますか?いくつかの特定の機能は失敗しますか? – Luke
これはネイティブコードを使ってテストされており、うまく動作します。唯一の注意点は、1)管理者として実行する必要があり、2)SeCreateGlobalPrivilegeを有効にする必要があることです。 – Luke
@ルーク、タイニッド氏は以下のように指摘しました。欠けている部分はSeCreateGlobalPrivilegeです。私は正しい方向に私を指し示すが、それをテストするチャンスを持っていないと思う次のリンクを発見した:http://msdn.microsoft.com/en-us/library/aa446619(v=VS.85) ).aspx –