Run program with build errors - c#

This question might be a little bit weird, but I'd like my program to run with build errors. I am using windows forms (c#), and before initializing the main form, the program checks if I have Adobe Reader installed. This is necessary, because certain forms are designed to use Adobe's COM extension.
So I'd like my program to check at startup if Adobe Reader is installed, and if it is, continue, and if it is not, execute the supplied Adobe installer. My problem is that if Adobe Reader is not installed, the program won't even execute, so it can't even check for the installation, because it won't recognize certain parts of the code.
Do I have to use another program, which then executes the main one if Adobe is installed, or is there a workaround, so that I can use only the main application?

You should consider using some kind of Launcher or Installer that checks for all the requested prerequesites before it starts your program.
I suggest you just add another application that checks for adobe installation and after the validation/installation is finished to start your own application.

There are two parts to this "solution":
The way I've worked around this problem (so that it will at least build) is to include the referenced DLL/COM object's (on the reference, choose to "Copy to Local" and set it to true). Extract them to a folder and it should allow for you to at least build when the application has errors, since the references are available. I've seen this used extremely successfully against COM object.
Say you have a "Common Libraries" folder in your solution's base directory, you'll navigate to the bin directory after you build the application on a machine with a good copy of everything that's needed (the COM object for Adobe). You'll then copy the appropriate Adobe DLL's from that folder into the Common Libraries, remove the reference to the Adobe COM and then re-add pointing to the DLL's in the "Common Libraries" folder. You may have to choose NOT to embed the types in the application (also part of the Reference properties).
The second part is to check for the application and determine its state. I imagine even attempting to use the COM object without the application present should throw some kind of error -- and I've seen folks use try-catch blocks around to "fix" this. That's not a great programming practice, so anything you can do to scan for it otherwise is better, but for quick and simple, try-catch generally will work.

Related

IIS ASP.NET MVC and dllimport calls lock the file preventing future deployment

So I have a ASP.NET MVC project handling video files uploads, and I used the MediaInfo library (C++) along with the included C# wrapper (using DllImport functions) to determine the video duration. I added the MediaInfo.dll file to my project, and set the "copy to output directory" to always. Everything works perfectly.
My problem is that when I rebuild (from Visual Studio) or re-deploy the project to my production environment, it fails because the file is locked.
Unable to copy file "Sources\MediaInfo\MediaInfo.dll" to "bin\MediaInfo.dll". The process cannot access the file "bin\MediaInfo.dll" because it is being used by another process.
Of course, that's because IIS is still running. I'm aware I can stop the AppPool, rebuild, and restart it, but it is an hassle to do it every time you build in development, and complicate updates in production. Especially when every other DLLs (.NET) and the rest of the project can be updated without having to do that.
So I tried the method suggested here and here . Each time I want to scan a video, I use LoadLibrary() and after call FreeLibrary() until it returns false. The FreeLibrary part works, it unlock the file. But calling the method a second time, it calls LoadLibrary and then at the first DllImport function call, I get an InvalidOperationException and the process crash.
I feel like I'm overdoing thing and it don't feel normal and I'm wondering if I'm completely on the wrong track.
What's the usual method to develop using non-managed dll calls in a usual Visual Studio / MVC environment?
After reading more on the subject, if you want to control the DLL loading/unloading process, it can't be done with DllImport. You need to use GetProcAddress to call the functions. You could also create a C++/CLI library.
In my case, I managed to "hack" around the problem by creating a different AppDomain every time and forcing a FreeLibrary call and a AppDomain.Unload. This cause the DllImport to reload the dll successfully because it's a different AppDomain.

Generate a CIL executable not EXE then execute it

