Can you force MonoTouch to include an unreferenced assembly in its static compilation? - xamarin.ios

I have a MonoTouch app that dynamically instantiates a class (using Type.GetType()) at runtime. The class is in an assembly that is not referenced anywhere else in the app, so the MonoTouch static compiler thinks that the assembly isn't used and ignores the assembly when it compiles the app. If I add a reference to the class in the app, then the compiler includes the assembly and the call to Type.GetType() works fine:
MyAssembly a;
I would prefer to just tell the compiler to always include all the assemblies listed in the project's "References" when it compiles the app. Is this possible?
Thanks,
-Tom B.

You will have to change your project's Linker behavior from "Link all assemblies" to "Link SDK assemblies only".
The other solution, if you have the project code that assembly was created with, is to mark the class you want to use with the PreserveAttribute.

Were you able to figure this out yet? If not, I had a similar problem: Is there a way to force MonoDevelop to build/load an assembly?
As I understand it, that's just how the C# compiler works. I was able to get around this by adding a custom pre-build step that scripts a class into the referencing assembly that includes dummy references to the unreferenced assemblies, like so:
using System;
namespace MyNamespace
{
public static class Referencer
{
Type t;
//These lines are scripted one per class in the unreferenced assemblies
//You should only need one per assembly, but I don't think more hurts.
t = typeof(Namespace1.Class1);
t = typeof(Namespace2.Class2);
...
t = typeof(NamespaceN.ClassN);
}
}

Related

Calling C external library (.so) from android java

