Mono: Load an assembly from an injected dll on a process - c#

I'm trying to load an assembly from an injected dll ( c++ ) ,
First I hook :
pMono1 = (Mono1Fn)DetourFunction((PBYTE)GetProcAddress(addr,"mono_assembly_load_from_full"), (PBYTE)Mono1);
pMono2 = (Mono2Fn)GetProcAddress(addr, "mono_image_open_full");
mono_jit_exec_ = (mono_jit_exec_t)GetProcAddress(addr,"mono_jit_exec");
pMonoDomainGet = (mono_domain_get_t)GetProcAddress(addr,"mono_domain_get");
(I've checked that addr is correct )
Then what I do is
MonoAssembly* __cdecl Mono1(MonoImage *image, const char*fname, MonoImageOpenStatus *status, gboolean refonly)
{
if(!Loaded)
{
Loaded = true;
OpenAssembly();
}
return pMono1(image,fname,status,refonly);
}
So, what I'm trying to do is:
When the target process opens an assembly, I open mine and the original assembly to load
But the problem is : the opened assembly doesnt run.
Here is the method OpenAssembly():
void OpenAssembly()
{
MonoImageOpenStatus status = MONO_IMAGE_ERROR_ERRNO;
MonoImage *Image = (MonoImage*)pMono2("B:\\AsmTest.dll",&status,FALSE);
MonoAssembly *Assm = (MonoAssembly*)Mono1(Image,"B:\\AsmTest.dll",&status,FALSE);
char* in[] = {"B:\\AsmTest.dll" };
cout << "In[0] : " << in[0] << endl;
mono_jit_exec_((MonoDomain*)pMonoDomainGet(),Assm,0,in);
}
In the embedding mono tutorial they say that mono_jit_exec calls the Main method,
but it doesnt,( which leads me to think that the error is in my assembly ),
Here the code of the simple Assembly :
public class AssemblyTest
{
static void Main()
{
MessageBox.Show("I do WORK :d");
}
}
So like I said before , my problem is that the Main() method never gets called in the process.(Because the MessageBox doesnt show up)
For your information : I've put the assembly in B disk.
I think my problem is so simple, but I cant find why.
Thanks in advance, I hope you understand what I mean :)

Related

Unable to load DLL the specified procedure could not be found. (Exception from HRESULT: 0x8007007F)

