include assemblies via code? C# - c#

In msvc i can write
#pragma comment(lib, "my.lib");
which includes my.lib in the linking stage. In my solution i have 2 projects. One is a class project the other is my main. How do i include the reference dll in code instead of adding the reference in the project?

Contrary to popular belief, it is possible :-)
To statically link .NET assemblies check out ILMerge. It's a utility that can be used to merge multiple .NET assemblies into a single one. Be it an executable or a DLL.
You could create a batch script that packages your assemblies together as a post-build step.
Edit: One thing to note however is that this does not remove the need to reference the library. The reference is still needed in order to compile your code that is dependent the external types. Much like including header files under C(++). By default c# assemblies are independent, there is no linking involved. However the tool I mentioned above allows you to create a new assembly with the external dependencies included.

As far as I know, you can't. If you need to access type that are included in a non referenced assembly, you'll have to use Assembly.Load().

I'm afraid you can't.
You can dynamically load the assembly via Assembly.Load(...) but then you have use reflection to explicitly create each Type you need to use.

I don't think you can include a dll from code without adding a reference. What you can do however is to use reflection to load that assembly and use a type from that assembly.
Assembly.Load() will get you a handle on the assembly and then you should be able to iterate through the types in the assembly.

Managed code doesn't use a linker. The C/C++ equivalent of a reference assembly is the #include directive, you need that in C/C++ to allow the compiler to generate code for an external type. Exact same thing in C#, you can't use an external type unless the compiler has a definition for it. The reference assembly supplies that.
The equivalent of C/C++ linking is done at runtime in a managed program. The JIT compiler loads assemblies as needed to generate machine code.
One thing you can do in a C# program that you can't do in a C/C++ program is using Reflection. It allows you to invoke a constructor and call a type's methods with type and method names as strings. Start that ball rolling with Assembly.GetType() and the methods of the Type class. However, consider a plug-in model with, say, the System.AddIn namespace first.

If you want to load an assembly at runtime, you can use Assembly.LoadFrom(filePath). But that way you are not referencing the assembly, and you can't use strong typing.
For example, you can have different plugins implementing a known interface (the one which is in a separate, referenced assembly), and have them all placed in a folder. Then you can check the folder and load all implementing classes at runtime (like in this example).

Related

Reference has not compile-time usages

I've been watching over the architecture view of our solution created by ReSharper, when I noticed some of the project references has no compile-time usages, does that mean I can change assemblies at runtime?
In simple terms, no compile-time usage means that your code will compile even if you remove the reference. You cannot directly derive anything regarding runtime from this statement. It might even be that your application runs perfectly fine if you just remove this reference. It might also be that your reference is somewhat obfuscated and the compiler doesn't know it. This could be because the reference is implementing interfaces that you compile against or you are looking for it manually at runtime (see Florians answer). You could probably also hide it with reflection if you really wanted to. But that would also need to load the assembly manually at runtime.
At compile-time, the compiler will link the new binaries to the corresponding code in the referenced assemblies. This will allow automatically loading the assembly at runtime. It will also copy const values to your assembly.
You can definitely change the referenced assembly between compile- and runtime, although you should tread very carefully. If method signatures changed, compile-time references will break.
At runtime, referenced assemblies will be loaded once you try to interact with them. Once an assembly is loaded, it cannot be unloaded directly. You can only unload AppDomains. So if you want to change assemblies at runtime, look into AppDomains.
So what could be an intended use of those non-compile-time references? The most common architecture that uses this was mentioned by Florian in the other answer: Plugins. Also other dependencies where you want to separate your code from the actual implementation via interfaces. Your project references without compile-time dependencies are then only used to deliver the implementation to the actual application. Otherwise you would need to add this to your delivery and debugging process, which can be a pain depending on your project.

Importing nested COM references

