I have a C# project that contains 1 EXE and about 7 DLLs. What I would like to have is a folder beside the EXE called "Library" (or something similar) that contains all the DLLs so that it is a bit more organized and looks better for the end user.
I know this can be done using an AppConfig but the I don't want another file beside the EXE. All I want is the main EXE and the folder.
Is it possible to use AppConfig and embed it or load the DLLs without using a AppConfig that won't change how I currently use my DLLs? I know you can load a DLL at run time but I don't think that is what I am looking for.
Thanks!
EDIT
I know the pros and cons to doing this, so please only answers on how to do this and no advice as to why I should or should not do this.
Use System.Reflection.Assembly.LoadFrom(path).
LoadFrom will allow it to look in the same folder as the targetted dll for any dependencies. If you use Load, then it will not consider dlls that are sitting in the same folder as the dll you Load.
I know this doesn't directly answer your question, but manually calling LoadFrom on the DLLs early in your process startup should do the trick if you want an "xcopy" installable .net app or something.
PrettyBin is your solution. It does this beautifully!
SetDllDirectory() + carefully coded AssemblyResolve. Works for me in a nontrivial project, with no DLL hell.
https://github.com/TASVideos/BizHawk/blob/d05ddabf5f22debf47369f94868462a75ea0b466/BizHawk.Client.EmuHawk/Program.cs
I created new console application-launcher. In app folder contains my EXE file - MyApp.exe and all DLLs.
static void Main(string[] args)
{
var process = new Process
{
StartInfo =
{
FileName = "app\\MyApp.exe",
}
};
process.Start();
}
If you want the application to be launched when you drag certain files onto the EXE:
class Program
{
static void Main(string[] args)
{
if (args.Length > 0)
{
String FileName = System.IO.Path.GetDirectoryName( System.Reflection.Assembly.GetExecutingAssembly().Location )
+ "\\app\\MyApp.exe";
ProcessStartInfo startInfo = new ProcessStartInfo(FileName);
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.Arguments = args[0].ToString();
Process.Start(startInfo);
}
else {
var process = new Process
{
StartInfo =
{
FileName = "app\\MyApp.exe",
}
};
process.Start();
}
}
}
Related
I am trying to get my console application to simulate dragging and dropping a file, so far I have had no luck.
The system throws a win32 exception stating it cannot find the file, since I know that is not really the problem I was hoping someone could shed some light on what might be causing this behavior.
I suspect it might be DEP. I can drag and drop the file and the process runs as expected, but I need to automate this.
I have created a filewatcher and am right now trying to figure out how to get the code to work, prior to making it a windows service.
But right now I am really stuck on this win32 error.
public class Watcher
{
public static void Main(string[] args)
{
Run();
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public static void Run()
{
string[] args = System.Environment.GetCommandLineArgs();
// If a directory is not specified, exit program.
if (args.Length != 2)
{
// Display the proper way to call the program.
Console.WriteLine("Usage: Watcher.exe (directory)");
return;
}
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = args[1];
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// Only watch jpg files.
watcher.Filter = "*.jpg";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.EnableRaisingEvents = true;
// Wait for the user to quit the program.
Console.WriteLine("Press \'q\' to quit the sample.");
while (Console.Read() != 'q') ;
}
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
Process.Start(e.FullPath + "c:\\demo\\kr-pano\\mpr.bat");
}
Visit the link to see the full win32 exception details.
Win32Exception
Apparently the issue is being caused because the filesystemwatcher is single threaded, and when I try to launch my new process it stops the old one from running. All I needed to do was stub out a new runpano function and call it from my code, its working now.
I'm doing some introspection and analysis of csproj files using the Microsoft.Build.Evaluation tools in a small C# console app. I want to locate the actual location of Reference items, using the same heuristics as MSBuild itself ie the locations described here. I'm heading towards auto conversion of build artifacts into packages, similar to what's outlined on the JetBrains blog here
The only examples I can find expect the HintPath to be correct, for example this project, and I know there are some HintPaths that are not currently correct, I don't want to trust them. This project very close what I'm trying to do, with the added complication that I want to use real resolution behaviour to find dependencies.
I have an instance of a Microsoft.Build.Evaluation.Project object for my csproj, and I can't see any methods available on it that could exersize the resolution for me. I think what I'm hoping for is a magic Resolve() method for a Reference or a ProjectItem, a bit like this method.
I can probably find an alternative by constraining my own search to a set of limited output paths used by this build system, but I'd like to hook into MSBuild if I can.
The reference resolution is one of the trickiest parts of MSBuild. The logic of how assemblies are located is implemented inside the a standard set of tasks:
ResolveAssemblyReference, ResolveNativeReference, etc. The logic is how this works is very complicated, you can see that just by looking at number of possible parameters to those tasks.
However you don't need to know the exact logic to find the location of referenced files. There are standard targets called "ResolveAssemblyReferences", "ResolveProjectReferences" and some others more specialized for native references, COM references. Those targets are executed as part of the normal build. If you just execute those targets separately, you can find out the return values, which is exactly what you need. The same mechanism is used by IDE to get location of refereces, for Intellisense, introspection, etc.
Here is how you can do it in code:
using Microsoft.Build.BuildEngine;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using System;
using System.Collections.Generic;
class Program
{
static int Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: GetReferences.exe <projectFileName>");
return -1;
}
string projectFileName = args[0];
ConsoleLogger logger = new ConsoleLogger(LoggerVerbosity.Normal);
BuildManager manager = BuildManager.DefaultBuildManager;
ProjectInstance projectInstance = new ProjectInstance(projectFileName);
var result = manager.Build(
new BuildParameters()
{
DetailedSummary = true,
Loggers = new List<ILogger>() { logger }
},
new BuildRequestData(projectInstance, new string[]
{
"ResolveProjectReferences",
"ResolveAssemblyReferences"
}));
PrintResultItems(result, "ResolveProjectReferences");
PrintResultItems(result, "ResolveAssemblyReferences");
return 0;
}
private static void PrintResultItems(BuildResult result, string targetName)
{
var buildResult = result.ResultsByTarget[targetName];
var buildResultItems = buildResult.Items;
if (buildResultItems.Length == 0)
{
Console.WriteLine("No refereces detected in target {0}.", targetName);
return;
}
foreach (var item in buildResultItems)
{
Console.WriteLine("{0} reference: {1}", targetName, item.ItemSpec);
}
}
}
Notice, the engine is called to invoke specific targets in the project. Your project usually does not build, but some targets might be invoked by pre-requisite targets.
Just compile it and will print a sub-set of all dependencies. There might be more dependencies if you use COM references or native dependencies for your project. It should be easy to modify the sample to get those as well.
I have a difficulty with texturepacker2 from libgdx. I was trying to create textureAtlas using texturepakcer2 so that I can create animated images. However I could not use
TexturePacker2.process(Input Directory Path", "Output Directory Path", "texture_file");
Because it could not recognize TexturePacker2.
Even thought I import gdx-tool.jar file inside libs and also added libraries through
Project -> Properties -> Java Build Path -> Libraries -> Add jars, it still cannot resolve nor recognize the gdx-tool.jar.
How can I create texture atlas using TexturePakcer2? I heard there is a way to create using nightly-build from libgdx, how can I do it? When I unzip latest nightly-build there were so many jar, but I could only run setup-ui.
There are several ways. I used to take the way of implementing it into my Desktop application. Whenever i start it, the Atlas is generated. (If i changed something in it).
public class Main
{
public static void main(String[] args)
{
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "MyApp";
cfg.useGL20 = true;
cfg.fullscreen = false;
// switch for fullscreen
if (cfg.fullscreen)
{
cfg.width = Toolkit.getDefaultToolkit().getScreenSize().width;
cfg.height = Toolkit.getDefaultToolkit().getScreenSize().height;
}
else
{
cfg.width = 1280;
cfg.height = 720;
}
cfg.addIcon("data/appiconWindows.png", FileType.Internal);
// automatic packing of the textures and images and so on
Settings settings = new Settings();
settings.maxWidth = 2048;
settings.maxHeight = 2048;
settings.paddingX = 0;
settings.paddingY = 0;
TexturePacker2.process(settings, "directory with the files",
"output dir", "name of Atlas"); //third is outputdir
new LwjglApplication(new MainClass(), cfg);
}
}
Dont forget to add the tools lib to the Desktop project. gdx-tools.jar From the nightly or the Stable.
Else you can call it with the console. Like this:
java -cp gdx.jar;extensions/gdx-tools/gdx-tools.jar com.badlogic.gdx.tools.texturepacker.TexturePacker inputDir [outputDir] [packFileName]
Use TexturePacker from com.badlogic.gdx.tools.imagepacker.TexturePacker then create a class as below:
public class TextureSetup {
public static void main(String[] args) {
//TexturePacker; using default settings
TexturePacker.Settings packSettings = new TexturePacker.Settings();
TexturePacker.process(packSettings, "input-folder", "output-folder", "textures.pack");
}
}
I have a solution with libraries (DLLs) which are used in 2 identical projects (one for WP7, another for WP8). In one of the libraries I have the code which determines the version of the application.
private static Version mVersion;
public static Version Version {
get {
if (mVersion == default(Version)) {
var lcAssembly = Assembly.GetExecutingAssembly();
var parts = lcAssembly.FullName.Split(',');
var lcVersionStr = parts[1].Split('=')[1];
mVersion = new Version(lcVersionStr);
}
return mVersion;
}
}
The problem is that this code returns the version number of the library itself because of this Assembly.GetExecutingAssembly() code. How to get a MAIN Assembly version and not DLL's?
That's a great question on code-sharing between WP7 and WP8.
The simplest way for you to do that would be to read the AppManfiest.xml file at run-time, get the EntryType and use that to get at the entry point Assembly instance. Here's how a sample AppManfiest.xml looks like once MSBuild did its magic on it:
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="myAssembly" EntryPointType="myNamespace.App" RuntimeVersion="4.7.50308.0">
<Deployment.Parts>
<AssemblyPart x:Name="myAssembly" Source="myAssembly.dll" />
</Deployment.Parts>
</Deployment>
And here's how you would read the file, get the attributes, then get the entry point type and finally the entry point assembly:
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var appManfiest = XElement.Load("AppManifest.xaml");
var entryAssemblyName = appManfiest.Attribute("EntryPointAssembly").Value;
var entryTypeName = appManfiest.Attribute("EntryPointType").Value;
Type entryType = Type.GetType(entryTypeName + "," + entryAssemblyName);
Assembly entryAssembly = entryType.Assembly;
}
That's a simple solution and it works. However, that isn't the cleanest architectural solution. The way I'd implement this solution is to have an interface declared in the shared library, both WP7 and WP8 implement that interface and register their implementation with an IoC container.
For example, let's say you need to "DoSomething" in the shared library that's platform version specific. First you'll create have an IDoSomething interface. Let's also assume you have an IoC standing by.
public interface IDoSomething
{
}
public static class IoC
{
public static void Register<T>(T t)
{
// use some IoC container
}
public static T Get<T>()
{
// use some IoC container
}
}
In your WP7 app you'll implement the shared Interface for WP7 and register it once the WP7 starts up.
public App()
{
MainPage.IoC.Register(new MainPage.DoSomethingWP7());
}
private class DoSomethingWP7 : IDoSomething
{
}
You'll also do the same for WP8 in the WP8 app. And in your shared library you can then ask for the relevant interface regardless of its platform version specific implementation:
IDoSomething sharedInterface = IoC.Get<IDoSomething>();
I have a simpler answer. I think you are close with what you are doing. I just used your code with one modification so I can use it with the Telerik controls. Here's what I did. I located your code in my project's App class (codebehind of App.Xaml). I made one change that I think will take care of your problem:
private static Version mVersion;
public static Version Version {
get {
if (mVersion == default(Version)) {
var lcAssembly = typeof(App);
var parts = lcAssembly.FullName.Split(',');
var lcVersionStr = parts[1].Split('=')[1];
mVersion = new Version(lcVersionStr);
}
return mVersion;
}
}
Now I can get the version number by calling "App.Version".
This worked for me:
var appAssembly = Application.Current.GetType().Assembly;
var appAssemblyVersion = appAssembly.GetName().Version;
I tested with WP7.1 and WP8.0.
I would like to break out my controllers and views into separate class libraries so they can be reused in multiple ASP.NET MVC 3 applications. The controllers part was not an issue when using a separate assembly, however getting the view engine to locate the view was.
I ended up using Compile your asp.net mvc Razor views into a seperate dll.
Is there an easier way that I missed?
I have modified the idea posted here, to work with MVC3. It was pretty fast and easy. The only minor drawback is that shared views need to be embedded resources, and therefore, compiled.
Put your shared views (.cshtml, .vbhtml files) into a library project. (I also have some shared controllers in this project.) If you want to use the _Layout.cshtml from your application, make sure you include a _ViewStart.cshtml, that points to it, in with your shared views.
In the library project, set all of your views' Build Action properties to Embedded Resource.
In the library project add the following code which will write the contents of your views to a tmp/Views directory.
.
public class EmbeddedResourceViewEngine : RazorViewEngine
{
public EmbeddedResourceViewEngine()
{
ViewLocationFormats = new[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml",
"~/tmp/Views/{0}.cshtml",
"~/tmp/Views/{0}.vbhtml"
};
PartialViewLocationFormats = ViewLocationFormats;
DumpOutViews();
}
private static void DumpOutViews()
{
IEnumerable<string> resources = typeof(EmbeddedResourceViewEngine).Assembly.GetManifestResourceNames().Where(name => name.EndsWith(".cshtml"));
foreach (string res in resources) { DumpOutView(res); }
}
private static void DumpOutView(string res)
{
string rootPath = HttpContext.Current.Server.MapPath("~/tmp/Views/");
if (!Directory.Exists(rootPath))
{
Directory.CreateDirectory(rootPath);
}
Stream resStream = typeof(EmbeddedResourceViewEngine).Assembly.GetManifestResourceStream(res);
int lastSeparatorIdx = res.LastIndexOf('.');
string extension = res.Substring(lastSeparatorIdx + 1);
res = res.Substring(0, lastSeparatorIdx);
lastSeparatorIdx = res.LastIndexOf('.');
string fileName = res.Substring(lastSeparatorIdx + 1);
Util.SaveStreamToFile(rootPath + fileName + "." + extension, resStream);
}
}
I'm using Adrian's StreamToFile writer, found here.
In the Global.asax.cs of your application add:
.
public static void RegisterCustomViewEngines(ViewEngineCollection viewEngines)
{
//viewEngines.Clear(); //This seemed like a bad idea to me.
viewEngines.Add(new EmbeddedResourceViewEngine());
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
RegisterCustomViewEngines(ViewEngines.Engines);
}
Take a look at mvc contrib's portable areas:
http://www.lostechies.com/blogs/hex/archive/2009/11/01/asp-net-mvc-portable-areas-via-mvccontrib.aspx
They were made specifically for this purpose. If you go that road, it is less code you have to mantain ;-)
Just a few additions to Carson Herrick's excellent post...
You will need to resolve a few of the references (you will need to include System.Runtime.Remoting into your project).
Utils.SaveStreamToFile needs to be changed to ->
System.Runtime.Remoting.MetadataServices.MetaData.SaveStreamToFile(resStream, rootPath + fileName + "." + extension);
You may get the error - The view must derive from WebViewPage, or WebViewPage<TModel>. The answer is here: The view must derive from WebViewPage, or WebViewPage<TModel>
When you deploy the project, it is highly likely you will get an error when you load the project. You need to give the APP POOL you are using (full) rights to the folder.