For a long time I have a problem with a project that I have to implement in mine, I'll explain it to you.
My goal is to call a C ++ class from a C # application (Project 1), the problem is that the C ++ project (Project 3) is not compatible with CLR.
What I have done so far has been created an intermediate project also in unmanaged C ++ (Project 2) to be compatible with the project 3.
Project 2 consists of a very simple method that initializes a class from project 3 and uses this object for different operations.
I'm working in Visual Studio and it does not give me an error when compiling, but at run time I get the following error:
Unable to load the DLL file 'PROJECT-ROUTE \ Project2.dll': The specified procedure could not be found. (Exception from HRESULT: 0x8007007F)
in project1.process ()
The thing is that the previous error comes out only when within the project2 method I initialize the class from project 3, if I comment the initialization line then it goes well, I can not understand why between 2 C ++ projects of the same type gives me this type of problems.
Can somebody help me?
thank you
C# Code (Project 1)
private const string DllFilePath = #"PATH_TO_DLL\Proyect2.dll";
[DllImport(DllFilePath, CallingConvention = CallingConvention.Cdecl, EntryPoint = "process")]
public extern static void process();
[HandleProcessCorruptedStateExceptions]
public static string Prox(string a, string b)
{
string str = "OK";
try
{
process();
}
catch (System.AccessViolationException exception)
{
return exception.Message + " " + exception.StackTrace;
}
catch (Exception exception)
{
return exception.Message + " " + exception.StackTrace + " ";
}
return str;
}
}
Middle proyect Unamanged C++ Code (Project 2)
Project2.h
#include <stdexcept>
#include "Project3.h"
using namespace std;
namespace FinalProcess
{
extern "C" { __declspec(dllexport) void __cdecl process(); }
}
Project2.cpp
#include "Project2.h"
#include <iostream>
#include <chrono> // To measure execution time
namespace FinalProcess
{
void process()
{
OCTA::Analyzer& ld = OCTA::Analyzer::getInstance(); // <-- Singleton
// if I comment this line then it goes well
}
}
Assuming that the information that you present here is correct (and I have my doubts because you've not copied it verbatim as can be seen from the DLL name of Proyect2.dll) then the error cannot be that the function process is not found. In which case the error has to be in the linking to Project3.
Your Project2.dll is presumably attempting to link to Project3.dll and to a function that is not exported from Project3.dll. That would explain the behaviour that you report. This would happen typically if the Project3.lib file that you linked when building Project2.dll did not match the Project3.dll file found by the executable at runtime.
Make sure that the version of Project3.dll that is being loaded is up to date and matches the .h and .lib files you used to build Project2.dll.
Rather than give an absolute path of the DLL in your C# code, you just the file name of the DLL. Place both DLLs in the same directory as your C# executable.

BadImgeFormatException when trying to run application after reinstalling Windows 8.1

I hope this question will not be regarded as a duplicate as I know there are many similar questions on stackoverflow. I should know. I already read most of them. So bear with me...
I am writing a C# application that relies on the OpenCV libraries to function. The OpenCV libraries are written in c++ code and to use them in c#, I wrote 2 libraries: a static library containing the methods I want from OpenCV; a CLR DLL that acts like a bridge between the static lib and the C# project.
What perplexes me is the fact that everything worked fine until I reinstalled Windows 8.1 due to a virus. Before the reinstall, the app compiled and ran just like intended. After the reinstall, the very same project throws a "BadImageFormatException" when trying to debug:
namespace G19_GUI
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new GUI.GUI()); //this is the line producing the exception
}
}
}
 
Additional information: Could not load file or assembly 'clrLib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format.
I know the most common cause for this exception is that the application is trying to load a 32bit library into a 64bit compiled application or vice-versa. As such, I verified that the OpenCV libraries I am trying to use are destined for use in a 32bit application and indeed they are. I tried switching to the 64bit dlls, action that produced 39 errors of type "LINK2028: unresolved token".
Keep in mind that the project itself did not change at all between the 2 installations of Windows. I used the same property sheet and the same OpenCV libraries. Everything was kept on an external drive, which was unplugged at the time I foolishly double clicked the virus executable, and backed up on DropBox, the only thing I had to do after reinstalling Windows was to reset the path and OpenCV environment variables, which I did using a .bat file, the same .bat file used to set those very same variables in the first install of Windows. Therefore, I highly doubt the possibility of the virus messing with my project files. Even so, I double-checked everything and couldn't find anything wrong.
I proceeded to documenting the exception online. As a result, I ended up trying every possible combination of configuration builds and target platforms I dared have the patience to try for all of the 3 projects I had in my solution.
Indeed, trying to build and compile for a 64bit machine removed the exception but another DLL my C# project depended on was destined for 32bit use and when trying to load that DLL, the very same exception popped up (which was expected). Unfortunately, the DLL did not come with a 32bit version or with a source code to try and build my own 64bit version of said DLL.
Thus, I am forced to build my application either for both target platforms (any cpu, mixed platform, whatever) or only for 32bit. Which, of course, produces the exception at start-up.
I know all my DLLs are made for 32bit use. For the life of me, I cannot figure out what the problem is, nor why this problem did not exist before I reinstalled the os.
Below is the code of my clrLib dll:
#include "Stdafx.h"
#include "clrLib.h"
#include <vector>
namespace clrLib
{
public ref class mapper
{
private:
static openCVProc * myProc;
public:
static mapper(void)
{
myProc = new openCVProc();
}
char * mapStringToChar(String ^ path)
{
return (char*)(void*)Marshal::StringToHGlobalAnsi(path);
}
array<int>^ getRGBfromHSV(int h, int s, int v)
{
array<int>^ values = gcnew array<int>(3);
std::vector<int> myVals = myProc->hsv2rgb(h, s, v);
values[0] = myVals[0];
values[1] = myVals[1];
values[2] = myVals[2];
return values;
}
array<int>^ getHSV(String^ src)
{
array<int>^ vals = gcnew array<int>(3);
vals[0] = (myProc->getHSV(mapper::mapStringToChar(src)))[0];
vals[1] = (myProc->getHSV(mapper::mapStringToChar(src)))[1];
vals[2] = (myProc->getHSV(mapper::mapStringToChar(src)))[2];
return vals;
}
void openCam()
{
myProc->startCam();
}
void closeCam()
{
myProc->stopCam();
}
int^ getBrightness()
{
int^ b;
b = myProc->getB();
return b;
}
bool^ camState()
{
return myProc->camState();
}
array<Byte>^ mapper::getFrameData()
{
cv::Mat f = myProc->getFrame();
int width = f.cols;
int height = f.rows;
array<Byte>^ bitmapData = gcnew array<Byte>(width*height * 3);
int c = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
bitmapData[c] = f.at<cv::Vec3b>(i, j)[0];
bitmapData[c + 1] = f.at<cv::Vec3b>(i, j)[1];
bitmapData[c + 2] = f.at<cv::Vec3b>(i, j)[2];
c += 3;
}
}
return bitmapData;
}
Size^ mapper::getFrameSize()
{
std::vector<int> size = myProc->getFrameSize();
Size^ frameSize = gcnew Size(size[0], size[1]);
return frameSize;
}
};
}
The other 2 libraries are a bit lengthy, but I will include them if need be.
Thank you for taking the time to read my post.

