Resource can not be loaded IF program.exe name changed after compiling - c#

I have an unmanaged dll so i wrote this to save the dll to file once the program is run.
Working code :
public static void ExtractResourceToFile()
{
if (!File.Exists("loader.dll"))
try
{
using (System.IO.FileStream fs = new System.IO.FileStream("loader.dll", System.IO.FileMode.Create))
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Kraken.Resources.loader.dll").CopyTo(fs);
Thread.Sleep(5000);
}
catch ( Exception ex)
{ }
}
Problem:
if the compiled Kraken.exe name changed the DLL is not being saved.
what I've tried :
public static void ExtractResourceToFile()
{
if (!File.Exists("loader.dll"))
try
{
string file = System.Reflection.Assembly.GetExecutingAssembly().Location;;
string app = System.IO.Path.GetFileNameWithoutExtension(file);
using (System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Create))
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(app + ".Resources.loader.dll").CopyTo(fs);
Thread.Sleep(5000);
}
catch ( Exception ex)
{ }
}
I've also tried to get the current process name and use it, but same problem occurred.

See this:
How do I get the name of the current executable in C#?
Particularly these comments are interesting:
Beware of GetExecutingAssembly(): if you call this from a library
assembly, it returns the name of the library assembly, which is
different from the name of the entry assembly (i.e. the original
executable). If you use GetEntryAssembly(), it returns the name of the
actual executable, but it throws an exception if the process is
running under WCF (admittedly a rare situation). For the most robust
code, use Process.GetCurrentProcess().ProcessName. – Contango Nov 3
'10 at 12:01
Hmm, note that the returned string won't change even if you rename
the executable file by hand using the file explorer. While
Environment.GetCommandLineArgs()[0] changes along with the actual
executable filename (of course). Coincidentally, the second method
resulted better for my specific situation as I want the data folder to
be named as the actual executable filename. – Hatoru Hansou Jan 23 '14
at 2:25
Hatoru's comment seems to support Phil1970's comment, that GetExecutingAssembly() probably use the resource properties found in the assembly instead of the actual file name.
So I'd use
Process.GetCurrentProcess().ProcessName
as Contango suggested.
And as zerkms said, don't ignore exceptions.

Related

Forcing .Extensions namespace to load when embedded DLL will need it

