21

私のプログラムでは、Running Object Table (ROT) を使用して、プログラムのインスタンスが 1 つだけ実行されるようにしています。私は残念ながら会社を去った開発者からそのコードを「継承」しているため、問題を解決するのは貧しい人です。コードは問題なく動作しますが、39,000 のうち 3 人の顧客がAccessDeniedException. すべての顧客は、ユーザー モードでソフトウェアを実行します。

何が間違っている可能性がありますか?

bool retVal = false;
IMoniker[] arrMoniker = new IMoniker[1];
IBindCtx bindCtx = null;
string displayName;
int hResult;
int mkSys;
Guid clsidRot;
bool guidCompare = false;

IntPtr number = IntPtr.Zero;
moreObjectsListed = false;
objectFromRot = null;

try
{
    // check the objects in the running object table for fitting the specified class id
    while ((retVal == false) && (0 == enumMoniker.Next(1, arrMoniker, number)))
    {
        hResult = CreateBindCtx(0, out bindCtx);
        if (hResult == 0)
        {
            arrMoniker[0].IsSystemMoniker(out mkSys);

            if (mkSys == 4)
            {
                try
                {
                    // the display name is the class id of the object in the table
                    // --> AccessDeniedException raises here <--
                    arrMoniker[0].GetDisplayName(bindCtx, null, out displayName);
                    clsidRot = new Guid(displayName.Substring(1));  
                    guidCompare = clsidRot.Equals(clsid);
                }
                catch(Exception) {}

                // an object with fitting class id was found
                if (guidCompare == true)
                {
                    rot.IsRunning(arrMoniker[0]);
                    rot.GetObject(arrMoniker[0], out objectFromRot);
                    retVal = true;
                }
            }
        }
    }
}
finally
{
    if (arrMoniker[0] != null)
    {
        moreObjectsListed = true;
        Marshal.ReleaseComObject(arrMoniker[0]);
    }
    if (bindCtx != null)
    {
        Marshal.ReleaseComObject(bindCtx);
    }
}

編集: ROTにオブジェクトを登録するために要求されたコードは次のとおりです。

internal static extern uint RegisterActiveObject([MarshalAs(UnmanagedType.IUnknown)]object pIUnknown, ref Guid refclsid, uint flags, out uint pdwRegister);
internal const uint ActiveObjectStrong = 0;

...

NativeMethods.RegisterActiveObject(this, ref guid, NativeMethods.ActiveObjectStrong, out this.runningObjectTableRegisteredId);

編集2:

まず、すべての調査員にとって大きな言い訳です。AccessDeniedException は発生しません。これは System.UnauthorizedAccessException (HRESULT: 0x80070005 (E_ACCESSDENIED)) です。

次に、「調査者」ケン・ブリテンの質問に対する回答: - SharePointは混同されていません- ROT から正しいオブジェクトを要求することを確信しています - もう 1 つのヒントは、おそらく 3 つの問題のうちの 1 つ (39,000 が正常に動作していること以外) が実行されていることです。 WTS (Windows ターミナル サーバー) 上のアプリ

編集3:

これらの例外の 1 つのスタック トレースを次に示します。