In Visual Studio 2015 if I create a "class library" C# project and then add a reference to a custom COM DLL (created using VB6), VS will then also automatically add all (?) the COM references that the VB6 DLL depends on.
How does it do this? How can it statically figure out what those references are?
Note -- Our VB6 DLL uses "early binding", but even still there is no equivalent of an imports table for COM items like you would see in a traditional "C" style DLL.
You are actually adding a reference to a type library. It is embedded inside the DLL as a resource. You can see it when you use File > Open > File, select the DLL, open the TYPELIB node. It plays the exact same role as metadata in a .NET assembly, listing the type definitions of the exposed interfaces and classes. It has a binary format, you can decompile it with the OleView.exe utility.
And has dependency info as well, the registry helps to find such dependent type libraries (HKLM\Software\Wow6432Node\Classes\Typelib key). Roughly the same role that the GAC plays in .NET. COM just isn't as different from .NET as everybody assumes :) The first version of the CLR was created by the COM+ group at Microsoft. Eliminating the registration and DLL Hell problems associated with COM were on the top of the todo list.
Type libraries are not exactly legacy, they still play a pivotal role in the brand-new WinRT (aka UWP, aka Modern UI). Which is COM-based at its core, very well hidden. But the olden format was retired because of limitations, replaced by the .winmd format. Which is exactly the same as the .NET metadata format. Any .NET decompiler can show their content.
The reason that Visual Studio type library importer chases type library dependencies is to gather type information to map to .NET.
A type library doesn't have direct dependency information. So this is a very good question: how to track type library dependencies?
The only feasible way to detect type library dependencies is by referring to a type which states the declaring type library.
For instance, if your type library references IXMLDOMDocument in a method's signature, it'll be recorded in a type info record.
You can crawl a type library, by loading one, getting a ITypeLib from it and enumerating ITypeInfos recursively.
You'll eventually see this record. Then, you can get the type's containing type library ID through ITypeInfo::GetContainingTypeLib. If it refers to another type library, you found a dependency.
A crawler may track dependencies all the way until it has no more type libraries to load.
You don't have to crawl every type of every type library to find the strictly necessary set of types, but the job of the type library importer is to mirror type library information to .NET type info and metadata assemblies, so it imports type libraries in full. It's easier to implement, to explain/understand what it's doing and the output is reusable outside the context of the root type library.
If you didn't use early binding, your type library would instead mention IDispatch, IUnknown and/or VARIANT, which would make it impossible to detect any dependency.
You may use registration-free COM in isolated applications to have the dependencies sorted out, but it still doesn't have to be a proper dependency tree, e.g. you may state all dependencies in one manifest.
And remember that type library != DLL. A type library may be embedded as a resource in a DLL or in its own TLB file.
So, this whole talk is about type dependencies, not class/component or other runtime dependencies.
I don't think it is actually statically analyzing all the dependencies.
I think it is just adding the COM references which are part of the public API of the DLL. These would be plainly visible in the typelib which is part of the DLL, as far as I understand it.
Probably other dependencies which are used internally but not in the public interface are neglected.

How to merge F# and C# assemblies with ILMerge so that all types would be available when referenced?

I have a solution with many F# and C# projects. My goal is to merge them all to one library using ILMerge. Resulting merged dll will be put in a NuGet package and referenced in other projects. However, I'm running into few issues when merged dll is referenced in F# projects.
The problem I have is that if primary assembly given to ILMerge is F# then referencing resulting dll in F# project allows to only access F# types. If C# dll is chosen as primary assembly for merge then extension methods from merged F# assemblies were not available when referencing in F# project. Also modules with AutoOpen attribute were no longer implicitly opened when opening enclosing namespace.
Is there a way to merge F# and C# assemblies so that all types (including extension methods) would be available?
In part of our code base, a big chunk of the library is done in F# and the rest in C#. Both F# and C# code are front facing.
We have a hellish batch file to take care of mergeing and what I see is that we are merging with this code:
echo merging %mergeapp% /keyfile:"%keyfile%" /target:library /attr:"%dstpath%%csharpdll%" /targetplatform:%targetplatform%,%targetlib% /lib:%sllib% /lib:%targetlib% /lib:"%libpath%lib" /out:"%mergedpath%..\%csharpdll%" "%dstpath%%csharpdll%" "%dstpath%%fsharpdll%"
%mergeapp% /keyfile:"%keyfile%" /target:library /attr:"%dstpath%%csharpdll%" /targetplatform:%targetplatform%,%targetlib% /lib:%sllib% /lib:%targetlib% /lib:"%libpath%lib" /out:"%mergedpath%..\%csharpdll%" "%dstpath%%csharpdll%" "%dstpath%%fsharpdll%"
and that does what we intend. However, we do not publish any extension methods nor do we do any AutoOpen. What we discovered was a bug in the F# compiler that, up until we started putting obfuscation in the mix, required us to run ildasm on the F# assembly and rip out the offending code. The other issue is that F# doesn't properly support the protected modifier on members (F# makes them public) so we created an attribute that we could hang on class members that were meant to be protected. Then we wrote a tool that uses Cecil to blow the assembly apart, rip out our attribute and change the access to those members to protected (code is in the accepted answer here).
I didn't know about AutoOpen, but I had to do a similar task, so I created class called a registrant that did that kind of work like this:
type FSharpRegistrant() =
do
// do whatever I need to get going
Then in a static constructor within the C# module, I wrote some code that instantiates the F# registrant using reflection to find the class (since in my code base the C# code builds first and doesn't know there's F# code at all). This is ugly code with a lot of error checking, but it works.