I have a c# project that generates an EXE file. Now, I'm in a "secure" corporate environment, where I can compile my project, but I cannot execute the EXE file.
As a Java programmer, I'm wondering if there is not a way to compile the c# project into something that would not be an EXE file, but a CIL file and then execute the CIL file by something that corresponds to java.exe in the dotnet world.
EDIT in response to comments:
I can run exe files that have been installed by a package manager
Yes, I know the corporate policy is stupid.
Well, this should be pretty easy.
.NET executables are simply DLLs like any other - the main difference being the executable format itself, and the fact that EXE files have an entry point, while DLLs don't.
It also means that you can load the EXE into memory exactly the same way as you would with a DLL:
Assembly.LoadFrom("SomeExe.exe");
You're already half way there - now we just need to find and execute the entry point. And unsurprisingly, this is also pretty trivial:
var assembly = Assembly.LoadFrom("SomeExe.exe");
assembly.EntryPoint.Invoke(null, null);
For most applications, this should work perfectly fine; for some, you'll have to make sure the thread you're using to invoke the entry point has STAThread or MTAThread respectively (Thread.TrySetThreadApartment if you're starting a new thread).
It might need tweaking for some applications, but it shouldn't be too hard to fix.
So you can just make some bootstrap application ("interpreter") that only really contains these two lines of code. If you can't get even that approved, and you really need something as an "official package", try some .NET application that allows you to execute arbitrary code - for example, LINQPad, or PowerShell.
EDIT:
This does have limitations, of course, and it does introduce some extra setup work:
The bootstrapper has to target the same or higher version of .NET Framework. .NET Portable might be particularly tricky, but I assume you have that well under control. It also has to have the same bitness (if specified explicitly).
You need to run the debugging through the bootstrapper. That actually isn't all too hard - just go to project properties, debug and select "Start external program".
The bootstrapper has to run under full trust conditions - it's necessary for reflection to work. On most systems, this simply means you have to have the exe as a local file (e.g. not from a network share). Tools like LINQPad will run under full trust by default.
The application must not depend on Assembly.GetEntryAssembly. This isn't used all that often, so it shouldn't be a problem. Quite a few similar issues should also be fine since you build the application you're trying to run yourself.

What files are mandatory in release windows form?

I have files in ...bin/release where is my windows form application, I have used EEPlus library as well. What the files do I need to send to client to have application work correctly?
My files:
name.exe
name.exe.config
name.pdb
name.vshost.exe
name.vshost.exe.config
name.vshost.exe.manifest
EEPlus.dll
EEPlus.xml
I know that first two are mandatory, but what about all rest?
thanks in advance
name.exe //necessary, it is your main executable
name.exe.config //necessary, it is your application config file
name.pdb //not necessary, it contains code and debug symbols configuration of your assembly, but let it be there, it is useful when users encounter a bug or crash
name.vshost.exe //not necessary, it is the hosting process of visual studio for debugging purposes
name.vshost.exe.config //not necessary, config file of name.vshost.exe
name.vshost.exe.manifest //not necessary, manifest of name.vshost.exe
EEPlus.dll //necessary, it is one of your application dependencies
EEPlus.xml //not necessary, contains some information for EEPlus.dll
reference for xml, reference for vshost, reference for pdb
All except *.pdb and *vshost*.
Really you should look at the REFERENCES of your project.
Generically all the assemblies that don't make part of the NET Framework need to be redistributed.
In this case, it seems that you need to distribute EEPlus.dll only.
The other files are there just as a byproduct of the compilation.
Of course, you should also consider that a thirdy party library could need other files, but this should be explained in their documentation under the redistrubute page.
You could try this:
Delete all files except the name.exe, name.exe.config and EEPlus.DLL, then run your app outside VS directly in the BIN\RELEASE folder. However I recommend to have a clean virtual machine where you could test your app and be sure to not forget anything.
Always
name.exe
name.exe.config
Dependency dlls
Interop dlls
First we check this mandatory files before giving to client, because at client, when running application that will be crashed without displaying any errors...

Open C:\windows\assembly\gac_msil from C#

How can I open C:\windows\assembly\gac_msil in a Windows Explorer window using C#?
Explanation: When I deploy an assembly to the GAC in my development environment, I like deploying the .pdb symbol file to the same directory as the assembly located at C:\Windows\assembly\GAC_MSIL\AssemblyName\Version__PublicKeyToken\. That way if I want to attach the Visual Studio debugger, it automatically finds the symbol file.
I've built a little utility that detects when I add one of my assemblies to the GAC and I want it to show a button that pops open the directory for me. I have the button and the path, but starting a process that launches explorer.exe with the path doesn't work. The only way I know of to open this directory in Windows is through the Run dialog.
You can't get to it within explorer or using the command line command: explorer.exe "C:\Windows\assembly\GAC_MSIL...". Only if you type the path into the Run dialog. So how do I do what the Run dialog is doing?
As Hans Passant at one time had answered, the old GAC is displayed by a shell extension which masks the directory structure. This is to make sure the assemblies in the GAC are managed properly. Opening the directory structure is intentionally not supported. In .NET 4, that is no longer the case so if you can upgrade, that's the way to go.
To programmatically open the old GAC there are a few options but again, it is normally masked for a reason. Options:
Remove the shell extension. You can unregister Shfusion.dll, open the directory, then re-register it. This, of course, could go wrong and leave you with Shfusion.dll permanently unregistered. This would allow other users to freely mess with the GAC directory structure and files which would cause it to become invalid and fall out of sync with the registry = bad.
Disable the shell extension. The HKLM Fusion registry key can have a DisableCacheViewer DWORD value. When set to 1, it will disable the view. The key can be set to 1, the window opened, then the key can be set back to 0. This approach has the same risks as option 1. Additionally, as a user (Damien) whose comment seems to have been deleted pointed out, other processes may also use this global key causing a race condition = bad.
Use a 3rd party application like Total Commander (thanks to Csaba Toth) or Far Manager to view the directory structure instead of Explorer. The downside here is, assuming they can even accept arguments to allow them to open to the GAC directory, it would require installing that software everywhere I want to run my app.
If you are considering using options 1 or 2, be aware that in most scenarios they are a bad idea and should be avoided unless you are messing around with your own machine. This directory structure is synchronized with the registry and should not be directly edited. Use Gacutil.exe to manage the assemblies in the GAC.

How to publish a beta version of a ClickOnce application?

I want to publish a beta version of my application every time it builds, so users can access the "beta" version and test features out before a general release.
I tried doing this by overriding the ProductName while running it to [product]-beta. The problem is the Publish process still creates a [product].application and it seems that the ClickOnce magic doesn't know the difference between a [product].application on one URL and a [product].application on another.
Any idea of how I would get around this?
I ran into a very similar problem and here is the solution I came up with.
I put all of my GUI forms into a DLL including the main startup form. I then created 2 EXE projects which reference my GUI dll. One has the name Product and the other ProductBeta.
The code in the EXE is virtually the same between both of them. Namely Application.Run(new MainForm()).
I then set them to publish to sub-directories on the same share.
It's annoying and has a bit of overhead but the results work very well.
As you've discovered, modifying the product name isn't sufficient. You need to modify the assembly name.
Details from http://weblogs.asp.net/sweinstein/archive/2008/08/24/top-5-secrets-of-net-desktop-deployment-wizards.aspx
The most important thing is having
support for multiple environments -
this isn't built in, and if you
attempt to deploy two different
ClickOnce builds with the same
deployment name to different sites,
the latest build will take precedence
and effectively overwrite the existing
deployment on the desktop.
The fix for this is relatively
straightforward - you need to provide
different deployment name for each
build. Like so -
<MSBuild
Projects="ClickOnce.csproj"
Targets="Publish"
Properties="
MinimumRequiredVersion=$(MinimumRequiredVersion);
ApplicationVersion=$(ApplicationVersion);
ApplicationRevision=$(ApplicationRevision);
CodeBranch=$(CodeBranch);
DeployEnv=$(DeployEnv)
AssemblyName=ClickOnce.$(DeployEnv);
PublishUrl=$(PublishUrl);
ProductName=ClickOnce $(CodeBranch) $(DeployEnv)" />
The one limitation of this approach is
that project references will no longer
work. Use file based assembly refs,
and it'll be fine.

Categories

Resources