System.UnauthorizedAccessException: Access denied (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
at System.Runtime.InteropServices.ComTypes.IRunningObjectTable.EnumRunning(IEnumMoniker& ppenumMoniker)
at Datev.Framework.DirectStart.RunningObjectTableClientManager..ctor()

残りのスタック トレースはコード内にあります。この場合、RunningObjectTableClientManager のコンストラクターで例外が発生することは注目に値します。そのコンストラクタのコードは次のとおりです。

private IRunningObjectTable rot;
private IEnumMoniker enumMoniker;

public RunningObjectTableClientManager()
{
    int retVal = GetRunningObjectTable(0, out this.rot);

    if (retVal == 0)
    {
        rot.EnumRunning(out this.enumMoniker);
    }
}
4

3 に答える 3

5

私の経験では、GUID 衝突の可能性はありそうにないように見えるため、調査されませんでした。私が取った最初のトラックは、AccessDeniedException. そこからさかのぼってみると、GetDisplayNameがこの例外を明示的にスローしない (または同様のものを返さない) ことがわかります。

では、何をしますか?コードは C# のようです。私が間違っていない限り、C# から COM を使用すると、主要な相互運用が行われます。IMoniker私が見つけたインターフェイスを公開する相互運用機能は 2 つだけです。

  • System.Runtime.InteropServices.ComTypesIMoniker を含む
  • Microsoft.VisualStudio.OLE.Interop IMonikerも 1 つ含まれています

あなたはアプリケーションについて話しているので、ランタイム バージョンを使用していると直感的にわかります。呼び出しを見ると、何らかの形式のAccess Denied HRESULTやそれに類するものを返す呼び出しが見つかりませんでした。VisualStudio相互運用機能では、アクセスと信頼について次のように言及しています: Using Libraries from Partially Trusted Code。これは従うべき道のように聞こえ、Visual Studio 相互運用機能を使用している場合に適用されます。

アセンブリに含まれているランタイム サービスの名前空間を使用している場合mscorlib.dll(このページによると、部分的に信頼されたコードによって呼び出し可能な .NET Framework アセンブリは、呼び出し可能な部分的に信頼されたコードとしてマークされています)、説明は適用されないようです。

んで、どうする?検索を行ったところ、MSDNで古いものとしてマークされているMicrosoft.Office.Server.ApplicationRegistry.Infrastructure.AccessDeniedExceptionAccessDeniedExceptionクラス以外のサポートされている実装が見つかりませんでした。クラスは、SharePoint 2010クラス ライブラリの下にファイルされます。

では、私の質問は次のとおりです。どの相互運用機能を使用していますか? SharePoint はまったく混在していますか? 以前、GUID の衝突は疑われないと言いましたが、今はその仮定に疑問を投げかけています。ROT から適切なオブジェクトを要求していますか? このオブジェクトは別のプロセス (つまり、あなたのものではない) で実行されていますか?

于 2011-11-22T13:30:44.937 に答える
1

このサイトから、レジストリ設定またはテーブルに登録されたオブジェクトのセキュリティ設定が原因である可能性があるようです。

           Check "HKLM\Software\Network OLE\Enabled". Fail the    
           request if zero.                                       

           Check "HKCU\Software\Network OLE\Enabled". Fail the        
           request if zero.                                           
           Before performing any operation against a ROT entry        
           (i.e., IRunningObjectTable::Revoke,                        
           IRunningObjectTable::IsRunning,                            
           IRunningObjectTable::GetObject,                            
           IRunningObjectTable::NoteTimeChange,                       
           IRunningObjectTable::GetTimeOfLastChange, or when          
           including an entry in an IEnumMoniker::Next of an          
           IEnumMoniker returned from                                 
           IRunningObjectTable::EnumRunning), check the call against  
           the SECURITY_DESCRIPTOR available from                     
           IRunningObjectTable::Register. This will be either the     
           value returned by the object's                             
           IActivationSecurity::GetSecurityDescriptor at the time of  
           IRunningObjectTable::Register or will have been taken      
           from "HKCU\Software\Network OLE\DefaultROTSecurity" or     
           "HKLM\Software\Network OLE\DefaultROTSecurity" at the      
           time of IRunningObjectTable::Register if the object did    
           not support IActivationSecurity.
于 2011-12-01T02:46:04.377 に答える
1

おそらくこれはあなたが探している答えではないかもしれませんが、このコードを継承したことで、これがあなたのユースケースにとって正しいテクニックであったかどうか疑問に思ったことはありませんか? 複数のアプリ インスタンスを防止するなどの目的で Com Interop を使用する C# アプリを見たのはこれが初めてです。私は Com で良い経験をしたことがなく、同様の原因不明または文書化されていない例外を見つけました。

複数のアプリケーション インスタンスを防止するための代替手法を検討してみませんか? 私は過去のソリューションでミューテックスを使用しましたが、問題はありませんでした。私は過去のコードを手元に持っていませんが、この問題は以前にスタックオーバーフローで数回取り上げられており、ピアレビューされ、コミュニティが編集したいくつかのかなり良い回答があります。

たとえば、「C# でグローバル ミューテックスを使用するための適切なパターンは何ですか? 'には、あらゆる種類の奇妙なボールの競合状態とスレッド/プロセスの終了、および潜在的なセキュリティの問題を考慮しているように見える、コミュニティが編集した優れた回答があります。

したがって、Com Interop から離れて、代わりに Mutex の実装を取得することをお勧めします。

于 2011-12-01T07:25:34.770 に答える