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);
}
}
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)?
From this site it appears it could be due to a registry setting or due to the security settings on an object registered in the table:
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.
Perhaps this isn't the answer you are looking for, but having inherited this code, have you stopped to question if this was even the right technique for your use case? This is the first time I've seen a C# app use Com Interop for something like preventing multiple app instances. I've never had good experiences with Com and found similar unexplained or undocumented exceptions.
Why not take a look at an alternative technique for preventing multiple application instances? I have used a Mutex in past solutions of mine and never had an issue. While I don't have my past code handy, this issue has been covered several times before on stackoverflow with some pretty good answers that have been peer reviewed and community edited.
For example 'What is a good pattern for using a Global Mutex in C#?' has a good community edited answer that seems to take into account all sorts of odd ball race conditions and thread/process terminations as well as the potential security issues.
So my recommendations would be to step away from Com Interop and grab a Mutex implementation instead.
Related
Following various examples from MS and elsewhere, I have written this piece of test code...
[ComImport]
[Guid("4AEEEC08-7C92-4456-A0D6-1B675C7AC005")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IInitializeWithWindow
{
void Initialize(IntPtr hwnd);
}
and..
private async Task<bool> TestCode()
{
StoreContext Store = StoreContext.GetDefault();
StoreAppLicense licence = await Store.GetAppLicenseAsync();
bool trial = licence.IsTrial;
bool full = licence.IsActive;
IInitializeWithWindow initWindow = (IInitializeWithWindow)(object)Store;
initWindow.Initialize(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
StoreProductResult App = await Store.GetStoreProductForCurrentAppAsync();
StoreProduct p = App.Product; // Title, price
string title = p.Title;
StorePrice price = p.Price;
return true;
}
And I call it with using
bool x = TestCode().Result;
It all compiles and runs, so I presumably have all the right usings and references added. But when run, the line:
IInitializeWithWindow initWindow = (IInitializeWithWindow)(object)Store;
stops with the exception..
Unable to cast object of type 'Windows.Services.Store.StoreContext'
to type 'IInitializeWithWindow'
and I have no clue why.
This is a C# program with a UWP wrapper creating an MSIX package.
This seems to be a pretty standard block adapted from various examples from MS.
Within VS 2019, I have associated the program with the store app.
The 'trail' and 'full' variables seem to be populating correctly.
I have called this from various locations, Constructor, random button, etc.
My questions...
Why does the cast throw an exception?
Is this an old way of doing things that no longer applies?
Does associating the package in VS 2019 to the store app make the call to IInitalizeWithWindow redundant?
How do I fix the code so that 'title' and 'price' populate correctly?
Heaps of head bashing and I finally have it working...
Considering that in the last few days there was not a combination/permutation that I did not try, I don't know really the logic of it working now, but anyway..
Within the UWP installer project I associated the project with the App in the Microsoft Store, then I removed the lines:
[ComImport]
[Guid("4AEEEC08-7C92-4456-A0D6-1B675C7AC005")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IInitializeWithWindow
{
void Initialize(IntPtr hwnd);
}
IInitializeWithWindow initWindow = (IInitializeWithWindow)(object)Store;
initWindow.Initialize(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
The rest is now working just fine. Funny as I had already associated the app with the store AND removed the offending lines. I must have done something just a little bit different this time!
I have a PoC to use some existing Java-codebase in some UWP-app using the most current Visual Studio Community 19 version 16.3.2 and the latest released IKVM 8.1.7195.0. The app builds and runs fine in Debug-mode, but fails to build already in Release-mode with the following error:
MCG0004:InternalAssert Assert Failed: ICE: trying to add a local var
with the same name, but different types. during
[_RegisterClipboardFormat] Ams.Oms.Poc
RegisterClipboardFormat is part of IKVM:
#DllImportAttribute.Annotation(value = "user32.dll", EntryPoint = "RegisterClipboardFormat")
private native static int _RegisterClipboardFormat(String format);
#cli.System.Security.SecuritySafeCriticalAttribute.Annotation
private static int RegisterClipboardFormat(String format)
{
return _RegisterClipboardFormat(format);
}
https://github.com/ikvm-revived/ikvm/blob/master/openjdk/sun/awt/IkvmDataTransferer.java#L95
What I'm wondering is which local variable the error message is referring to? Might be something added implicitly or might have to do with String in Java vs. string in C#? OTOH that file is clearly named .java.
Didn't find much about the error message in general, only the following two links seems to be more interesting:
Variables having same name but different type
Why doesn't C# allow me to use the same variable name in different scopes?
So I'm currently even unsure where the message comes from, Visual Studio/C# directly or IKVM during running code during building Release-mode. I strongly suspect the error is coming from Visual Studio/C#, though.
Searching for the function itself doesn't reveal much of help as well:
Sorry, AWT is not a supported part of IKVM.
https://sourceforge.net/p/ikvm/bugs/225/
Others seemed to have the same problem, because CN1 simply disabled that code entirely in their fork of IKVM:
//#DllImportAttribute.Annotation(value = "user32.dll", EntryPoint = "RegisterClipboardFormat")
//private native static int _RegisterClipboardFormat(String format);
#cli.System.Security.SecuritySafeCriticalAttribute.Annotation
private static int RegisterClipboardFormat(String format)
{
throw new Error("Not implemented");
//return _RegisterClipboardFormat(format);
}
https://github.com/ams-ts-ikvm/cn1-ikvm-uwp/blob/master/openjdk/sun/awt/IkvmDataTransferer.java#L95
Any ideas? Thanks!
There seems to be a workaround by not changing any code at all: The settings of the Release-build contain a checkbox if to use the .NET native toolbox for the build, which is enabled by default. By disabling that the build succeeds without any code change and is as fast as the Debug-build again. Before changing that, the Release-build took a lot longer as well.
Don't know what that means regarding actually calling native code, if that fails or not, because my app doesn't use those. I guess it would fail, depending on if it works in Debug or not. Additionally, I'm not sure if the Windows store accepts such a modified Release-build, but as UWP-apps aren't forced to use native code at all, I guess there's a good chance things are going to work.
I am working on a application which needs to communicate via COM interface with multiple CAD applications (not in the same time). I want to have nice and reusable code, but I came across problems with type casting of COM objects when I made generic application handle getter method.
What I tried so far:
This is the attempt I would like the most if it worked.
public static TCadAppType CadApp<TCadAppType>()
{
dynamic cadApp = default(TCadAppType);
//Here under Dynamic View/Message there is already an error
// Message = "Element not found. (Exception from HRESULT: 0x8002802B (TYPE_E_ELEMENTNOTFOUND))"
// cadVersion.Value evaluates to "SldWorks.Application"
cadApp = (TCadAppType)Marshal.GetActiveObject(cadVersion.Value);
//Following 2 lines of code are for testing purposes only, i am testing with Solidworks API
AssemblyDoc Assembly;
//The exception is thrown when I try to access some method from the Solidworks API
Assembly = (AssemblyDoc)cadApp.OpenDoc6("some parametras...");
}
Attempt using Convert class
// Another attempt using Convert class
public static TCadAppType CadApp<TCadAppType>()
{
dynamic cadApp = default(TCadAppType);
// cadVersion.Value evaluates to "SldWorks.Application"
cadApp = Marshal.GetActiveObject(cadVersion.Value);
cadApp = Convert.ChangeType(cadApp, typeof(SldWorks.SldWorks));
// Exception is thrown with the following message:
// Message = "Object must implement IConvertible."
}
I really thought that I am on the right track, since there is an article on Microsoft Docs website explaining how dynamic can help you with com interopt: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic#com-interop
Any ideas how I can do this runtime casting a keep my code as reusable as possible?
My software setup:
Win 10
Project is targeted for .NET 4.7.2
First Tests are with Solidworks 2019
Turns out that the my coding attempt 1 was valid c# code indeed.
I tried it using with Autodesk Inventor, and it works.
So the only thing left for me is to conclude that this is some bug from Solidworks and their COM interfacing.
Thank you Optional Option for your interest in the topic.
This question already has answers here:
SetWindowsHookEx failing in .NET 4.0 on 32-bit machine with "module not found"?
(3 answers)
Closed 5 years ago.
This question is a follow on from: How do you disable system hotkeys in user32.dll? . I have not added it to chat because after googling, this appears to be an issue and I haven't found a solution which works. The error code seems to have multiple causes, one of which being a possibly corrupt dll. The fact that I can't figure out whether or not this is the case is a problem.
The code from this question comes from:
https://www.codeproject.com/articles/7294/processing-global-mouse-and-keyboard-hooks-in-c Look for the file "HookManager.Callbacks.cs"
Useful: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
I keep getting the following error:
Error: System.ComponentModel.Win32Exception (0x80004005): The
specified module could not be found at
Gma.UserActivityMonitor.HookManager.EnsureSubscribedToGlobalKeyboardEvents()
in [REDACTED DIRECTORY]HookManager.Callbacks.cs:line 401
The code causing this:
private static void EnsureSubscribedToGlobalKeyboardEvents()
{
// install Keyboard hook only if it is not installed and must be installed
if (s_KeyboardHookHandle == 0)
{
//See comment of this field. To avoid GC to clean it up.
s_KeyboardDelegate = KeyboardHookProc;
//install hook
s_KeyboardHookHandle = SetWindowsHookEx(
WH_KEYBOARD_LL,
s_KeyboardDelegate,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]),
0);
//If SetWindowsHookEx fails.
if (s_KeyboardHookHandle == 0)
{
//Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set.
int errorCode = Marshal.GetLastWin32Error();
//do cleanup
//Initializes and throws a new instance of the Win32Exception class with the specified error.
throw new Win32Exception(errorCode); // this line is causing this
}
}
}
Unless I am mistaken, the culprit from the above code is:
s_KeyboardHookHandle = SetWindowsHookEx(
WH_KEYBOARD_LL,
s_KeyboardDelegate,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]),
0);
So does anyone understand what the problem here is?
What have I tried?
I have tried previously re-creating the entire project and copy+pasting code in case any of the program's other files were corrupted (from copying to/from USB). I had believed the problem was fixed (though I might be mistaken). The problem is now back and what I previously thought would work is not working (re-creating the project).
I will try other solutions I find online, which relate to problems with Windows. If anyone can see anything wrong with the code, please let me know. Though the code came from a very reliable source and loads of people have used it so this seems unlikely.
https://social.msdn.microsoft.com/Forums/en-US/b7d1a35f-3759-4217-91ba-e4416ac19d78/how-do-you-fix-error-code-0x80004005?forum=jscript
I tried the solution which involved "regsvr32 jscript.dll" and "regsvr32 vbscript.dll". It didn't work.
You exchange last two parameters of SetWindowsHookEx(): third parameter should be set to IntPtr.Zero for same process and last one is thread.
You can as well pinvoke the thread id:
[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();
SetWindowsHookEx(WH_KEYBOARD_LL, s_KeyboardDelegate, IntPtr.Zero, GetCurrentThreadId());
I have a C# dll that references a 3rd party dll. There are different versions of the 3rd party dll.
As you might expect if the latest 3rd Party dll is present I want to use the new functionality if not I want to execute the old functionality.
I wasn't sure how to achieve this but I thought the first thing to try would be a simple if statement that decides which function to call.
So I find the assembly, get its location and hence its version info. (I need the file version as the product versions are the same).
Then a simple
if (version >= 3) do x() else do y()
When I execute the code on a machine with version 2 installed I get a MissingMethodException regarding x(). I thought I had made a stupid mistake but the logic was correct. The version is 2 so x(); should not be executed. I decided to remove the offending method and replace it with a throw new Exception(). The exception is not thrown and the code completes successfully.
Here is the danger - I am thinking that this is due to branch prediction. This is dangerous because it is not an area I have any knowledge of and therefore making assumptions is a dangerous thing.
So my questions are:
Am I tacking this problem the wrong way - is there a more obvious solution that I am missing?
or
Is there a way to disable branch prediction (if that is the cause) or to somehow enforce/flag the if condition as a point that must be executed before continuing.
Here is the code being executed:
On a machine with version 3 installed then it is fine.
On a machine with version 2 installed I get a MissingMethodException regarding method x().
It I removed the call to x(); and uncomment the throwing of the exception - no exception is thrown.
Relevant code:
Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(3rdPartyClass));
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
if (fileVersionInfo.FileMajorPart >= 3)
{
// throw new Exception("aagghh");
x();
}
else
{
y();
}
Using reflection, it's possible to get a list of Methods available for a particular DLL (more specifically: Type).
You could use this methodinfo to dynamically invoke the method as specified in Vlad's solution.
In fact, you could leave out the version check and just try to find the intended method directly.
var methodX = assembly.GetType("sometype").GetMethod("X");
if (methodX != null)
{
methodX.Invoke(params);
}
else
{
assembly.GetType("sometype").GetMethod("Y").Invoke(otherParams);
}
Edit: This is not exactly what you want, but with this kind of reflection you can find the correct methods, also for your own assembly.
There is no "branch prediction": the runtime binding seems to happen as the method is executed.
So the workaround would be like this:
if (fileVersionInfo.FileMajorPart >= 3)
{
CallX();
}
else
{
CallY();
}
void CallX()
{
DependentClass.X();
}
void CallY()
{
DependentClass.Y();
}
However, anyway this seems to be a hack: you need to execute with the version of DLL you were linking against.
This is actually a more accurate answer :
Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(String));
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
ObjectHandle oh = Activator.CreateInstanceFrom("AssemblyName.dll", "namespace.class");
object o = oh.Unwrap();
Type to = o.GetType();
if (fileVersionInfo.FileMajorPart >= 3)
{
to.InvokeMember("Method X", BindingFlags.InvokeMethod, null, o, null);
}
else
{
to.InvokeMember("Method Y", BindingFlags.InvokeMethod, null, o, null);
}