Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
244 views
in Technique[技术] by (71.8m points)

c# - Problems accessing the Running Object Table

In my program I use the Running Object Table (ROT) to ensure only one instance of my program is running. Since I "inherit" that code from a developer who unfortunately left the company, I am the poor guy to solve the problems. The code works fine, but we have 3 customers (out of 39,000) who will get an AccessDeniedException. Every customer runs the software in user mode.

Any suggestions what could be wrong?

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);
    }
}

Edit: Here is the requested code for the registration of an object in the 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);

Edit 2:

First of all a big EXCUSE to all investigators, we don't get an AccessDeniedException it is an System.UnauthorizedAccessException (HRESULT: 0x80070005 (E_ACCESSDENIED)).

Second the answers to the questions of "investigator" Ken Brittain: - SharePoint is not in the mix - I'am shure to request the correct object from ROT - Another hint maybe that 1 of the 3 problem (besides 39,000 working correctly) is running the apps on a WTS (Windows Terminal Server)

Edit 3:

Here is a stack-trace of one of those exceptions: (I've translated the stacktrace, because it was on a german machine)

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()

The rest of the stack trace is in our code. Markable in this case is that the exception is raised in the constructor of our RunningObjectTableClientManager. Here is the code of that constructor:

private IRunningObjectTable rot;
private IEnumMoniker enumMoniker;

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

    if (retVal == 0)
    {
        rot.EnumRunning(out this.enumMoniker);
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In my experience the probability of a GUID collision, while possible appears unlikely, so it was not investigated. The first track I took was looking what could cause the AccessDeniedException. Working backward from there you can see that GetDisplayName does not explicitly throw this exception (or return anything similar).

So what does? Your code appears to be in C#. Unless I am mistaken using COM from C# will go through a primary interop. There are only two (2) interops that expose an IMoniker interface that I could find:

  • System.Runtime.InteropServices.ComTypes contains IMoniker
  • Microsoft.VisualStudio.OLE.Interop contains one as well IMoniker

You are talking about an application so my gut tells me you are using the runtime version. Looking at the calls I could not find a call returning any form of an Access Denied HRESULT or simething similar. The VisualStudio interop does mention the following about access and trust: Using Libraries from Partially Trusted Code. This sounded like a path to follow and would apply if your are using the Visual Studio interops.

If you are using the runtime services namespace which is contained in the mscorlib.dll assembly (which according to this page .NET Framework Assemblies Callable by Partially Trusted Code is marked as callable partially trusted code) the explanation does not appear to apply.

So now what? I did a search for AccessDeniedException and found no supported implementation other than an Microsoft.Office.Server.ApplicationRegistry.Infrastructure.AccessDeniedException class that is marked as obsolete in MSDN. The class is filed under the SharePoint 2010 class library.

So here are my questions: Which interop are you using? Is SharePoint in the mix at all? I said previously GUID collision was not suspected but now I am questioning that assumption. Are you requesting the proper object from the ROT? Is this object running under another process (meaning not yours)?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...