My managed application has a few dependencies on unmanaged DLLs. Even though my unmanaged DLLs are deployed in my bin folder they don’t get loaded. I already found a (hopefully) outdated SO post which points out two possible solutions:
add dlls to a well-known lookup path (e.g. \System32\Inetsrv)
add my bin folder to PATH
However, I don’t like either solution as it basically adds a dependency outside my deployment folder (=outside my jurisdiction). Can’t I let IIS know to load an unmanaged DLL (e.g. through web.config)?
You could load the unmanaged DLL passing the full path where it's located to LoadLibraryEx:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
//...
//get the physical path of the root directory of the application
string rootPath = System.Web.HttpContext.Current.Server.MapPath("~");
string libPath = Path.Combine(rootPath, "bin", "relative path to your DLL");
var h = LoadLibraryEx(libPath, IntPtr.Zero, NativeDlls.LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH);
if (h == IntPtr.Zero)
{
throw new Exception("Error in LoadLibrary: " + Marshal.GetLastWin32Error());
}
Library should be set to be copied to the output directory of the build.
Related
How to turn this Hello-JNI project https://codelabs.developers.google.com/codelabs/android-studio-jni/index.html?index=..%2F..%2Findex#0
to an Xposed module and use method "getMsgFromJni" inside hooking methods?
I dont know if Xposed already supports this feature but it should be possible to place the .so in the apps native libraries folder or perhaps hook Android's DexClassLoader to load your library.
I have successfully loaded .so files into other apps using a class loader. My solution can be a nice use case so you can find how to make it do what you want. Basically I placed the libraries in /data/local/tmp/natives and then did something like:
//JNI classes are in data/local/tmp/dexjars/
File[] files = new File("data/local/tmp/dexjars/" + type + "/").listFiles();
//Folder to store optimized dex code
String hash = "dex" + lpparam.packageName.hashCode();
//In case you want to have several packages to load
for (File file : files) {
final File tmpDir = new File("data/local/tmp/optdexjars/" + hash + "/");
tmpDir.mkdirs();
//Create a DexClassLoader that links yo your native libraries
final DexClassLoader classloader = new DexClassLoader(
file.getAbsolutePath(), tmpDir.getAbsolutePath(),
"data/local/tmp/natives/",
ClassLoader.getSystemClassLoader());
//Retrieve your classes performing the JNI
Class c = Class.forName("FULLY_QUALIFIED_JNI_CLASSNAME", true, classloader);
}
If you need some details on how to package your functionality take a look here.
If you find how to do it in a easier way please do post.
Good luck!
I am trying to send a dicom file to a remote AE, it seems like it could be done instantly with DCXREQ object and Send method from the rzdcx.DLL, however, it didnt work when I was trying to add rzdcx.dll to my reference, it says please make sure that the file is accessible, and that it is a valid assembly or COM component, what are the possible ways to fix this problem in order to successfully add this reference??
So far I have tried DllImport, the object from the dll cannot be created.
[DllImport(#"C:\Users\Kevin Eger\Documents\Visual Studio 2010\Projects\RealDicomServer\RealDicomServer\bin\Debug\rzdcx.dLL", EntryPoint = "DCXREQ")]
public static extern void Send(string localAE, string remoteAE, string IPA, int PortN, string filepath, string succeededFilesList, string failedFileList);
static void main()
{
string s = "";
string f = "";
DCXREQ requester = new DCXREQ();
requester.Send();
}
RZDCX.DLL is a COM object.
To develop with it you have to regsvr32 it.
From command line with admin rights do the following:
regsvr32 rzdcx.dll
For distribution you can check in the references "Isolated COM" so RZDCX can be used in user mode and your users don't have to regsvr32
I am creating two solutions for a project I am working on, one for the main server, which will ideally continuously run without need for update. The secondary solution is a DLL, where programmers will continuously change and update code. The server solution is a windows Application and the programmer's solution (the one constantly changing, AKA JupiterCode.dll) is a Class Library.
I am accessing the code via telnet, which is required, and will be entering commands there. The input string will then be executed via reflection on the DLL file ("The user entered 'smile'. Is there a command called 'smile'? Yes, ok, let's execute that code."). I have all of that working and it's going swimmingly, but I hit a snag for when I want to actually update the DLL so that there are more commands the user can enter. When I rebuild the Class Library, the server does not yet reflect the new changes. The server only reflects the new changes when I rebuild the server.
I am trying to have it so when a user enters UPDATE into the telnet server, it will update the loaded DLL with the new DLL, but when I try to do something like...
string originalDllPath = "C:\\Users\\*****\\Documents\\PseudoGameClient\\bin\\Debug\\JupiterCode.dll";
string newDllPath = "C:\\Users\\*****\\Documents\\PseudoServerStub\\bin\\Debug\\.dll";
string newDllBakPath = "C:\\Users\\*****\\Documents\\PseudoServerStub\\bin\\Debug\\JupiterCodeNewBak.dll";
string oldDllPath = "C:\\Users\\*****\\Documents\\PseudoServerStub\\bin\\Debug\\JupiterCode.dll";
string oldDllBakPath = "C:\\Users\\*****\\Documents\\PseudoServerStub\\bin\\Debug\\JupiterCodeBak.dll";
try
{
File.Copy(originalDllPath, newDllPath, true);
AppDomain.Unload(updatedCodeDomain);
AppDomain sandbox = AppDomain.CreateDomain("Sandbox");
Assembly assembly = sandbox.Load(oldDllBakPath);
upToDateCode = assembly;
File.Copy(oldDllPath, newDllBakPath, true);
File.Copy(newDllPath, oldDllPath, true);
AppDomain.Unload(sandbox);
AppDomain newCodeDomain = AppDomain.CreateDomain("NewCode");
assembly = newCodeDomain.Load(oldDllPath);
upToDateCode = assembly;
File.Copy(newDllBakPath, oldDllBakPath, true);
File.Delete(newDllPath);
File.Delete(newDllBakPath);
updatedCodeDomain = newCodeDomain;
}
catch (Exception ex)
{
}
In this method, once it gets to
Assembly assembly = sandbox.Load(oldDllBakPath);
It gives me the exception:
"Could not load file or assembly 'C:\\Users\\aderbedrosia\\Documents\\PseudoServerStub\\bin\\Debug\\JupiterCodeBak.dll' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)":"C:\\Users\\aderbedrosia\\Documents\\PseudoServerStub\\bin\\Debug\\JupiterCodeBak.dll"} System.Exception {System.IO.FileLoadException
(Note: Uptodatecode is kept as a class field because I refer to it later down to execute the commands on it, which again, is working perfectly fine, save for the inability to update.)
I have also tried:
File.Copy(originalDllPath, newDllPath, true);
Assembly assembly = Assembly.LoadFrom(oldDllBakPath);
AppDomain.Unload(updatedCodeDomain);
AppDomain sandbox = AppDomain.CreateDomain("sandbox");
sandbox.Load(assembly.GetName());
upToDateCode = null;
upToDateCode = assembly;
File.Copy(oldDllPath, newDllBakPath, true);
File.Copy(newDllPath, oldDllPath, true);
assembly = Assembly.LoadFrom(oldDllPath);
AppDomain.Unload(sandbox);
AppDomain sandbox2 = AppDomain.CreateDomain("secondarySandbox");
sandbox2.Load(assembly.GetName());
upToDateCode = assembly;
File.Copy(newDllBakPath, oldDllBakPath, true);
File.Delete(newDllPath);
File.Delete(newDllBakPath);
updatedCodeDomain = sandbox2;
and it errors out on
sandbox.Load(assembly.GetName());
with
"Could not load file or assembly 'JupiterCode, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=9a98a67e4d0b3db8' or one of its
dependencies. The system cannot find the file
specified.":"JupiterCode, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=9a98a67e4d0b3db8"
Again, to reiterate, I am able to dynamically load the assembly at runtime, but replacing the loaded DLL with a more up to date one (at runtime, without rebuilding) is proving difficult.
For anyone who is facing the same problem, I was able to use a dynamic compiler. look into CSharpCodeProvider and CSharpCodeProvider.CompileAssemblyFromFile. It was everything I needed.
I'm trying just to see resource names but nothing appears.
I've made and compiled a C++/CLI (Managed) DLL in Visual Studio 2010 and added some Resource files as a test (one icon and one bitmap). I've checked with PE Explorer and the resources definitely are there.
My simple code:
Assembly asm = Assembly.LoadFrom("C:\\test.dll");
String[] res = asm.GetManifestResourceNames();
I know that the DLL is loaded because when I debug i can see all the infos in the 'asm' variable. Also i can Import data (using MEF) from the DLL.
So, the DLL has the resources and the code IS loading the assembly for sure. But why my 'res' variable always returns empty string list?
EDIT:
I've created a C# Class Library (.dll) with a resource just for a test. Now it works!! But still in my C++/CLI DLL the resources do not appear. Somehow they are in the DLL but the code cant reach it (only in the C++ DLL). Maybe it would have something to do with managed/unmanaged code, but since i'm compiling it with CLR it does not seem to be the case. Any suggestions?
SOLUTION
I've got it! Just in case someone needs.
According to these topics:
Embedding resource in a C++/CLI project
and
http://bytes.com/topic/net/answers/571530-loading-markup-xamlreader-load-resource-file#post2240705
the problem is exactly the C++/CLI thing. You have to add it in Input item under Linker tab in Project Properties. Now it seems to work fine. Thanks
I have a similar problem and your question helps me to solve it.
my project platform is C++/CLI and my DLL platform is c#.
I want to pack DLL into my executive file, hence we should put DLL in the project resource file through below steps at first:
1.copy DLL in project path.
2.put DLL name(e.g. test.dll) in below place
properties->linker->input->Embeded Managed Resource File
then we should read and use embedded DLL:
Stream^ stream = Assembly::GetExecutingAssembly()->GetManifestResourceStream("test.dll");
array<unsigned char>^ dllRawBuffer = gcnew array<unsigned char>(stream->Length);
int res = stream->Read(dllRawBuffer, 0, stream->Length);
stream->Close();
Assembly^ dllAssembly = Assembly::Load(dllRawBuffer);
System::Type^ testclass = dllAssembly->GetType("TestNamespace.TestClass");
MethodInfo^ TestMethod = testclass->GetMethod("TestMethodName");
// Create an instance.
Object^ Testobj = Activator::CreateInstance(testclass);
// Execute the method.
array<Object^>^ params = gcnew array<Object^>(2);
params[0] = 2;
params[1] = 3;
Object^ result = TestMethod->Invoke(Testobj, params);
obviously, this solution only works for managed DLLs.
I am trying to access the i18n properties file I'm using in my JSF application in code. (The idea is to have a page that displays its keys and values as a table actually.)
The project is a maven project, and in the src/resources/localization folder, and deployed in the war file in WEB-INF\classes\localization\
java.util.Properties prop = new java.util.Properties();
String path = "localization/stat_codes.properties";
InputStream foo = prop.getClass().getResourceAsStream(path);
But the variable foo turns out to be null whatever I set the path variable to, /WEB-INF/classes/localization/stat_codes.properties, "localization.stat_codes.properties" etc. A similar question is here, but there is no helpful answer there as well.
The Class#getResourceAsStream() can take a path which is relative to the location of the Class which you're using there as starting point. So, for example, if the class is located in the com.example package and you request the path foo/filename.properties, then it will actually load the com/example/foo/filename.properties file. But if you use /foo/filename.properties, then it will actually load foo/filename.properties from the classpath root.
So, your code
java.util.Properties prop = new java.util.Properties();
String path = "localization/stat_codes.properties";
InputStream foo = prop.getClass().getResourceAsStream(path);
will actually look for java/util/localization/stat_codes.properties file.
But in applications with a complex multiple classloader hierarchy, the one classloader isn't the other. The classloader which loaded the core Java classes does not necessarily have knowledge about files which are in the webapp's /WEB-INF/classes. So prefixing the path with / will not necessarily be the solution, it would still return null.
If you can guarantee that the current class is visible by the same classloader as the properties files (because they're in the same sub-root of the classpath, e.g. /WEB-INF/classes, then you should indeed use
String path = "/localization/stat_codes.properties";
InputStream foo = this.getClass().getResourceAsStream(path);
But if at some point, the properties files will be externalized because of more easy maintenance/editing during runtime so that you don't need to rebuild/redeploy/restart the webapp whenever you want to edit the files, then the above line of code will likely fail as well. The externalized location would be only accessible by a different classloader. The canonical solution is to use the thread's context classloader as starting point instead, it has access to all resources in the classpath.
String path = "localization/stat_codes.properties";
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream foo = loader.getResourceAsStream(path);
(note that this one cannot take a path starting with /, it's always relative to the common root)
See also:
Where to place and how to read configuration resource files in servlet based application?
ExternalContext#getResourceAsStream() returns null, where to place the resource file?
It seems that the culprit is the prop object, I supposed any object would work, but it has to be the current object (this) on which the method getClass() is invoked, it seems. Also, the path should start with a / since the localization directory resides in WEB-INF/classes.
String path = "localization/stat_codes.properties";
InputStream foo = this.getClass().getResourceAsStream(path);