How to avoid 'Unable to load DLL' scenarios - c#

I'm trying to build a game using Monogame. Monogame uses its own bunch of DLLs. However inside one of those DLLs is a dependency on another DLL (which could potentially not exist as it was not installed).
More specifically when trying to utilize a method/class of Monogame's DLLs
GamePad.GetState(PlayerIndex.One).Buttons.Back
This error is produced:
Unable to load DLL 'xinput1_3.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
The fix for this error isn't difficult. The user needs to install the correct system requirements.
How do I tell this to the user from the front end? My aim is to inform the user that 'Gamepad controllers are disabled for this because xxx is not installed on your system', while carrying on running the game - as gamepads are optional.
Is there a way I could have caught this issue (i.e. is there a way I could have checked to see if this DLL exists - without being very specific of its location/filepath) before attempting to utilize the method/class?
Is having a try-catch block around the whole application the best approach?
Are there better ways to handling the (common?) 'Unable to load DLL' cases?
My main goal is to ignore any DLL dependency issues as I plan to distribute this game without installers. Plus any missing non-game-breaking DLLs should just be ignored.

One solution could be to programmatically check all system folders for the required dlls during startup and alert user if they are missing.
EDIT: There is a better solution, check using LoadLibrary() function, Check if a DLL is present in the system

You can check list of all .DLLs you need before running the app.
Of course you can alays rely on try and catch for DLLs which you never knew.

Related

Check if all required DLLs and their dependencies exist on target

Is there a good way in C# to check if all referenced DLLs are installed on the target machine?
What I want to achieve is that my software doesn't start if one of the referenced DLLs are missing on the target machine. Based on that I can be sure that my features won't break during runtime because a DLL can't be found.
My idea: Create a separate AppDomain during startup, and load ALL referenced DLLs to it. If it fails I'd shut down my software. If loading succeeds I'd unload the separate AppDomain and proceed to start the software. Is it a good idea to perform the check in such a manner, or are there some known problems/pitfalls around it.
I'm aware that I posted no corresponding piece of code, I only want to gather feedback if my idea is a good one or not.
Thx

Registration free activation of native COM (activex) component from .NET

