I need to develop a Shell Context Menu extension that references some other custom assemblies... I don't want to assign a Strong Name Key to those custom assemblies!
The guide I followed to do this uses the SharpShell project and illustrates how to sign (but does not expalins why) the assembly... and this is my problem: if I sign my final .dll then I have many errors during my project's building phase, because some assemblies my project references are not strongly named ("Referenced assembly does not have a strong name").
In general, googling about the C# Shell Extension implementation, all best tutorials I found sign the final assembly... is it mandatory?
Without signing the assembly ServerManager.exe returns this error: "The file 'XYZ.dll' is not a SharpShell Server".
Finally I've solved my troubles... the SharpShell.dll file obtained through NuGet was a different version of the ServerManager.exe ones.
Uninstalling the SharpShell NuGet package and directly referencing the SharpShell.dll you find inside the ServerManager folder was my solution!
Moreover, I was looking between the article comments... please read this question.
You don't need to use old DLL.
Please use this code directly, without using ServerManager.exe.
private static ServerEntry serverEntry = null;
public static ServerEntry SelectedServerEntry
{
get
{
if (serverEntry == null)
serverEntry = ServerManagerApi.LoadServer("xxx.dll");
return serverEntry;
}
}
public static ServerEntry LoadServer(string path)
{
try
{
// Create a server entry for the server.
var serverEntry = new ServerEntry();
// Set the data.
serverEntry.ServerName = Path.GetFileNameWithoutExtension(path);
serverEntry.ServerPath = path;
// Create an assembly catalog for the assembly and a container from it.
var catalog = new AssemblyCatalog(Path.GetFullPath(path));
var container = new CompositionContainer(catalog);
// Get the exported server.
var server = container.GetExport<ISharpShellServer>().Value;
serverEntry.ServerType = server.ServerType;
serverEntry.ClassId = server.GetType().GUID;
serverEntry.Server = server;
return serverEntry;
}
catch (Exception)
{
// It's almost certainly not a COM server.
MessageBox.Show("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", "Warning");
return null;
}
}
Install code:
ServerRegistrationManager.InstallServer(SelectedServerEntry.Server, RegistrationType.OS64Bit, true);
Register code:
ServerRegistrationManager.RegisterServer(SelectedServerEntry.Server, RegistrationType.OS64Bit);
Related
I have an application that can be customized by writing custom extensions. All of them are in proj\Extensions folder. At runtime my Core project loads every extension from the folder and executes code. The problem is when one of the extensions uses additional libraries, because the Core project cannot find reference to these additional libraries.
So for example in my Core project I have:
public void Preview(IFileDescription fileDescription)
{
var extension = Path.GetExtension(fileDescription.FilePath);
var reader = _readerFactory.Get(extension);
Data = reader.GetPreview(fileDescription);
}
In one of my extensions I have
public DataTable GetPreview(IFileDescription options)
{
var data = new DataTable();
using (var stream = new StreamReader(options.FilePath))
{
var reader = new CsvReader(stream); // <- This is from external library and because of this Core throws IO exception
}
/*
...
*/
return data;
}
Core only knows about the interface, so when one of readers uses for example CsvHelper.dll I get exception of FileNotFound, because Core cannot find CsvHelper.dll. Is there any way to tell the compiler to look for additional libraries in specific folder? I used Reference Paths, but it didn't solve the problem. It still threw the same exception.
Yes, it's possible. You can attach to the AppDomain.AssemblyResolve event and manually load the required DLLs from your add-in directory. Execute the following code before executing any add-in code:
var addinFolder = ...;
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
{
var missing = new AssemblyName(e.Name);
var missingPath = Path.Combine(addinFolder, missing.Name + ".dll");
// If we find the DLL in the add-in folder, load and return it.
if (File.Exists(missingPath))
return Assembly.LoadFrom(missingPath);
// nothing found, let .NET search the common folders
return null;
};
What Happens?
I have been having an issue on this now for the past week and I feel like i get closer and closer each day but can't put my finger on what it is.
I have purchased a license of a Third-Party program called 'Streamcoders' (lets you encoder a live stream). When installing this program it gives you (as far as i know) an x86 and x64 version of two .dll's 'MediaBase' and 'MediaSuite'. I have added the x86 version into my references as this is the one I need.
The properties of these dll's are :
Embed Interop Types = false.
Copy Local = true.
Aliases = global.
Specific Version = false.
So i go to publish my application. I specify the location, and then specify that i want the user to install the application from a Web Site. This all works and the application is installed.
I go to the clients machine and install the application and I get an error:
System.IO.FileNotFoundException: Could not load file or assembly 'MediaSuite.dll' or one of its dependencies. The specified module could not be found.
My Tests + Code
So when looking through my code I tried to add MessageBox.Show(""); to pin-point where the error occurs.
So on my Login page constructor, i call a method CheckUserRegistry():
try
{
if (Registry.GetValue("HKEY_CURRENT_USER", "URL", "").ToString() == string.Empty)
{
//User has not used the application before.
MessageBox.Show("NO URL FOUND");
return false;
}
else
{
MessageBox.Show("GENERATE");
//User has used the application before and is generating that user a session GUID.
Global.podiaClient = new podiaPublish.PublishClient();
Global.podiaClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(string.Format(Registry.GetValue("HKEY_CURRENT_USER", "URL", "").ToString() + "/wcf/publish.svc"));
//Global.podiaSession = Global.podiaClient.Login(Registry.GetValue("HKEY_CURRENT_USER", "UID", "").ToString(), Global.Decrypt(Registry.GetValue("HKEY_CURRENT_USER", "PWD", "").ToString()));
Global.podiaSession = Global.podiaClient.Login(Registry.GetValue("HKEY_CURRENT_USER", "UID", "").ToString(), Registry.GetValue("HKEY_CURRENT_USER", "PWD", "").ToString());
return true;
}
}
catch (Exception ex)
{
//Global.HandleError(ex);
MessageBox.Show("here");
MessageBox.Show(ex.InnerException.ToString());
return false;
}
It successfully hits the MessageBox.Show("GENERATE"); and then after that seems to hit the catch and displays the error.
If i comment out the lines below the code does not error. podiaPublish is a Service Reference in my project.
Global.podiaClient = new podiaPublish.PublishClient();
Global.podiaClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(string.Format(Registry.GetValue("HKEY_CURRENT_USER", "URL", "").ToString() + "/wcf/publish.svc"));
Global.podiaSession = Global.podiaClient.Login(Registry.GetValue("HKEY_CURRENT_USER", "UID", "").ToString(), Registry.GetValue("HKEY_CURRENT_USER", "PWD", "").ToString());
Does anyone have any clue as to what is going on?
I have a Console Application in C# and a Class Library named AppManager.cs. The Method of this class is used in the console Application as given below.
try
{
AppManager mgr = new AppManager(); //Want to skip this line when dll is missing.
mgr.Method_Name(this, true); //Want to skip this line when dll is missing.
}
catch (Exception)
{
}
When I have published the Code and extracted only exe then application fails to run [I know as the exe try to find that dll and method present in dll won't available].
Now my Question is That Is there any way to skip the code which will produce error when it will not find the reference of dll.
I also tried this but it didn't worked:
String file = null;
String filePath = Path.GetDirectoryName(Application.ExecutablePath);
file = Directory.GetFiles(filePath, "myLibrary.dll", SearchOption.AllDirectories)
.FirstOrDefault();
if (file != null)
{
AppManager mgr = new AppManager();
mgr.Method_Name(this, true);
}
If you do that, it won't give the desired output too. Why don't you integrate the dll with your exe? You can do it by using this tool
Can you not simply check if the dll exists or not?
string filePath = #"SOME_PATH";
var exists = File.Exists(filePath);
if(exists)
{
AppManager mgr = new AppManager();
mgr.Method_Name(this, true);
}
I've a problem running an ASMX Web Service. I'm Calling a DLL from a method (AceptaTools.dll) and this DLL load ca4xml.dll.
AceptaTools.dll has been registered with REGSVR32. But ca4xml.dll Can't.
When i Invoke the service:
_objURL = _CA4XML.GetLastResponse();
i get a message "ca4xml.dll not loaded".
Looking al Dependency Walker:
Here both files in detail:
Both DLL are in BIN folder and my project run as x86... Why can't load?? Please help.
[WebMethod]
public string Send(string Ip, string Puerto, string NroDocumento, string TipoDocumento, string Comando, string Impresora, string Linea)
{
try
{
int _Result = 0;
string _Null = "";
string _objURL;
//Config Capsula
string serverConfig = "cfg|" + Ip.ToString() + "|" + Puerto.ToString() + "|10";
//Impresora FACTURA,1 por Defecto.
if (string.IsNullOrEmpty(Impresora)) { Impresora = "FACTURA,1"; }
if (string.IsNullOrEmpty(NroDocumento)) { NroDocumento = "0"; }
if (string.IsNullOrEmpty(Comando)) { Comando = "generar"; }
//Nuevo CAXML Cliente
AceptaTools.CA4XML_Client _CA4XML = new CA4XML_Client();
_Result = _CA4XML.Send(ref serverConfig, ref NroDocumento, ref Comando, ref Impresora, ref Linea, out _Null);
if (_Result != 0)
{
_objURL = _CA4XML.GetLastResponse(); //Get URL
return _objURL.ToString();
}
else
{
return "Error";
}
}
catch (Exception ex)
{
return ex.Message.ToString();
}
}
}
Did you make sure that the ca4xml.dll is deployed properly? Since I guess it is not referenced as .NET assembly the VS will treat it like a normal file and you will need to specifically tell VS to include it when deploying.
Do the following steps to check whether deployment has been setup properly:
Open the Solution Explorer -> Got to the ca4xml.dll -> Right click -> Select Properties -> Set Build Action = None & Copy to Output = Always
Also in addition to the Dependency Walker I suggest to use Process Monitor. When you use the file access view (disregarding registry changes etc.) you can see all the locations where a process tries to load a dll from. Afterwards you can make sure that the dll you are missing is in one of the listed locations, here is the link:
http://technet.microsoft.com/en-us/sysinternals/bb896645
When you do not load DLL in the program because you need to update some things .
you can update project in nuget manager
I am building a program that uses a very simple plugin system. This is the code I'm using to load the possible plugins:
public interface IPlugin
{
string Name { get; }
string Description { get; }
bool Execute(System.Windows.Forms.IWin32Window parent);
}
private void loadPlugins()
{
int idx = 0;
string[] pluginFolders = getPluginFolders();
Array.ForEach(pluginFolders, folder =>
{
string[] pluginFiles = getPluginFiles(folder);
Array.ForEach(pluginFiles, file =>
{
try
{
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(file);
Array.ForEach(assembly.GetTypes(), type =>
{
if(type.GetInterface("PluginExecutor.IPlugin") != null)
{
IPlugin plugin = assembly.CreateInstance(type.ToString()) as IPlugin;
if(plugin != null)
lista.Add(new PluginItem(plugin.Name, plugin.Description, file, plugin));
}
});
}
catch(Exception) { }
});
});
}
When the user selects a particular plugin from the list, I launch the plugin's Execute method. So far, so good! As you can see the plugins are loaded from a folder, and within the folder are several dll's that are needed but the plugin. My problem is that I can't get the plugin to 'see' the dlls, it just searches the launching applications startup folder, but not the folder where the plugin was loaded from.
I have tried several methods:
1. Changing the Current Directory to the plugins folder.
2. Using an inter-op call to SetDllDirectory
3. Adding an entry in the registry to point to a folder where I want it to look (see code below)
None of these methods work. What am I missing? As I load the dll plugin dynamically, it does not seem to obey any of the above mentioned methods. What else can I try?
Regards,
MartinH.
//HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
Microsoft.Win32.RegistryKey appPaths = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(
string.Format(
#"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\{0}",
System.IO.Path.GetFileName(Application.ExecutablePath)),
Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree);
appPaths.SetValue(string.Empty, Application.ExecutablePath);
object path = appPaths.GetValue("Path");
if(path == null)
appPaths.SetValue("Path", System.IO.Path.GetDirectoryName(pluginItem.FileName));
else
{
string strPath = string.Format("{0};{1}", path, System.IO.Path.GetDirectoryName(pluginItem.FileName));
appPaths.SetValue("Path", strPath);
}
appPaths.Flush();
Use Assembly.LoadFrom not Assembly.LoadFile
Whenever I dynamically load plugins like this, I usually create an app domain and load the assembly in the new app domain. When creating an app domain, you can specify the base directory. Dependent assemblies will be loaded from this base directory.