I am writing an example android app to demonstrate the use of our (university research) C/C++ library.
I know that, using jni, we can call C functions from java.
However, I have not found a step by step set of instructions for how to do this within Android Studio Artic Fox.
I have seen the need to write jni compatible C wrapper functions, but have not found how to do this (correctly formed function signatures) or where to put them.
In addition, what do I need to change in the project setup to correctly build the project (using gradle) ?
Note that I have to use directly the pre-built .so file and the public header file which defines the set of public C functions for the library.
There are plenty of examples which give partial outdated information, but still nothing comprehensive - or have I missed something ?
I put together a quick guide below, but I want to clarify how it all fits together first.
In an Android application, you can bind native methods to specially-named functions that are loaded from a native library.
These specially-named functions receive pointers to a JNIEnv struct to interact with the embedding Java application.
The native library is typically built using CMake. Any external dependencies (such as your prebuilt library) need to be made visible to CMake in its CMakeLists.txt. The weapon of choice here are IMPORTED libraries, which are exactly what you think they are.
the steps
First, create an Android project with Kotlin as language.
Right click the app at the top of the tree and select "Add C++ to module" to generate the necessary build stuff.
Change your MainActivity.kt file to be:
class MainActivity : AppCompatActivity() {
external fun doit();
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val nativeThread = Thread {
doit()
}
nativeThread.start()
}
}
You will get a build error stating "cannot resolve corresponding JNI function". If you select the quick fix for that, Android Studio will generate a .cpp file with the appropriate JNI wrapper code inside it.
The generated function will look like:
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_doit(JNIEnv *env, jobject thiz) {
// TODO: implement doit()
}
and above that will be instructions on how to load the native library from Kotlin. Copy that code to your MainActivity.kt.
Edit that .cpp file to do whatever you need to do with your native library (eg #include some files and call some functions).
Finally, edit app/src/main/cpp/CMakeLists.txt to point to your headers and precompiled library.

C++/CLI Interface is not visible from my C# Class

I have an interface in C++/CLI I need to implement in C#, but I it is not visible. However I have other classes (abstract and concrete that I can inherit from).
My C++/CLI Interface:
namespace MyNamespace { namespace MySubnamespace {
public interface class ITestInterface
{
public:
property bool FirstProperty
{
bool get();
}
property bool SecondProperty
{
bool get();
}
};
}}
I have a Test project where I use all the functionality in my Managed Library, but the Interface never becomes visible.
How I try to use it in my C# Test project: (I tried using it from a Class Library Project also, and it doesn't work either).
public class Test: MyNamespace.MySubnamespace.ITestInterface
{
}
I get "Cannot resolve symbol 'ITestInterface'"
What am I missing?
Update
I kept trying different things following the comments to my question, and I found that if I include my .h file in some other .h file of my C++/CLI project, the class becomes visible.
Basically I just do:
#include "ITestInterface.h"
In one of my other .h files of the C++/CLI project and the Class becomes visible to the c# project.
Is there a way I could avoid doing that?
C++/CLI is similar to C++ in that only .cpp files are compiled directly. Header files are only compiled when included. This is why adding an #include for your interface header works.
There are several ways to make sure your code is included for a C++/CLI class:
Have both a .h and .cpp file (even if the .cpp file only includes the .h file it corresponds to)
Have only include files and then include all of the headers in one .cpp file (which may be empty other than the includes)
Have only .cpp files (which is fine if the other code does not reference this code)

T4 template shadow copy does not work

I'm using VS2012 and T4 templates and assemblies are supposed to be shadow copied, meaning that you can reference an assembly in a template and then recompile that assembly. But this simply doesn't work for me. When I try it, when I try to rebuild the assembly, I get errors like:
Unable to copy file "obj\Debug\xxx.dll" to "..\bin\xxx.dll".
The process cannot access the file '..\bin\xxx.dll' because it is being used by another process.
The only way around it is to restart Visual Studio, and this is so tedious that I'm ready to abandon T4 entirely. What could I be doing wrong?
So this isn't really an answer yet but hopefully we get there
Test ran the following in VS2013 (I realize you run VS2012)
<## assembly name = "$(SolutionDir)\TestProj\bin\Debug\TestProj.dll"#>
<## import namespace = "TestProj"#>
namespace ConsoleApplication1
{
class <#=Testing.Name#>
{
}
}
The TestProj contains the Testing class
namespace TestProj
{
public static class Testing
{
public static string Name
{
get { return "Tester" ;}
}
}
}
This did work very well in VS2013 and as far as I remember this worked in VS2012 as well.I will try to install VS2012 on one of my machines but do you mind testing this simple sample on your installation to validate it's not something in your solution that holds the dll?
In case you are interested in the project file you can find it here:
https://github.com/mrange/CodeStack/tree/master/q21118821
I work around similar issue. T4 design time template is processed in different App domain under the same process of visual studio. When rebuild the solution Visual Studio tries to replace the referenced DLL, and it cannot replace it because it is still in use.
I work around this issue by deleting the AppDomain in which T4 template is processed. See msdn

Can`t Load C++/CLI DLL resources

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.

Listing all the classes in a DLL

I would like to list all of the classes that are in a DLL without having to load the dependencies. I don't want to execute any functionality, I just want to find out (problematically) what classes are inside of a given DLL. Is that possible? I've tried using the assembly.GetTypes() call, but it fails because of dependencies for executing the DLL. Is there any other way to list all the public classes?
I suggest you use the mono Cecil library. This is the basic example:
//Creates an AssemblyDefinition from the "MyLibrary.dll" assembly
AssemblyDefinition myLibrary = AssemblyFactory.GetAssembly ("MyLibrary.dll");
//Gets all types which are declared in the Main Module of "MyLibrary.dll"
foreach (TypeDefinition type in myLibrary.MainModule.Types) {
//Writes the full name of a type
Console.WriteLine (type.FullName);
}
This will not load all the dependencies.
Okay, I found it. This combination works to get a list of all classes without having to deal with the dependencies:
Assembly assembly = Assembly.LoadFrom(filename);
Type[] types = assembly.GetTypes();
You can use Assembly.ReflectionOnlyLoad method to load assembly without executing it.
How to: Load Assemblies into the Reflection-Only Context
Also you need to attach AppDomain.ReflectionOnlyAssemblyResolve as In the reflection-only context, dependencies are not resolved automatically.

Resources