Accessing my WPF COM Library from Python

I'd like to run my WPF application from a python script, however am having difficulty.
To achieve this I have converted the WPF application to a COM library as follows:
namespace MyWpfApp
{
[Guid("F75D3377-D677-41BF-B3D5-C677C442228F")]
public interface IMyWpfAppInterface
{
void ShowCOMDialog();
void ClickButton1();
void ClickButton2();
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("D936A84B-8B1C-4D62-B090-C06E3EB5EEE9")]
public class MyWpfClass : IMyWpfAppInterface
{
private static Thread m_runDlgThread;
private static MainWindow m_mainWindow = null;
private static Application m_app = null;
public MyWpfClass() { }
public void ShowCOMDialog()
{
m_msgHelper = new MessageHelper();
m_runDlgThread = new Thread(runDlg);
m_runDlgThread.SetApartmentState(ApartmentState.STA);
m_runDlgThread.Start();
}
public void ClickButton1(){// to do}
public void ClickButton2(){// to do}
private void runDlg()
{
Application m_app = new Application();
m_mainWindow = new MainWindow();
m_app.Run(m_mainWindow);
}
}
}
I have installed my assembly to the global assembly cache and registered the dll as follows
gacutil.exe" /i MyWpfApp.dll
REGASM MyWpfApp.dll /tlb:com.MyWpfApp.tlb
I have tested that I can successfully import the Typelib and run my WPF application from a win32 console application.
#include "stdafx.h"
#import "..\MyWpfApp\bin\Debug\com.MyWpfApp.tlb" named_guids raw_interfaces_only
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL); //Initialize all COM Components
// <namespace>::<InterfaceName>
MyWpfApp::IMyWpfAppInterfacePtr pDotNetCOMPtr;
// CreateInstance parameters
// e.g. CreateInstance (<namespace::CLSID_<ClassName>)
HRESULT hRes =
pDotNetCOMPtr.CreateInstance(MyWpfApp::CLSID_MyWpfClass);
if (hRes == S_OK)
{
const DWORD cTimeout_ms = 500;
HANDLE hEvent = CreateEvent(0, TRUE, FALSE, 0);
BSTR str;
pDotNetCOMPtr->ShowCOMDialog ();
bool toggle = true;
while(true)
{
DWORD dwWait = WaitForSingleObject(hEvent,cTimeout_ms);
if(toggle)
{
pDotNetCOMPtr->ClickButton1();
toggle = false;
}
else
{
pDotNetCOMPtr->ClickButton2();
toggle = true;
}
}
//call .NET COM exported function ShowDialog ()
}
CoUninitialize (); //DeInitialize all COM Components
return 0;
}
When I attempt to access the COM component from Python
import win32com.client
from win32com.client import constants as c
myWpf = win32com.client.Dispatch("MyWpfApp.MyWpfClass")
This fails, reporting
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 114, in _GetGoodDispatchAndUserName
return (_GetGoodDispatch(IDispatch, clsctx), userName)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 91, in _GetGoodDispatch
IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
com_error: (-2147221164, 'Class not registered', None, None)
I can see the class "MyWpfApp.MyWpfClass" int the registry and also from OLE Viewer.
I've done this kind of thing many times for a C++ based application without any problems. However this was with either an ATL project or MFC app with automation switched on. In this case I have converted WPF application to a dll and converted to COM by hand.
Could someone please advise what else I need to do to run the app from python?
Thanks in advance.
Further Edit :
I can load the typelib in python but still can't access the com class
I ran
import win32com.client
import pythoncom
myApp = pythoncom.LoadTypeLib("D:\\MyWorkSpace\\testProgs\\ATL_COM\\WPF\MyWpfApp\\MyWpfApp\\bin\\Debug\\com.MyWpfApp.tlb")
downloads_stat = None
for index in xrange(0, myApp.GetTypeInfoCount()):
type_name = myApp.GetDocumentation(index)[0]
type_iid = myApp.GetTypeInfo(index).GetTypeAttr().iid
print type_iid
print type_name
if type_name == 'MyWpfClass':
downloads_stat = win32com.client.Dispatch(type_iid)
This confirms that the classes are loaded but I can't access them because they are reported as not registered.
>>>
{B5E3A6C6-09A0-315C-BF3A-CB943389F610}
MessageHelper
{FBE23BB0-3EDC-3A65-90EB-DF84F7545D70}
COPYDATASTRUCT
{8BEE824F-F708-3052-BC21-A9EC4E1BB002}
MainWindow
{8C0044EF-91A9-3CB3-9945-1ACA076F3D7E}
NextPrimeDelegate
{F75D3377-D677-41BF-B3D5-C677C442228F}
IMyWpfAppInterface
{D936A84B-8B1C-4D62-B090-C06E3EB5EEE9}
MyWpfClass
Traceback (most recent call last):
File "D:\MyWorkSpace\testProgs\ATL_COM\WPF\MyWpfApp\MyWin32App\Python\MyPythonClient.py", line 15, in <module>
downloads_stat = win32com.client.Dispatch(type_iid)
File "C:\Python27\lib\site-packages\win32com\client\__init__.py", line 95, in Dispatch
dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 114, in _GetGoodDispatchAndUserName
return (_GetGoodDispatch(IDispatch, clsctx), userName)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 91, in _GetGoodDispatch
IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
com_error: (-2147221164, 'Class not registered', None, None)
>>>
I can also confirm that there is an entry 'MyWpfApp.MyWpfClass' in the registry with the class id {D936A84B-8B1C-4D62-B090-C06E3EB5EEE9}.
Further Edit:
I tried installing Python for .Net and ran the following command
import clr;
import sys
sys.path.append('D:\\MyWorkSpace\\testProgs\\ATL_COM\\WPF\\MyWpfApp\\MyWpfApp\\bin\\Debug')
clr.AddReference("MyWpfApp.dll")
However this produced the following error
FileNotFoundException: Unable to find assembly 'MyWpfApp.dll'.
at Python.Runtime.CLRModule.AddReference(String name) in C:\Users\Barton\Documents\Visual Studio 2008\Projects\PySharp\trunk\pythonnet\src\runtime\moduleobject.cs:line 375
My knowledge of COM, Assemblies and typelibs are quite limited so I would appreciate if someone could help me understand what I need to do to access the DLL from python.
When I look at the entry in OLE/COM Object viewer, it points to the tlb file, not the dll, i.e.
Win32=D:\MyWorkSpace\testProgs\ATL_COM\WPF\MyWpfApp\MyWpfApp\bin\Debug\com.MyWpfApp.tlb
So, it is only the tlb file that is registered, not the class. When I run the LoadTypeLib class I am loading this from a path on my hard drive. I need the dll to be registered when I attempt to dispatch. Otherwise, if I can access this directly from a fixed path this would also be good but I don't know how to do this.
Again, thanks for your help.