I have a native dll (which is an activex control) that I need use with my .NET application without having to register the dll in the registry.
I have read several in depth posts about registration free activation, some of the better ones are
A lengthy one from Steve White and Leslie Muller
This one from samuel jack
And another from Mike Makarov
and from what I can see it is possible. However several hours and hundreds of tests later I just cant get it to work. I've done a bit of PInvoking and even less with ActiveX controls in .NET in my career, so would appreciate any input from anyone whom might have kicked goals on this before.
So far I'm following Steves advice, in terms of building an application that works and then trying to formulate the winning manifest file syntax via repeatedly running the regsvr32 command to add and remove the unmanaged dll's from the registry. Just a bog simple .Net console application with about 10 lines of code...
One part that I am confused about is the interop. The native dll's I have are also accompanied with managed runtime callable wrappers (RCW's). In my .NET application I add reference to these RCW's and then can consume the respective classes and functionality provided for by the unmanaged dll's. I'm not PInvoking via dllimport.
In creating the manifest files I'm unsure if I need to worry about these RCW's and how they work in a registration free scenario, or even if if they need to be in the compiled output?
I've also tried several tools such as (OLE/COM object viewer, Mt.exe from the windows sdk, and regsvr42 from codeproject). But the manifest structure and necessary GUID's all vary between tools and posts.
Current status is that I receive a InvalidCastException "Unable to cast COM object of type System.__ComObject to interface type MyFunkyDllLib.FunkyDllControl. This operation failed because the QueryInterface call on the COM component for the interface with IID '{some guid}' failed due to the following error: Library not registered.
Can anyone confirm the correct syntax for the application and dll manifest files ? Online posts even vary on the name with some using sxs in the name....
Update1:
Whilst Joe's answer below did not work it did give me some better insights into reg free COM. In the properties of the Interop dll (the one that that is added to the project reference from the list of installed COM components on the dev machine) I changed the Isolated Property to True. This has the effect of making VS dump a copy of the COM dll (not the interop, it is embeded in the exe) to the bin\debug folder. VS also then creates a myapplication.exe.manifest.
In this manifest file is supposedly sufficent information for reg free com. I found other posts indicating success with this method but in my case I still ended up with the same InvalidCastException.
Reading over Samuel Jacks post again, I tried his method of creating both a manifest for the exe and the COM dll using the clsid information from the VStudio output manifest when Isolated=true. (I also deleted the <file/> section created by VS from the exe.manifest). After unregistering the COM from the registry I now have success ! The application starts and does not error.
Why this approach works and not the Isolated=true I have no idea because it is beyond my knowledge of manifests and assemblies.
However we are still not at the wizards castle yet Toto.
Now I'm back at the same issue I posted on this SO thread. However in this scenario unit tests are not involved. Just a plain console application with 10 lines of code. Works fine when in normal registered COM mode, but not in reg free mode.
After many hours of trial and error I finally got a solution to how to successfully implement RegFree COM.
Here is a full explanation incase it helps someone else.
I create a new .NET class library in VS
Right click references and select the COM components of interest.
(Note: for the COM to be visible in the list they must be registered
on the development machine. This can be acheived by using the
Regsvr32.exe tool included with windows. Calling "regsvr32
mycomdll.dll" registers it in the windows registry)
Right click the COM reference, goto properties, and then set Isolated=True. This has the effect of causing VS to output a .manifest file supposedly containing all the registry details necessary for a consuming .exe to know what resources to load instead of querying the registry. However in my case it was incomplete. Calls to Interop methods would work, but events from the COM component would not. See step 5 for my solution)
Build the project. The .manifest should appear in the build output.
Open the manifest in notepad or similar. Within the <assembly /> tag I needed to add a <comInterfaceExternalProxyStub /> tag with appropriate IID, tlbid and proxyStubClsid32 GUID elements. Elements of the manifest are documented on msdn. In my case the proxy/stub was proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"/> which is the built in windows proxy. The iid and tlbid I originally discovered via Process Monitor whilst calling regsvr32. An easier and more reliable option I later discovered was to use a tool like SxS manifest maker as it added a second <comInterfaceExternalProxyStub /> that I originally did not have.
Create an exe project in VS and reference the previously built library.
Build the exe project.
Run regsvr32 /u mycomdll.dll. To remove all registry associations.
Run the exe. In my case calls to and events from the COM component in the class library worked perfectly.
Caveats: I dont know why VS does not include the <comInterfaceExternalProxyStub /> element automatically in the .manifest. At the time of writing the only way to automatically update the manifest was to add a post build Task in VS. In my case I copied the entire XML manifest into an XML in the class library project and then just overwrote the .manifest file in the build output.
Unit (integration) testing of the COM is inconsistent. Currently in my case calls to Interop methods work, but events do not. It has something to do with the fact that the Test Runner is not compiled with knowledge of the dependencies and therefore such are not present in the activation context.
You are probably missing a typelib declaration...but ignore that for now... Instead, do the following...
After playing with this on and off for a while, I decided that the easiest way to do it is using MSBuild and a GenerateApplicationManifest task. I've been using it with a unmanaged app, but I don't see why it would not work with a managed app. I say "app" ... because my app is managed but I have both COM libraries and .NET assemblies with ComVisible classes in them.
From your description it sounds like you are dealing with having COM and don't have to worry about consuming .NET assemblies from COM. You can google for MSBUILD and GenerateApplicationManifest to get an example MSBuild file.
So, I assume you will not need to populate the "Dependencies" attribute of the task. You will need to populate the "IsolatedComReferences" attribute with a list of your COM DLLs. They can be a simple semi-colon delimited list, but usually they are in "ItemGroup" declarations in the MSBuild project file. The COM DLLs need to be registered at the time you generate the manifest.
As for your RCW, there is nothing special you need to do. IMO, they don't need to be in the manifest. .NET has a way of finding them as long as they are in the same directory as your app/DLLs.
If you use MSBuild, you won't have to generate manifests for your COM DLLs... They probably already have manifests already... Usually, the wizards automatically generate manifests and embed them. The only manifest that will need the COM type information is the manifest you generate with MSBuild.
The whole point of the manifests used in this manner is to populate the manifest space with all the COM information that would be in the registry.

Launching C# WPF from Java causes FileNotFoundExceptions

