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