Effect of LoaderOptimizationAttribute

I have written a small piece of code regarding the dynamic loading of assemblies and creating class instances from those assemblies, including an executable, a test lib to be dynamically loaded and a loader library to load dynamic assembly into a new Appdomain. Loader library is referenced by both executable and the dynamic library.
//executable
[System.STAThreadAttribute()]
[System.LoaderOptimization(LoaderOptimization.MultiDomain)]
static void Main(string[] args)
{
AppDomainSetup domainSetup = new AppDomainSetup()
{
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
LoaderOptimization = LoaderOptimization.MultiDomain
};
AppDomain childDomain = AppDomain.CreateDomain("MyDomain", null, domainSetup);
Console.WriteLine(AppDomain.CurrentDomain.SetupInformation.LoaderOptimization.ToString());
Console.WriteLine(childDomain.SetupInformation.LoaderOptimization.ToString());
byte[] assembly = null;
string assemblyName = "CSTestLib";
using (FileStream fs = new FileStream(assemblyName+".dll",FileMode.Open))
{
byte[] byt = new byte[fs.Length];
fs.Read(byt,0,(int)fs.Length);
assembly = byt;
}
object[] pararmeters = {assemblyName,assembly};
string LoaderAssemblyName = typeof(AssemblyLoader).Assembly.FullName;
string LoaderClassName = typeof(AssemblyLoader).FullName;
AssemblyLoader assloader = (AssemblyLoader)childDomain.CreateInstanceAndUnwrap(LoaderAssemblyName,LoaderClassName , true, BindingFlags.CreateInstance, null, parameters, null, null);
object obj = assloader.Load("CSTestLib.Class1");
object obj2 = assloader.Load("CSTestLib.Class2");
AppDomain.Unload(childDomain);
Console.ReadKey();
}
//Dynamic Lib
using System;
namespace CSTestLib
{
public class Class1 :MarshalByRefObject
{
public Class1() { }
}
public class Class2 : MarshalByRefObject
{
public Class2() { }
}
}
//Loader Library
using System;
namespace LoaderLibrary
{
public class AssemblyLoader : MarshalByRefObject
{
string assemblyName;
public AssemblyLoader(string assName, byte[] ass)
{
assemblyName = assName;
AppDomain.CurrentDomain.Load(ass);
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + " " + AppDomain.CurrentDomain.SetupInformation.LoaderOptimization.ToString());
}
public object Load(string className)
{
object ret = null;
try
{
ret = AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, className);
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
return ret;
}
}
}
Here I set LoaderOptimizationAttribute on main() method but AppDomain.CurrentDomain.SetupInformation.LoaderOptimization.ToString(); says it is NotSpecified Why?
The differences between MultiDomain and MultiDomainHost is not so clear to me. Is MultiDomainHost for only GAC assemblies? For my situation which is more suitable?
According to this
JIT-compiled code cannot be shared for
assemblies loaded into the load-from
context, using the LoadFrom method of
the Assembly class, or loaded from
images using overloads of the Load
method that specify byte arrays.
So how can I detect if an assembly is loaded domain-neutral or not? How can assure I it is loaded domain-neutral?
This attribute has only an effect if you precompile your assemblies with NGen to speed up a warm start of your application. When you specify MultiDomain or MultiDomainHost you enable the usage of precompiled (ngenned) assemblies. You can verify this with Process Explorer where you can look at the list of loaded modules.
This is one of the biggest startup time savers if your application consists of several executable instances which share assemblies. This enables .NET to share the code pages between processes which in turn saves real memory (one assembly exists only once in the physical memory but it is shared between one or more processes) and prevents JITing the same code over and over again in each process which takes time at the cost that the generated code is a little less efficient as it could be when it would be compiled with the regular JIT which can use more dynamic data to generate the most efficient code.
In your example you load the assembly into a byte array which is located in the managed heap and increases your private byte count. This makes it impossible to share data between processes. Only read only pages which have a counterpart on your hard disc can be shared between processes. This is the reason why the attribute has no effect. If you are after a factor 2 of warm startup performance this is the attribute you were seeking for. For anything else it is not relevant.
Now back to your original question:
It is set but when you start your application under a debugger this MultiDomain attribute is ignored. When you start it outside of a debugger you will get the expected results.
Yes MultiDomainHost does enable AppDomain neutrality only for signed assemblies all others are not shared.
Code sharing can only happen when it is precompiled. The real question is: How to check if the assembly is precompiled? I do it with Process Explorer by looking at the list of loaded modules. When my loaded assembly shows up with a path to the Native Image cache and an .ni extension I am sure the precompiled image is beeing used. You can check this also with fuslogvw when you set the radio button to Native Images to check why a native images was not used by the runtime.

