How to Create a File in Assembly with a Dynamically Specified File Path

How do you create a file in assembly with a dynamically specified file path?

System calls that take a const char* without a length arg always take C strings: 0-terminated, implicit length.

Like open(const char *path, int flags, int mode), unlike write(int fd, void *buf, size_t len).

This is why they work when called from C like open("input.txt", O_RDONLY), or open(argv[1], O_WRONLY|O_CREAT). Remember that C string literals give you a pointer to an array of char in static storage with a 0 terminator.

BTW, NULL is a pointer constant. NUL is ASCII '\0'. Just call them "0 terminated" strings.


So yes, you should use , 0 at the end of your db.

Command-line args are always in this C-string format; it's how Unix passes around string data across system-call / process boundaries, as well as to ISO C standard library functions. This includes all pathnames.


In Linux, on entry to _start, the stack pointer points at argc. Above that are the elements of the char *argv[] array. (Not a char **argv pointer, just an array of values right there on the stack, from ESP+4 to ESP+argc*4. Also terminated by a NULL pointer (0)). This is documented in the i386 and x86-64 System V ABI docs.

Linux Assembly x86_64 create a file using command line parameters shows an example of loading argv[1] into the pathname arg of a system call.

Reading from a file in assembly is a 32-bit example.

How to create a folder and file inside of the folder where the app is installed? c#

What you are trying to do is not advisable; if your application is installed using recommended default methods (following Microsoft guidelines) the app will be in a directory under C:\Program Files (or where the program files folder may be redirected) and the user that runs the app will not have write access to that directory, so the directory creation will fail.

That said, you cannot use the Environment.CurrentDirectory, because it may or may not be the directory where your application's executable files reside, neither CurrentDomain.BaseDirectory, because that is not significative too (documentation says it's the directory where the loader will search for assemblies, but that may or may not be the directory of your application's executable files).

Copying from this other answer, the correct way to find the directory of your assembly is

public static string AssemblyDirectory
{
get
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}

Once you have the path, you can try to create the directory with System.IO.Directory.CreateDirectory() and a file with System.IO.File.WriteAllText() or its siblings, or any other standard method of creating files.

You may also want to use the newer Assembly.GetExecutingAssembly().Location property, and use Path.GetDirectoryName() on that.

Dynamically Load Assembly and manually force path to get referenced assemblies

You could load the dependent assemblies yourself before loading the one that requires them.

How to create dynamic instance of assembly ( C# ) and loading the dependencies of instance assembly dynamically as well?

Finally I found solution for my problem.

This is what worked for me. Perfect and what I was looking for !! :)

static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

var implementor = string.Concat(Directory.GetCurrentDirectory(), @"\Implementations\Calculator.dll");
var implementorBytes = File.ReadAllBytes(implementor);

AppDomain.CurrentDomain.Load(implementorBytes);

Console.WriteLine(GetObject<IAdd>().SumNew(2, 2));
Console.WriteLine(GetObject<IAdd>().SumNew(2, 5));
}

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var dependencyResolverBaseDirectory = string.Concat(Directory.GetCurrentDirectory(), @"\Implementations");

return Directory.GetFiles(dependencyResolverBaseDirectory, "*.dll")
.Select(Assembly.LoadFile)
.FirstOrDefault(assembly => string.Compare(args.Name, assembly.FullName, StringComparison.CurrentCultureIgnoreCase) == 0);
}

public static T GetObject<T>()
{
var t = typeof(T);

var objects = (
from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetExportedTypes()
where typeof(T).IsAssignableFrom(type) && (string.Compare(type.FullName, t.FullName, StringComparison.CurrentCultureIgnoreCase) != 0)
select (T)Activator.CreateInstance(type)
).ToList();

return objects.FirstOrDefault();
}

Best way to dynamically set an appender file path

You are doing this the hard way! Define your log4net config as XML in your application's configuration file and use %property{} to advantage:

<appender name="YourAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="~/App_Data/%property{LogName}" />
....
</appender>

This is dynamic -- you just have to set the log4net property "LogName" before you initialize log4net. Thus, in your code any time before you configure log4net, set the desired value of this property:

string LogName = GetType().Assembly.GetName().Name + ".log";
log4net.GlobalContext.Properties["LogName"] = LogName;

Of course, you may use any property name. I've chosen "LogName" for a simple example, but you can have one per application if you want, as long as your code knows what the correct property name is and what the correct value should be.



Related Topics



Leave a reply



Submit