I have a existing Java Project which needs functionality from a SDK written in C#. It should open a WPF Window and send the information back to Java on close.
For a basic connection of those two worlds i created a Java Project ("DotNetCaller") calling native functions. These are implemented in a C++/CLI Project ("DotNetBridge") which calls the C# Project ("DotNetApplication").
I already can set Strings from Java in C# and callback from C# to Java.
But as soon as i add a WPF Window and try to launch it with:
Application app = new Application();
app.Run(new DotNetWindow());
in a STA Thread it crashes.
The DotNetApplication doesnt find mscorlib.resources, after i provide the DLL, PresentationFramework.resources is missing and if i provide that, the DotNetApplication.resource is missing (which i cant provide).
If i call the DotNetApplication alone or from the DotNetBridge the Window displays as expected.
Can anyone tell ma what i'm really missing here?
Thanks
Edit:
I looked at this example once more and tried to adapt it to my needs.
I have set the dll directory of the ResolveEventHandler to the .NET dir in "Referenced Assemblies"
C:\Program Files (x86)\Reference
Assemblies\Microsoft\Framework.NETFramework\v4.0
and added a Window in C#.
It failed aswell but with a new exception in the C++ part rather than C#.
The ResolveHandler gets called with an empty argument causing an uncatchable exception in mscorelib.
I added a check if the String is empty and this basic approach works fine now.
I'm still unsure if i have the correct approach for this, so feel free to contribute.
Your AppDomain::AssemblyResolve handler probably needs to be overhauled and based on your own understanding of what you want to do. There is some guidance here. The basic rule is that you return nullptr for requests that you can't handle.
But first you have to plan the locations in which you want to deploy (and/or debug) your assemblies. A simple layout would be to put all of the assemblies that your JNI DLL depends on in the same folder as the JNI DLL (with the exception of any that will be installed in the GAC). You can then use its location to satisfy resolution requests. But remember to return nullptr if no file containing a manifest for an assembly with the requested name is present there. (This is likely the case with your ".resources" requests. If there isn't one it's okay unless you know otherwise.)
I'd be a little surprised if an assembly in a Reference Assemblies folder wasn't also in the GAC—but it'd be up to the assembly provider. Reference Assemblies is for design and build tools (e.g. Visual Studio). (The old way was for each folder that had assemblies in it to be registered for each version of Visual Studio so the assemblies could be used for design and build.) If a dependency is not in the GAC, you can use the "Copy Local" property on the reference to make it available for debugging.
You might find the Assembly Binding Log Viewer useful while designing and troubleshooting. With it you can see all the folders and extensions that are tried before giving over to calling the AppDomain::AssemblyResolve handler chain. (Disable logging when you are done.)

Accessing assemblies at design time in Blend 4

I am getting an exception from my code while designing in Blend 4.
I have narrowed the issue down to loading a specific library. Other libraries can be loaded fine, just this one fails. So, for this code:
var a = Assembly.Load("lib1");
var b = Assembly.Load("lib2");
Line two will throw an exception: Could not load file or assembly 'lib2' or one of its dependencies. The system cannot find the file specified.
If the same code is run outside of Blend, it does not throw. Both assemblies appear to be referenced the same way in the project, and both are marked Copy Local.
Any suggestions on how to troubleshoot this issue?
At design time Blend copies your assemblies to a temporary folder other than your output folder so things can behave differently than when you run the program normally. Blend also requires the "Any CPU" configuration for design time so if you run "x86" normally you can get different results simply because of that.
But Blend itself is a managed program like any other and to diagnose the problem in detail you can crack open the Fusion Log Viewer to see assembly binding errors to try to find out what is going wrong. Presumably the library itself is where it ought to be (in Blend's temporary folder) but one of its indirect dependencies is not being found. By using the log viewer with sufficient detail, you should be able to see the specific binding failure that is causing the problem.
Here is a link:
Fuslogvw.exe (Assembly Binding Log Viewer)

Deploying XBAP with win32 DLL

My XBAP application uses two win32 dlls and as usual many .Net dlls. Since we add .net references to the project itself, that is not a problem, as they all get deployed automatically when publishing the project; only that their names change from mydotnet.dll to mydotnet.dll.deploy.
But the problem is, the win32 dlls don't get deployed, neither their names change. And I understand the reason. It's because I call them using p/invoke techniques, and they're not added to the project. In fact, visual studio 2010 doesn't let me add them to the references. So I manually copied them to the publish-folder, and tried experimenting if that works. But it didn't work. The error the browser shows, is this:
System.DllNotFoundException: Unable to
load DLL 'Player.dll': The specified
module could not be found. (Exception
from HRESULT: 0x8007007E)
at Player.PlayerProxy.Initialize()
atRunaware.WpfBrowserApp.Player.Page1.PlayFile(Object
sender, RoutedEventArgs e)
Can anyone explain me what is going on? And any solution for that?
Previously I was trying to do what I want to do in Silverlight, but Austin suggested me to use XBAP to achieve the same thing. URL to the previous topic:
Handle to Silverlight UserControl
Can you try:
Checking your project properties under the Publish > Application Files section and if your native dlls appear there, making sure they are set to include.
Try including the dlls as content files in your project with copy to output directory set to Copy Always (I would think this may make them appear in the list of references mentioned in point 1, allowing you to set them to "Include").

Categories

Resources