LuaInterface - How can I load an assembly from any path? - c#

I am trying to load a .net assembly using LuaInterface. If I place the assembly in the same folder as my executable (and my LuaInterface.dll and LuaNet.dll) then everything works great. I would like to move the assembly into a different folder, but when I try that I get "A .NET exception occured in user-code". I have tried:
package.path = package.path .. "C:\\path\\to\\my\\assembly\\?.dll"
luanet.load_assembly("MyAssembly")
and
luanet.load_assembly("C:\\path\\to\\my\\assembly\\MyAssembly")
and
luanet.load_assembly("C:\\path\\to\\my\\assembly\\MyAssembly.dll")
All of these return the .NET exception error. Is there a way to define the path that LuaInterface uses?

Your assembly is loaded by your "hosting" executable, and not really loaded by the Lua environment itself. luanet.load_assembly("MyAssembly") simply makes the assembly accessible to the Lua environment. For example (C#):
using MyAssembly; //you can't compile unless MyAssembly is available
namespace LuaRunner
{
class LuaRunner
{
void DoLua()
{
using (LuaInterface.Lua lua = new LuaInterface.Lua())
{
lua.DoString("luanet.load_assembly('MyAssembly')");
//... do what you want within Lua with MyAssembly
}
}
}
}
Your running program is the "host" for Lua to run within, so it's your running program that actually loads MyAssembly. Your executable needs a reference to MyAssembly.dll, (and needs to be able to find it at runtime in the usual locations).

To search other assemblies, set the package.cpath variable. For example:
package.cpath = DATA_DIR .. "\\clibs\\?.dll;" .. package.cpath
From the Lua 5.1 documentation:
require (modname)
First require queries package.preload[modname]. If it has a value, this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the path stored in package.path. If that also fails, it searches for a C loader using the path stored in package.cpath.
package.cpath
The path used by require to search for a C loader.
Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, using the environment variable LUA_CPATH or a default path defined in luaconf.h.

Related

C#.NET 6.0 - Load Class Library from file if newer version

I'm new to using class libraries. I've started a rather large project for work which needs the ability to be a self-contained file (essentially just drop a .exe on a desktop and run it without prereqs). This means the current class libraries build inside the .exe and I'm unsure how to directly reference them - but the application knows of them and uses them.
I've so far coded the project with the separate class libraries, and it all works great, but I'm now at the part where I need to add the ability for this to load the contents of a file dynamically if the file is available and of a greater file version.
For example:
File.dll v1 is self-contained
File.dll v2 is added to C:\ProgramData\FileVersions (dynamicdLLPath)
Assembly fileDll;
private void LoadDynamicDLLs()
{
if (Directory.Exists(dynamicDLLPath))
{
string filePath = dynamicDLLPath + "File.dll";
if (File.Exists(filePath))
{
FileVersionInfo curfvi = FileVersionInfo.GetVersionInfo(myassembly.Location);
FileVersionInfo newfvi = FileVersionInfo.GetVersionInfo(filePath);
if (Convert.ToInt64(newfvi.FileVersion) > Convert.ToInt64(curfvi.FileVersion))
{
fileDll = Assembly.LoadFrom(filePath);
}
} else
{
fileDll = Assembly.GetAssembly(typeof(FileDLL));
}
}
}
(FileDLL in this instance is the namespace of the self-contained dll)
If this loads correctly, can I then just call all my methods/functions from the file assembly as;
fileDll.myMethod();
This is as far as I've gotten based on not changing any of the existing code base that works. I'd rather not go through 20,000 lines if there's a solution to simply integrate what I've already got using a local .dll class library.

Runtime error with a very basic reflection example in C#

I'm trying to learn a bit more about System.Reflection using the official microsoft docs. Specifically I'm trying to run the following example:
// Loads an assembly using its file name.
Assembly a = Assembly.LoadFrom("MyExe.exe");
// Gets the type names from the assembly.
Type[] types2 = a.GetTypes();
foreach (Type t in types2)
{
Console.WriteLine(t.FullName);
}
So I made a new console app using dotnet new console -o=customconsole. I then removed ImplicitUsings from my project file (because I don't like that), and came up with the following code:
using System;
using System.Reflection;
namespace get_type_from_assembly
{
internal class Program
{
static void Main(string[] args)
{
// load assembly using full file name
Assembly a = Assembly.LoadFrom("C:\\Users\\bobmarley\\desktop\\temp\\csharp-reflection\\get-type-from-assembly\\bin\\Debug\\net6.0\\console-custom.exe");
// get type names from assembly
Type[] types2 = a.GetTypes();
foreach (Type t in types2)
{
Console.WriteLine(t.FullName);
}
}
}
}
Then I tried to run the generated executable using dotnet run --project=customconsole. I got the following runtime error:
Unhandled exception. System.BadImageFormatException: Bad IL format. The format of the file 'C:\Users\bobmarley\desktop\temp\csharp-reflection\get-type-from-assembly\bin\Debug\net6.0\console-custom.exe' is invalid.
at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
at get_type_from_assembly.Program.Main(String[] args) in C:\Users\bobmarley\desktop\temp\csharp-reflection\get-type-from-assembly\Program.cs:line 11
make: *** [Makefile:5: run] Error 1
I'm not sure why this occurs, because I checked and the executable does exist in the specified path. What is happening here and how can I fix it?
A likely reason is that the your project and the loaded assembly target different platforms, i.e. x86 vs x64, In my experience that is a common reason for BadImageFormatException. Another possible reasons is that one targets .net core while the other targets .net framework.
Dynamically loading an assembly will require that it is compatible with your project. If you want to read arbitrary assemblies you probably want some tool that can extract whatever information you are after from the CIL code directly, without actually loading it.

c# How to get the version of This current executable .exe

I have been using this code to obtain my programs version:
public string progVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
However, it doesn't always seem to grab the version I'm expecting. I don't really understand how this works entirely or what it's doing.
I think it is impart because I'm launching my program from another program then it appears to grab the version of the program that launched it instead, or the 'GetExecutingAssembly()' I'm assuming references the program that executed my program, like so:
System.Diagnostics.Process.Start(my_programs_path);
Is there a more reliable way to get the program version of the actual program at the time I ask for it?
Perhaps even launch my program without leaving some kind of trail, as if the user themselves just launched it.
Thanks for any help!
GetExecutingAssembly() returns the assembly that contains the method that calls it. If you call it from a library you will always get the version of the library not the application executable.
To get the application's executable use GetEntryAssembly()
Consider the following example:
In AssemblyA:
class VersionTest
{
void Test()
{
Console.Write("Executing assembly: {0}\n", Assembly.GetExecutingAssembly().GetName().ToString()); // returns AssemblyA
Console.Write("Entry assembly: {0}\n", Assembly.GetEntryAssembly().GetName().ToString()); // returns AssemblyB
}
}
In AssemblyB:
class Program
{
void Main()
{
var ver = new VersionTest();
ver.Test();
}
}
You could use the Assembly property of a known type via typeof which is defined in your application to ensure you got the 'correct' assembly and then retrieve the version of that, e.g.
typeof(YourKnownType).Assembly.GetName().Version.ToString();
Thanks for the great info. I finally settled on
Assembly.GetExecutingAssembly().GetName().Version.ToString()
for my solution.

Load an assembly from an embedded resource

I would like to load a dll file (Test.dll) as an assembly. I am able to do this using both direct Visual Studio references (ie. loading the dll as a reference to my C# application) as well as loading the dll using the Assembly.LoadFile(filename) method. Now, I would like to add my dll file as an embedded resource to my Visual Studio application, and load the dll file as an assembly. I know how to load this resource as a byte array, is there some correlation between the byte array and the assembly that I could use? Furthermore, I need to be able to call a method located within the dll file. See the code below - it will further explain what I am doing.
Assembly SampleAssembly = Assembly.LoadFrom("WindowsFormsApplication2.ThisisaTESTDLL.dll");
Type myType = SampleAssembly.GetTypes()[0];
MethodInfo Method = myType.GetMethod("myVoid");
object myInstance = Activator.CreateInstance(myType,null);
Method.Invoke(myInstance,new object[] { "param1", "param1"});
If I am missing anything here, please respectfully let me know and I will edit the original post.
Assembly.GetExecutingAssembly().GetManifestResourceStream(...)
That should get you a Stream object. You can read a byte array from that.
You can load that using Assembly.Load
I embedded AxInterop.WMPLib.dll and Interop.WMPLib.dll into my exe and got them loaded by using the following code. The code is placed just at the beginning of static void Main() in Program.cs file. Target framework is .NET 3.5 in my case. This code helped me bundle the dlls into the exe itself without having to deploy them through installers. I have hardcoded my names. In the code below "res" is the name of my resource "res.resx" that contains the two embedded dlls.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(
(s, a) =>
{
if (a.Name.Substring(0, a.Name.IndexOf(",")) == "AxInterop.WMPLib")
{
return Assembly.Load(res.AxInterop_WMPLib);
}
if (a.Name.Substring(0, a.Name.IndexOf(",")) == "Interop.WMPLib")
{
return Assembly.Load(res.Interop_WMPLib);
}
return null;
});

How do you call a managed (C#) function from C++?

I have a C# DLL file project (my_cs_dll.dll) which defines a static class with a static member function.
namespace Foo
{
public static class Bar
{
public static double GetNumber() { return 1.0; }
}
}
I also have a C++ DLL project which is using /clr.
#using <my_cs_dll.dll>
double get_number_from_cs() { return Foo::Bar::GetNumber(); }
I've added a reference to 'my_cs_dll.dll' in the C++ project Common Properties references section (copy local/copy dependencies are both True).
And I've also added the path to 'my_cs_dll.dll' in the C++ project Configuration Properties C/C++ General 'Resolve#using References' section.
Everything builds without error, however at runtime I keep getting a 'System.IO.FileNotFound' exception from the system claiming it can't find the my_cs_dll.dll assembly.
Both DLL files are definitely present in the same directory from which I'm running.
I have tried all sorts of variations on the settings mentioned above and read everything I could find on manged/unmanaged interop, but I can't seem to get my brain around what is wrong...
I'm using Visual Studio 2008 and .NET 3.5.
It sounds like your C# assembly is not being resolved at runtime. Is your C# dll in the same directory as (or a subdirectory of) your executable? It's been a while since I did this, but my recollection is that unless your assembly is installed in the GAC, it must be in the directory (or a subdirectory) where your executable is located, as opposed to the location of the dll that's using it. This has to do with the .NET security features.
If you are still having problems, you can try using resolving the assembly yourself. In your clr-enabled C++ project, try adding the following:
using namespace System;
using namespace System.Reflection;
void Resolve()
{
AppDomain::CurrentDomain->AssemblyResolve +=
gcnew ResolveEventHandler(OnAssemblyResolve);
}
Assembly ^OnAssemblyResolve(Object ^obj, ResolveEventArgs ^args)
{
#ifdef _DEBUG
String ^path = gcnew String(_T("<path to your debug directory>"));
#else
String ^path = gcnew String(_T("<path to your release directory>"));
#endif
array<String^>^ assemblies =
System::IO::Directory::GetFiles(path, _T("*.dll"));
for (long ii = 0; ii < assemblies->Length; ii++) {
AssemblyName ^name = AssemblyName::GetAssemblyName(assemblies[ii]);
if (AssemblyName::ReferenceMatchesDefinition(gcnew AssemblyName(args->Name), name)) {
return Assembly::Load(name);
}
}
return nullptr;
}
You may have to tweak the code a little bit to get it to compile in your project. In my case, I made the two functions static methods of a class in my clr-enabled project. Just make sure you call the Resolve() function early on in your code, i.e., before you try to call get_number_from_cs().
While using COM is an option, it is not necessary. You're on the right path with your current approach. If you want some hand-holding, take a look at this CodeProject example. It's the one I following to get my unmanaged application to use my managed assemblies.

Categories

Resources