Using C# preprocessor to add reference

I have a large application that I can build through the command line. I want to specify a flag that enables me to compile it into either one of two modes, Actual or Simulated.
So the main issue is, how can I use the preprocessor to programmatically add a reference?
For example:
#if SIMULATED
include SimulatedFiles;
myFactory = new SimulatedFiles.simFactory();
#else
myFactory = new realFactory();
#endif
I don't want any simulated files to compiled into my "actual" application. Since there is no "include" directive in C#, I am stuck on how to accomplish this.
You cannot do this via a C# preprocessor statement because the language doesn't support the notion of references via preprocessor macros.
What you can do is use a msbuild file and alter the set of references added based on msbuild parameters.
nant/msbuild and dependency injection tool with xml configuration?
In C#, there is no real preprocessor, as you can read on the C# Preprocessor's documentation.
From the documentation (emphasis mine):
While the compiler does not have a separate preprocessor, the directives described in this section are processed as if there was one; these directives are used to aid in conditional compilation. Unlike C and C++ directives, you cannot use these directives to create macros.
Are the include files your own source code, or third-party assembly dlls?
If they are your own sources, then you can easily use conditional compilation to remove the "simulated" code from your release build, exactly as you have done in your example (just replace 'include' with 'using'). This is common practice with debugging classes for example.
If you don't "control" the source code for the includes, then you can still add a project reference, but if you conditionally compile all the code that uses the assembly, your applicaton won't ever attempt to access the assembly, so it doesn't need to be be present when the code is running.
(Another possiblity that seems less useful for you is to write a "dummy" version of the referenced assembly that you ship in place of the "real" one, or a proxy that calls the real third-party dll in simulated builds only. If it supplies the public classes and methods that you call, you can ship the dummy instead of the simulated assembly to your customers)

Can a referenced DLL be loaded even if it's not called?

Env.: .NET / VS2008
Hi All,
My app uses a 3rd party DLL assembly separately installed on some systems (clearly identified) but not all of them.
Which means that on some systems, the DLL is not there hence must not be called. To solve this, I have 2 versions of the app (using 2 configurations) for the 2 use cases. In one of them, all calls to the DLL are #if'ed out.
Since there are no calls to the DLL compiled at all in the app(they're #if'ed out), is it safe to assume that the app won't try to load the DLL even though it is referenced?
Or should I also exclude the reference?
Note: Asked in reaction to womp's comment in this question.
TIA,
IIRC, the C# compiler will omit references to dll's that are never actually used in the code. So if all code is inside #ifs, the reference to the dll will not be there in your compiled app, and the dll will never be loaded.
You can check this using Reflector, by the way. Just drag & drop your compiled app into Reflector, and look at the References node. ILDASM also provides this feature, I think.
Caveat: DllImports and dynamic type loading (e.g., Type.GetType("type,dll")) will dynamically load dlls without the C# compiler knowing or caring. But again, if inside the proper #ifs, nothing will be loaded.
I would exclude it. It might load it no matter what and if you have a type reference, then that also could cause a problem.
Why not load the the assembly dynamically if needed/available? And then if its gets added at a later date you can just make use of it? You'll only need one version of your app also.
You are safe with a reference but without the actual DLL if you never (obviously) instantiate and referenced class AND never refer to the Class in any instantiated or referenced object.
Typically your DLL will be loaded the first time the Class Constructor of a referenced Class is run.
HTH
Jan

Categories

Resources