ILMerge alternative, how to embed application’s dependent DLLs inside an EXE file?

As stated here im trying to embed the dlls in the exe application in order to just distribute one exe, but when i try to run my application on a xp machine with full .NET 4 installed it just crashes with no error, im placing the following code on the main method
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
String resourceName = "AssemblyLoadingAndReflection." + new AssemblyName(args.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmrPrincipal());
}
i have a folder named dlls where im placing
Functions.Shared.dll
Alex.UI.dll
Alex.Controls.dll
and im setting its Build Action to "Embedded Resource".
if i remove that piece of code and set the dlls to be included by click once installer it works fine. btw im Using .NET Framework 4 Full profile and VS2010 SP1
The jitter goes kaboom when it tries to jit the Main() method. AssemblyResolve isn't registered yet, chicken and egg problem. You can only use types in Main that are available, so you'll have to stay away from frmrPrincipal. Using a little helper method can solve that problem, but now you'll have to suppress inlining with [MethodImpl]. You are also shooting your foot by not allowing ngen.exe to do its job.
using System.Runtime.CompilerServices;
...
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
// etc..
}
AvoidJitterBombing();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void AvoidJitterBombing() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmrPrincipal());
}
I played with this recently, starting from this or a very similar piece of code, and I think the construction of the resourceName is wrong. Try putting a breakpoint at the beginning of the resolve method, and then calling GetManifestResourceNames() on the executing assembly to see what name it is actually giving your embedded resources.
I suspect it's probably "dlls.Functions.Shared" and so forth instead of "AssemblyLoadingAndReflection.Functions.Shared"
You might take a look at .NETZ, we used for WinForms application deployment along with ClickOnce.
I suspect you are trying to load a dll with unmanaged code. For managed dlls merely reading and loading the assembly in memory would do or you can load from a certain location without even reading. For mixed mode assemblies, I had success only by writing the bytes to a file and loading from its location.
class Program
{
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string assemblyName = new AssemblyName(args.Name).Name;
if (assemblyName.EndsWith(".resources"))
return null;
string dllName = assemblyName + ".dll";
string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);
using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
{
byte[] data = new byte[stream.Length];
s.Read(data, 0, data.Length);
//or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);
File.WriteAllBytes(dllFullPath, data);
}
return Assembly.LoadFrom(dllFullPath);
};
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmrPrincipal());
}
}
where Program is the class name. To avoid chicken and egg problem, you have to ensure you declare the handler before accessing assembly and that you do not access the assembly members (or instantiate anything that has to deal with the assembly) inside the loading (assembly resolving) part. Also take care to ensure GetMyApplicationSpecificPath() is not any temp directory since temp files could be attempted to get erased by other programs or by yourself (not that it will get deleted while your program is accessing the dll, but at least its a nuisance. AppData is good location). Also note that you have to write the bytes each time, you cant just load from location just 'cos the dll already resides there.

Categories

Resources