I'm building a utility that uses Microsoft's DACPAC libraries. For the purpose of this tool, I want to embed all requisite libraries in the executable. It appears that when I execute DacServices.GenerateDeployScript() it's trying to use the Microsoft.SqlServer.Dac.Extensions library. The library is also embedded, but perhaps isn't being resolved with my EventHandler the way other DLLs are. My EventHandler is like this:
private static Assembly ResolveEventHandler(Object sender, ResolveEventArgs args)
{
//Debugger.Break();
String dllName = new AssemblyName(args.Name).Name + ".dll";
var assem = Assembly.GetExecutingAssembly();
String resourceName = assem.GetManifestResourceNames().FirstOrDefault(rn => rn.EndsWith(dllName));
if (resourceName == null) return null;
using (var stream = assem.GetManifestResourceStream(resourceName))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
This works for resolving other items, but I believe that the likely issue is that the Microsoft.SqlServer.Dac namespace is making an execution time call to the .Extensions namespace and isn't able to resolve the namespace or the methods in it. I could be wrong, but I'm not sure what else could be the cause.
The calls to methods and classes in .Dac itself are being handled fine, so I know the EventHandler is working properly. I'm not really sure what to do and would appreciate any guidance. I've tried using Microsoft.SqlServer.Dac.Extenions at the top of the .cs file, but since I don't directly call anything in that namespace, it's grey and probably is ignored by the compiler.
Thanks!
Update:
I made a call to the .Extensions namespace in the code to force it to be read into memory prior to the failing call, though it appears that it already was. I set a breakpoint where the resolver kicks off. Just prior to it failing, it's trying to resolve .resource for each DLL, e.g. Microsoft.SqlServer.Dac.resource and Microsoft.SqlServer.TransactSql.ScriptDom.resource - all for DLLs embedded in the executable. The resolver doesn't see anything because there are no .resource files in the project, so nothing compiled into the manifest. Aren't these supposed to just be resident in memory while a DLL is being utilized? When the DLLs are all present in the same directory as the .exe, it functions fine, and also doesn't create temporary .resource files in the directory, so I'm unsure what I'm looking to resolve.
Update 2:
Using a PDB of the DAC libraries, it appears the failing line is:
IOperation operation = DacServices.CreateDeploymentArtifactGenerationOperation(OperationResources.GenerateDeployScriptCaption, (ErrorManager errorManager) => this.CreatePackageToDatabaseDeployment(package.PackageSource, targetDatabaseName, dacDeployOption, errorManager), (IDeploymentController controller, DeploymentPlan plan, ErrorManager errorManager) => DacServices.WriteDeploymentScript(streamWriter, controller, plan, errorManager), cancellationToken1, dacLoggingContext);
And the resulting exceptions are:
The extension type Microsoft.SqlServer.Dac.Deployment.Internal.InternalDeploymentPlanExecutor could not be instantiated.
and
The extension type Microsoft.SqlServer.Dac.Deployment.Internal.InternalDeploymentPlanModifier could not be instantiated.

DLL cannot be found because the file name is different than the one referenced?

I have been baffled on how can this be happening.
So heres the deal, im trying to play a V2M chiptune with a dll called NV2.dll
Its referenced, and I used its functions like normal.
BUT when i try to run the application i get
Unable to load DLL 'V2.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
The referenced DLL i used is called NV2, I have checked it, the assembly goes by NV2, not V2, why is it trying to load a dll with a different name?!
So obviously, there is a reference to V2.dll inside the NV2.dll. Either the documentation is just shitty or you didn't notice that part, but inside the constructor of the NV2 class they try to write that V2.dll, which is saved inside the Resources of the dll as a byte[] V2 to disk, namely to the directory C:\Windows\system32. Code:
public NV2()
{
List<WeakReference> _ENCList = NV2.__ENCList;
Monitor.Enter(_ENCList);
try
{
NV2.__ENCList.Add(new WeakReference(this));
}
finally
{
Monitor.Exit(_ENCList);
}
//Here comes the part that writes the resources
FileStream fileStream = new FileStream(string.Concat(Environment.GetFolderPath(Environment.SpecialFolder.System), "\\V2.dll"), FileMode.OpenOrCreate);
fileStream.Write(Resources.V2, 0, checked((int)Resources.V2.Length));
fileStream.Close();
}
Meaning that either in your application you first have to do a
var engine = new NV2(); //triggers the constructor code
to trigger that, or you go hardcore on that and dump the byte[] from their dll.
I've dumped that file here for you and zipped it: http://www.file-upload.net/download-11263190/V2.zip.html
(You could have done that by saving the project using teleriks decompiler, fixing the errors in the ressources, changing the project to a console project, then coding a Main function like)
using System.IO;
using NV2.My.Resources;
namespace NV2
{
class MainClass
{
static void Main(string[] args)
{
FileStream fileStream = new FileStream("V2.dll", FileMode.OpenOrCreate);
fileStream.Write(Resources.V2, 0, checked((int)Resources.V2.Length));
fileStream.Close();
}
}
}

Registering DLL on windows mobile 6

I have a DLL file that contains an ActiveX control that I need to register it programmatically by code. here is the code I am using to register that DLL file but it keeps giving me "The system cannot find the file specified" when calling the Start method, And I do not know why regsvrce.exe is not found, should I change current directory or something, please help.
public static void registerDLL(string dllPath)
{
try
{
//'/s' : indicates regsvr32.exe to run silently.
string fileinfo = "\"" + dllPath + "\"";
Process reg = new Process();
reg.StartInfo.FileName = "regsvrce.exe";
reg.StartInfo.Arguments = fileinfo;
reg.StartInfo.UseShellExecute = false;
reg.Start();
reg.WaitForExit();
reg.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Windows CE does not understand or support relative paths. So first, you have to ensure regsvrce.exe exists on the platform (it's not a given that it will, in fact it's pretty common for it to not exist) and you must fully qualify the path to it:
reg.StartInfo.FileName = #"\Windows\regsvrce.exe";
If it doesn't exist (or even if it does) you could easily do the same thing regsvrce.exe does, which is to call DllRegisterServer by simply P/Invoking LoadLibrary and calling the method directly.

Assembly Location Changes in Runtime

I'm running coded ui automation and defined a method attribute called [ExternalDataSource()] to read a document (csv, xml...) and parse the data into some dictionaries. I'll copy it here so you can have a better insight:
[System.AttributeUsage(System.AttributeTargets.Method)]
public class ExternalDataSource : System.Attribute
{
public ExternalDataSource(string filename)
{
DirectoryInfo di = new DirectoryInfo(Assembly.GetExecutingAssembly().Location);
string file = Path.Combine(Path.GetDirectoryName(di.FullName), filename);
try
{
code
}
catch (Exception)
{
throw new UITestException("Cannot load data source document");
}
}
}
In it I try to access Assembly.GetExecutingAssembly().Location to get a file that is copied to the TestResult/Out folder. I assigned this attribute to only one TestMethod() in the whole application and while debugging, I found out that the application enters the attribute's c'tor twice. Both times the Location is different. Once it's from the bin/Debug folder, the other time it's from the TestResults/Out folder. Two questions:
Why does the debugger enter that attribute twice if I call it only once in my application?
Why does the location of the same assembly change?
Well it seems nobody had an answer, but while debugging a run from the command line using mstest.exe with the vs2012 JIT Debugger i found out a strange thing:
When putting a System.Diagnostics.Debugger.Break() in the class where this attribute is the jitter was called from MSTest.exe but when this breakpoint was in the testmethod decorated with this attribute, QTAgent32.exe was called. I had implemented a singleton class to handle my parameters, and while it was populated in ExternalDataSource in this attribute by MSTest, when entering QTAgent32 (the test) it was empty.
The solution that worked for me was just to initialize that Singleton with the data on [TestInitialize()].
Hope this helps somebody.

How do I get the name of the current executable in C#?

I want to get the name of the currently running program, that is the executable name of the program. In C/C++ you get it from args[0].
System.AppDomain.CurrentDomain.FriendlyName
System.AppDomain.CurrentDomain.FriendlyName - Returns the filename with extension (e.g. MyApp.exe).
System.Diagnostics.Process.GetCurrentProcess().ProcessName - Returns the filename without extension (e.g. MyApp).
System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName - Returns the full path and filename (e.g. C:\Examples\Processes\MyApp.exe). You could then pass this into System.IO.Path.GetFileName() or System.IO.Path.GetFileNameWithoutExtension() to achieve the same results as the above.
This should suffice:
Environment.GetCommandLineArgs()[0];
System.Diagnostics.Process.GetCurrentProcess() gets the currently running process. You can use the ProcessName property to figure out the name. Below is a sample console app.
using System;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Process.GetCurrentProcess().ProcessName);
Console.ReadLine();
}
}
This is the code which worked for me:
string fullName = Assembly.GetEntryAssembly().Location;
string myName = Path.GetFileNameWithoutExtension(fullName);
All the examples above gave me the processName with vshost or the running dll name.
Try this:
System.Reflection.Assembly.GetExecutingAssembly()
This returns you a System.Reflection.Assembly instance that has all the data you could ever want to know about the current application. I think that the Location property might get what you are after specifically.
Why nobody suggested this, its simple.
Path.GetFileName(Application.ExecutablePath)
Couple more options:
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name
Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase
System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name;
will give you FileName of your app like; "MyApplication.exe"
If you need the Program name to set up a firewall rule, use:
System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName
This will ensure that the name is correct both when debugging in VisualStudio and when running the app directly in windows.
When uncertain or in doubt, run in circles, scream and shout.
class Ourself
{
public static string OurFileName() {
System.Reflection.Assembly _objParentAssembly;
if (System.Reflection.Assembly.GetEntryAssembly() == null)
_objParentAssembly = System.Reflection.Assembly.GetCallingAssembly();
else
_objParentAssembly = System.Reflection.Assembly.GetEntryAssembly();
if (_objParentAssembly.CodeBase.StartsWith("http://"))
throw new System.IO.IOException("Deployed from URL");
if (System.IO.File.Exists(_objParentAssembly.Location))
return _objParentAssembly.Location;
if (System.IO.File.Exists(System.AppDomain.CurrentDomain.BaseDirectory + System.AppDomain.CurrentDomain.FriendlyName))
return System.AppDomain.CurrentDomain.BaseDirectory + System.AppDomain.CurrentDomain.FriendlyName;
if (System.IO.File.Exists(System.Reflection.Assembly.GetExecutingAssembly().Location))
return System.Reflection.Assembly.GetExecutingAssembly().Location;
throw new System.IO.IOException("Assembly not found");
}
}
I can't claim to have tested each option, but it doesn't do anything stupid like returning the vhost during debugging sessions.
System.Reflection.Assembly.GetEntryAssembly().Location returns location of exe name if assembly is not loaded from memory.
System.Reflection.Assembly.GetEntryAssembly().CodeBase returns location as URL.
This works if you need only the application name without extension:
Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName);
You can use Environment.GetCommandLineArgs() to obtain the arguments and Environment.CommandLine to obtain the actual command line as entered.
Also, you can use Assembly.GetEntryAssembly() or Process.GetCurrentProcess().
However, when debugging, you should be careful as this final example may give your debugger's executable name (depending on how you attach the debugger) rather than your executable, as may the other examples.
IF you are looking for the full path information of your executable, the reliable way to do it is to use the following:
var executable = System.Diagnostics.Process.GetCurrentProcess().MainModule
.FileName.Replace(".vshost", "");
This eliminates any issues with intermediary dlls, vshost, etc.
If you are publishing a single file application in .NET 6.0 or above, you can use Environment.ProcessPath
Is this what you want:
Assembly.GetExecutingAssembly ().Location
On .Net Core (or Mono), most of the answers won't apply when the binary defining the process is the runtime binary of Mono or .Net Core (dotnet) and not your actual application you're interested in. In that case, use this:
var myName = Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly().Location);
For windows apps (forms and console) I use this:
Add a reference to System.Windows.Forms in VS then:
using System.Windows.Forms;
namespace whatever
{
class Program
{
static string ApplicationName = Application.ProductName.ToString();
static void Main(string[] args)
{
........
}
}
}
This works correctly for me whether I am running the actual executable or debugging within VS.
Note that it returns the application name without the extension.
John
Super easy, here:
Environment.CurrentDirectory + "\\" + Process.GetCurrentProcess().ProcessName
To get the path and the name
System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName

Categories