C# System.DllNotFoundException - c#

I have a simple application using a product activation system offered by cryptlex (cryptlex.com).
The program works correctly on my computer, but when I try to run the program on another machine it returns this error:
I've already made sure that the dll is inside the executable folder and everything looks OK.
When I remove all part of cryptlex the program works perfectly on any machine (x86-x64)
I used depencywalker to check for errors and found these two in the executable that uses cryptlex:
Windows 7 64bits,
.NET Version: 4.0

You can use Process Monitor to record all file activities of the program. Set a filter for your executable. After reproducing the error, save the log as XML file.
Then run ProcMon Analyzer (note: I'm the author of it). It will analyze the file and give a list of DLLs that were not found.
You could also do that manually, but note that some DLLs may not be found at first, but later be found when looking in the %PATH% environment variable etc. The tool will remove all those entries which have PATH NOT FOUND first but SUCCESS later.

While the DLL is present, have you checked the bitrate?
Most C# projects default to building against Any CPU - if the DLL is specific to a bitrate (ie x86 or x64) then it might be that the program picks the wrong bitrate on end machines (usually x86) but the right one on your machine (x64). This is usually best resolved by building out different x86 and x64 versions; it's messier, but only .NET itself is good at using the Any CPU paradigm.

The exception should have detail about what DLL in particular was not found - maybe look closer?
GPSVC and IESHIMS missing should not be a problem; as indicated by the hour glass, they're deferred dependencies anyway.

Related

Accessing Published Version Number In .Net6 Windows Forms App [duplicate]

I have a windows forms application that is deployed to two different locations.
Intranet - ClickOnce
Internet - Installed on a citrix farm through Windows installer
I display ClickOnce version number for click-once deployed versionApplicationDeployment.IsNetworkDeployed.
if (ApplicationDeployment.IsNetworkDeployed)
return ApplicationDeployment.CurrentDeployment.CurrentVersion;
But for the non-click application, I am not sure how to retrieve clickonce version unless I hardcode the version number in assembly info.
Is there an automatic way of retrieve ClickOnce version number for non-clickonce deployed version?
Add an assembly reference to System.Deployment to your project.
Import the namespace in your class file:
VB.NET:
Imports System.Deployment.Application
C#:
using System.Deployment.Application;
Retrieve the ClickOnce version from the CurrentVersion property.
You can obtain the current version from the ApplicationDeployment.CurrentDeployment.CurrentVersion property. This returns a System.Version object.
Note (from MSDN):
CurrentVersion will differ from UpdatedVersion if a new update has
been installed but you have not yet called Restart. If the deployment
manifest is configured to perform automatic updates, you can compare
these two values to determine if you should restart the application.
NOTE: The CurrentDeployment static property is only valid when the application has been deployed with ClickOnce. Therefore before you access this property, you should check the ApplicationDeployment.IsNetworkDeployed property first. It will always return a false in the debug environment.
VB.NET:
Dim myVersion as Version
If ApplicationDeployment.IsNetworkDeployed Then
myVersion = ApplicationDeployment.CurrentDeployment.CurrentVersion
End If
C#:
Version myVersion;
if (ApplicationDeployment.IsNetworkDeployed)
myVersion = ApplicationDeployment.CurrentDeployment.CurrentVersion;
Use the Version object:
From here on you can use the version information in a label, say on an "About" form, in this way:
VB.NET:
versionLabel.Text = String.Concat("ClickOnce published Version: v", myVersion)
C#:
versionLabel.Text = string.Concat("ClickOnce published Version: v", myVersion);
(Version objects are formatted as a four-part number (major.minor.build.revision).)
No I do not believe that there is a way. I believe the ClickOnce information comes from the manifest which will only be available in a ClickOnce deployment. I think that hard coding the version number is your best option.
I would simply make the assembly version of the main assembly the same as the CLickOnce version every time you put out a new version. Then when it runs as a non-clickonce application, just use Reflection to pick up the assembly version.
Try thread verification:
if (ApplicationDeployment.IsNetworkDeployed)
{
if (ApplicationDeployment.CurrentDeployment.CurrentVersion != ApplicationDeployment.CurrentDeployment.UpdatedVersion)
{
Application.ExitThread();
Application.Restart();
}
}
not that it matters three years later, but I ended up just parsing the manifest file with xml reader.
To expand on RobinDotNet's solution:
Protip: You can automatically run a program or script to do this for you from inside the .csproj file MSBuild configuration every time you build. I did this for one Web application that I am currently maintaining, executing a Cygwin bash shell script to do some version control h4x to calculate a version number from Git history, then pre-process the assembly information source file compiled into the build output.
A similar thing could be done to parse the ClickOnce version number out of the project file i.e., Project.PropertyGroup.ApplicationRevision and Project.PropertyGroup.ApplicationVersion (albeit I don't know what the version string means, but you can just guess until it breaks and fix it then) and insert that version information into the assembly information.
I don't know when the ClickOnce version is bumped, but probably after the build process so you may need to tinker with this solution to get the new number compiled in. I guess there's always /*h4x*/ +1.
I used Cygwin because *nix scripting is so much better than Windows and interpreted code saves you the trouble of building your pre-build program before building, but you could write the program using whatever technology you wanted (including C#/.NET). The command line for the pre-processor goes inside the PreBuildEvent:
<PropertyGroup>
<PreBuildEvent>
$(CYGWIN_ROOT)bin\bash.exe --login -c refresh-version
</PreBuildEvent>
</PropertyGroup>
As you'd imagine, this happens before the build stage so you can effectively pre-process your source code just before compiling it. I didn't want to be automatically editing the Properties\AssemblyInfo.cs file so to play it safe what I did was create a Properties\VersionInfo.base.cs file that contained a text template of a class with version information and was marked as BuildAction=None in the project settings so that it wasn't compiled with the project:
using System.Reflection;
using EngiCan.Common.Properties;
[assembly: AssemblyVersion("0.$REVNUM_DIV(100)$.$REVNUM_MOD(100)$.$DIRTY$")]
[assembly: AssemblyRevisionIdentifier("$REVID$")]
(A very dirty, poor-man's placeholder syntax resembling Windows' environment variables with some additional h4x thrown in was used for simplicity's/complexity's sake)
AssemblyRevisionIdentifierAttribute was a custom attribute that I created to hold the Git SHA1 since it is much more meaningful to developers than a.b.c.d.
My refresh-version program would then copy that file to Properties\VersionInfo.cs, and then do the substitution of the version information that it already calculated/parsed (I used sed(1) for the substitution, which was another benefit to using Cygwin). Properties\VersionInfo.cs was compiled into the program. That file can start out empty and you should ignore it by your version control system because it is automatically changing and the information to generate it is already stored elsewhere.
Hard code, or... Keep track on your versions (File, Assembly, Deploy) in a database. Make a call to the database with your Assembly and get the Deploy version.
This assumes that you are incrementing your versions in a logical way such that each version type has a relationship. It's a lot of work for such a minor problem. I'd personally go with Jared's solution; although I hate hard coding anything.
Using a build component, you could read the click-once version from the project file and write it automatically to the assembly info so both of them are in sync.
Solution for .NET (Core) 7 and higher
On .net Core, you can read the version number from the environment variable ClickOnce_CurrentVersion.
string versionString = Environment.GetEnvironmentVariable("ClickOnce_CurrentVersion") ?? "0.0.0.0";
Version version= Version.Parse(versionString);
MessageBox.Show(version.ToString());
See documentation

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.

Build fails on mapped drive, but not locally

I'm working on a game written in C# using VS2013 and monogame. However, monogame doesn't support the XNA content pipeline (still), so the going advice is to build your content separately using Microsoft's XNA and VS2010. Since I didn't want to clutter my primary development machine (Win8) with VS2010 et cetera, I created a Win7 virtual machine to run Win7 along with VS2010 and all the tooling I need to build my content. All my project and solution files have corresponding 2010 versions, and the 2010 solution only has the necessary projects to build the content.
I can successfully build the content, but only if it's present direcly on the VM's hard disk (C:\). If I map a local drive to a network share on the host machine and attempt to build, I get a build time error. Why do I want to do this? Because I want a single copy of the source tree so I can iterate at a decent speed. It's just far too painful and error-prone if I have a separate source tree in the VM.
Here's the build error I get:
Error loading pipeline assembly "S:\Src\ContentPipelineExtension\bin\x86\Debug\Newtonsoft.Json.dll".
I have S:\ mapped to my network share. Newtonsoft.Json.dll exists at the indicated path.
I have tried:
specifying /verbosity:d when building to see if any more information is output. There isn't.
attaching a debugger to the MSBuild.exe process with break on any exception enabled. It never breaks.
using subst instead of Windows Explorer's drive mapping tool (it might be using subst behind the scenes, but I wanted to be sure).
debugging MSBuild, but I hit the "mismatched leave" bug when I did so.
applied the workaround for the mismatched leave bug and debugged the build simultaneously on both C:\ and S:\. In both cases, I put a breakpoint right before XNA's BuildContent task was called. I let both builds run until they hit this breakpoint, and then I opened the locals windows, side-by-side. I compared all locals and found no difference apart from the expected C:\ versus S:\ path roots.
spelunking through the XNA code in ILSpy to try and figure out where it's going wrong, but have had no luck with that either
enabling full trust on the network share in CAS by executing: CasPol.exe -m -ag 1.2 -url file://S:\* FullTrust. No change in behavior.
enabling Fusion Log Viewer (fuslogvw.exe) and checking out its log. It says it has successfully loaded the assembly!
added <loadFromRemoteSources enabled="true"/> to my MSBuild.exe.config. No change.
Why does the build fail when running off my mapped S:\ and succeed when a copy of the source is placed on my C:\?
UPDATE: I just found the most awful work-around. I modified my ContentPipelineExtension project's Output Path such that it is an absolute directory on my C:\. This allows the build to complete successfullly, but is obviously far from ideal.
Here is a hack I used. It's not a satisfying answer (and I won't mark it as accepted), but in the absence of a better solution, it will save me an enormous amount of time and pain.
I edited my 2010 project files and changed my output paths to something like this:
<OutputPath>$(TEMP)\ContentPipelineExtension\bin\x86\Debug\</OutputPath>
The TEMP environment variable resolves to a folder on C:\ and saves me hard-coding a specific path. Now I can build the project from my Win7 VM using the same source tree as I use in my primary Win8 machine.

Wrong Interop.Shell32.dll being loaded suddenly

I have a program that has been working just fine, however when I made a small change to the way the program loads from its ini, the zipping function stops working. I stepped through the program and found the error to be occuring on the following line:
var fs = File.Create(zipPath);
fs.Write(emptyZip, 0, emptyZip.Length);
fs.Flush();
fs.Close();
var sc = new Shell32.ShellClass();
var srcFlder = sc.NameSpace(program.Path); //THIS LINE
var destFlder = sc.NameSpace(zipPath);
var items = srcFlder.Items();
destFlder.CopyHere(items, 20);
System.Threading.Thread.Sleep(500);
ZippedPrograms.Add(zipPath);
I double checked the variables program.Path and others being sent to the ShellClass(), and they are not null or empty. This is the actual error that pops up when the program gets to this line:
Doing some googling I find that apparently the Shell32.dll I have referenced in my program does not work right with 7 (or server 2008, the target environment), and I needed to reference the XP version instead (52kb versus 48kb dll size). One of the links where I found this info: click me.
So I created a virtual machine and installed WinXP Professional on it, and navigated to C:\WINDOWS\system32\ and copied the Shell32.dll located there to my host computer. Strange enough, the DLL is ~8mb in size rather than the 52kb I was expecting. When I add it as a resource from VS2012, I browse to the copied file and add it (with copy local), but then for some reason it ends up being 48kb in size and the program continues to crash at the above mentioned line.
I have tried using DotNetZip along with other C# libraries for zip management, and for some reason they never work properly (creating corrupted ZIP files, not creating them at all, refusing to add random files/folders to the archive, etc). Before this issue the program was working flawlessly, so more than anything I am confused as to why all of a sudden it is not working and why the Shell32.dll is not A) the 8mb version I reference, and B) 'stripped down' to 48kb. On top of that, I checked the current deployment of the program, which lacks some features of the current version, among other things, and the DLL there is the 48kb size, and this particular deployment has worked with no problems.
I should also mention that I am currently running Windows 8 Pro, and developing in VS2012. The deployment environment is Windows Server 2008 R2. I originally wrote this program in VS2010 on Windows 8 Ultimate. When I opened the project for the first time in VS2012, there was no upgrade dialogue. All OS's listed (except WinXP Pro) are x64.
Has anyone had any experience with these issues/happenings? Any insight/tips/solutions will be greatly appreciated.
Thank you!
Dragging across an outdated system dll to a newer version of Windows is something that's just bound to fail, especially if it's (as in this case), a COM interop DLL. If Windows 8 is running a COM service, it's going to be running it with its "own" version of the DLL. If you then try to interact with it using an interface DLL for a different version, you'll get an interface mismatch. As you've seen, E_NOINTERFACE.
You're trying to use a version 6 DLL to communicate with a version 8 service. It's bound to run into problems.
The difference in size might have something to do with Visual Studio stripping the deployment DLL down to just the interfaces, instead of including all the implementation.

How do you use the standard library in IronPython?

I'll prefix this question with: No, Setting IRONPYTHONPATH is not the answer.
Anyway...
I was planning on using IronPython as a replacement for Powershell for a project, but I've been stumped before I've even started.
The very first thing I tried to do was use os.path, resulting in:
Traceback (most recent call last):
File "<string>", line 1, in <module>
ImportError: No module named os
After messing around I finally discovered I could use the standard library by adding it manually to the path:
import sys
sys.path.append(r"C:\Program Files\IronPython 2.7\Lib")
import os
However, this is a daft idea. Hard coding the path to the python library inside my scripts is a 100% guaranteed way of making them not work at some point.
I discovered this almost immediately when I tried to use the script on a windows 7 machine and the path was slightly different ('Program Files (x86)').
So, a couple of questions here:
1) Why is it so hard to use the standard library? At the very least I would have thought the interactive prompt in VS and basic ipy.exe would have this.
2) How can I determine the directory that iron python is installed in regardless of the system I'm using? (IronPython installer setting a var perhaps?)
Just a note here; yes, I have seen some other posts saying "set your IRONPYTHONPATH". This in unhelpful. If I have a blank machine that means I have to:
1) Install IronPython
2) Run some crazy powershell script to search out where-ever-the-heck the standard library was installed and set a global IRONPYTHONPATH variable to it.
3) Run python scripts
I'm looking for a better way.
--
Edit:
The fact I'm using this to do powershell like things is basically irrelevant, but I'm trying to achieve something like:
import clr
from System.Management.Automation import RunspaceInvoke
import os
scriptRoot = os.getcwd()
runSpace = RunspaceInvoke()
cmdPath64 = os.join(scriptRoot, "..\java\...")
cmdPath32 = os.join(scriptRoot, "..\java\...")
proc = runSpace.Invoke("Get-WmiObject Win32_Processor ... ")
if proc.AddressWidth == 32:
runSpace.Invoke(cmdPath32)
else:
runSpace.Invoke(cmdPath64)
I find that for ensuring that everything works for non-developer third parties, it's usually better to use pyc.py to create DLL's and and executable. I routinely create a DLL of the python standard modules and reference that in code. See my previous answer at this question IronPython: EXE compiled using pyc.py cannot import module "os"
It's a bit workaroundish but, given that the LIB directory of ironpython is installed under the x86 program files folder in 64bit systems and on the usual program files path on 32bit systems, you could do in this way:
import sys
import System
if System.IntPtr.Size * 8 == 32: # detect if we are running on 32bit process
sys.path.append(System.Environment.GetEnvironmentVariable("ProgramFiles") + "\IronPython 2.7\Lib")
else:
sys.path.append(System.Environment.GetEnvironmentVariable("ProgramFiles(x86)") + "\IronPython 2.7\Lib")
import os # it works !!
Here we use %ProgramFiles% and %ProgramFiles(x86)% to determine the path where IronPython is installed.
Quoting wikipedia about %ProgramFiles% variable (link):
%ProgramFiles%
This variable points to Program Files directory, which stores all the
installed program of Windows and others. The default on
English-language systems is C:\Program Files. In 64-bit editions of
Windows (XP, 2003, Vista), there are also %ProgramFiles(x86)% which
defaults to C:\Program Files (x86) and %ProgramW6432% which defaults
to C:\Program Files. The %ProgramFiles% itself depends on whether the
process requesting the environment variable is itself 32-bit or 64-bit
(this is caused by Windows-on-Windows 64-bit redirection).
This is very odd, because if you run the the IronPython installer, and then run C:\Program Files\IronPython 2.7\ipy.exe or C:\Program Files (x86)\IronPython 2.7\ipy.exe, you shouldn't need to do anything to have the stdlib available.
My guess is that you have more than one IronPython and you're running the wrong one, but only because I can't think of another reason this would happen. It's supposed to Just Work.

Categories

Resources