Visual C++ static library - visual-c++

I am writing a c++ static library A.lib in visual studio 2008. In my static library, I am using few APIs exposed by another static library B.lib(.lib).
I have a written an application that uses A.lib. Since few header files in A.lib are using headers from B.lib, my application wants a path of B.lib header files. How can I avoid my application so that I need not to provide path of B.lib header files for compilation ?

Refrain from using types from B-headers in the interface of your library. A good way of totally hiding the implementation is using the factory-pattern along with pure abstract base classes as interfaces. You will still have to link B.lib in your application though.
Sample Before:
// A.h
#include "B.h"
class Foo {
public:
void DoStuff();
private:
B::Bar Data; // B::Data comes from library B
};
This in your header adds a dependency to B.
With Factory, your application now uses IFoo.h instead of A.h:
// IFoo.h
class IFoo {
public:
static IFoo * CreateInstance( ); // implemented in IFoo.cpp, just returns new Foo
virtual void DoStuff() = 0;
virtual ~IFoo() {}
};
// A.h
class Foo : public IFoo {
public:
virtual void DoStuff();
private:
B::Bar Data; // B::Data comes from library B
};

You can go to settings and add the directory to the additional include directory's and you can just use the header by name.

Related

Using Thread in in Mixed App C++ /cli to Call native Function in native class from managed class

I am working on mixed application, using both managed & native codes
I want to call a function deployed in a native class from Main() function located in Program.cpp which is managed class.
i tried using std::thread but failed with /cli
i tried to use Managed System::Threading::Thread but failed because i need to call a native function in a native class.
So how i can handle thing without using any third-party?
If you start from a native project you need to do the following steps:
Select project properties and change the option "No Common Language Runtime Support" to "Common Language Runtime Support /clr".
Open the "Property Manager" from "View" menu / "Other Windows" and add the property sheet "C++ Common Language Runtime Support" to the needed configuration (eg.: Debug | Win32) on my system this sheet is under "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140". I use the "Microsoft.Cpp.ManagedExtensions.props" file.
You need to remove std::thread completely.
headerish:
#pragma once
#include<stddef.h>
using namespace System;
using namespace System::Threading;
namespace FooSpace
{
// Native stuff
public class Native
{
public:
static void Foo() { }
void Bar() {
}
};
// Managed stuff
public ref class Managed
{
private:
Native* m_Native;
public:
Managed()
{
m_Native = new Native();
}
~Managed()
{
if (NULL != m_Native)
{
delete m_Native;
m_Native = NULL;
}
}
void Bar()
{
m_Native->Bar();
}
static void ThreadCall(Object^ o)
{
auto me = (Managed^)o;
me->Bar(); // Call a method of an instance of the native class
Native::Foo(); // Call a static method of the Native class
}
void StartThread()
{
auto t = gcnew Thread(gcnew ParameterizedThreadStart(ThreadCall));
t->Start(this);
t->Join();
}
};
}
soure file:
#include "stdafx.h"
#include "CppCli_Native.h"
using namespace FooSpace;
int main()
{
Native::Foo(); // call native static method
auto native = new Native(); // create native instance
native->Bar(); // call native method
auto managed = gcnew Managed();
managed->Bar(); // This will call bar
managed->StartThread(); // This will start a thread
delete managed;
Console::ReadLine();
return 0;
}
Edit: It turns out that you don't need to use IntPtr to store native class.
I find this answer also useful, it also gives us a fast introduction to c++-cli syntax.

Expose types from embedded interop type to other assemblies

I have an ATL COM library that defines an enum and an interface in MIDL like:
[uuid(65785D49-574A-4B1B-95F1-B9C7F283364A)]
typedef enum Options
{
Option1,
Option2
} Options;
[
object,
uuid(2E3D1B1A-DF95-434F-836B-73FF1245B608),
oleautomation,
nonextensible,
pointer_default(unique)
]
interface IExample : IUnknown
{
HRESULT Test([in] Options option, [out, retval] BSTR* str);
};
I then create a managed assembly and reference the TLB, which creates a PIA and embeds the types (Embed Interop Types = true) into the managed assembly.
In the managed assembly, I now create a class that implements the interface:
public class Example : IExample
{
public string Test(Options option)
{
return option.ToString();
}
}
Now I would like to create a third assembly that references the managed assembly and creates the object and call into it, but it doesn't let me since Options is an unreferenced type (requires me to include the PIA generated from the typelib):
public class Equivalence
{
public void UseTest()
{
Example e = new Example();
e.Test(Options.Option1); // recognizes that it requires an ExampleLib.Options parameter, but that type isn't available
}
}
Using reflector, I can see it inside the managed assembly, but it isn't viewable by object browser:
namespace ExampleLib
{
[ComImport, CompilerGenerated, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("2E3D1B1A-DF95-434F-836B-73FF1245B608"), TypeIdentifier]
public interface IExample
[Guid("65785D49-574A-4B1B-95F1-B9C7F283364A"), CompilerGenerated, TypeIdentifier("15a6cf97-c415-4866-bdfb-7da65edb1faa", "ExampleLib.Options")]
public enum Options
}
My managed assembly is itself a library intended to be distributed as an API, and I would like to expose this enumeration and interface so that it can be used by outside parties without having to deliver the PIA generated from the typelib of the ATL COM library. Is it possible?
Apparently this cannot be done. One of the errors (CS1748) pointed me to this post which says the PIA must be linked in by both assemblies.

Subclass a C++ abstract class in Java using JNI

I have a C++ library that I have to use in an existing Android implementation. I'm using Android NDK and using the C++ classes via JNI.
However, I am not able to find how to subclass a C++ abstract class in Java using JNI.
Problems I face:
My aim is to provide Java implementation for the virtual methods in C++ by subclassing the abstract C++ class.
I have loaded the native library and I'm trying to declare the native methods.
The C++ methods have keyword 'virtual'. When I declare the native functions in Java after loading the C++ library, 'virtual' is not recognized. What is wrong here?
Any help is appreciated. I'm a newbie to JNI. Thanks in advance.
Let's consider we have a C++ class:
class iVehicle
{
public:
virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
virtual int GetSize() const; // we want to reuse it in Java
};
We want to create a class Bot in Java that extends class iVehicle in the sense that calls to super invoke the C++ code from iVehicle::GetSize() and, from the C++ point of view, we can use the instances of Bot as iVehicle* variables. That's tough since C++ provides no good built-in functionality for reflection.
Here is one possible solution.
To use C++ class in Java we need to generate a Java wrapper, i.e:
class iVehicle
{
public void Run() { Native_Run(); }
public int GetSize() { return Native_GetSize(); }
private native void Native_Run();
private native int Native_GetSize();
// typecasted to pointer in C++
private int NativeObjectHolder;
// create C++ object
native static private int CreateNativeObject();
}
The usage in Java is simple:
class Bot extends iVehicle
{
public int GetSize()
{
if ( condition ) return 0;
// call C++ code
return super.GetSize();
}
}
However, there is a C++ part to this code:
static jfieldID gNativeObjectHolderFieldID;
JNIEXPORT void JNICALL Java_com_test_iVehicle_Run( JNIEnv* env, jobject thiz )
{
int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
iVehicle* Obj = (iVehicle*)Obj;
// todo: add checks here, for NULL and for dynamic casting
Obj->Run();
}
The similar code is for GetSize().
Then creating an instance of Java's Bot you have to call CreateNativeObject() and assign the returned value to the NativeObjectHolder field.
JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject( JNIEnv* env, jobject thiz )
{
iVehicle* Obj = new iVehicle;
return (int)Obj;
}
So, this is the scheme. To make this work you will need to add the destruction code and to parse C++ classes to generate all this glue code.
Added:
In case where iVehicle is actually abstract you will have to generate a non-abstract wrapper that you are able to instantiate:
class iVehicle
{
virtual void Run() = 0;
}
class iVehicle_Wrapper: public iVehicle
{
virtual void Run() { ERROR("Abstract method called"); };
}
And instantiate iVehicle_Wrapper in CreateNativeObject(). Vuala! You have inherited an abstract C++ class in Java.

How to access a class in a namespace which is in different project?

I have three projects under another project of which each contains one namespace. Now among them I need to call a class which is under a namespace in visual studio 2008. Please don't ask me to add the dependencies to the main project so that I can access the namespace and all the classes in that just like local namespace which I can't do due to some restrictions. Tell me something like derived class concept so that I can access that class.
The LanguageTable class which I want to call is as follows:
#define GFX_LANGUAGE_MAX 20
namespace gfx_viewer_win32
{
public ref class LanguageTable
{
public:
static Dictionary<String ^, List<String ^>^> ^ language_string_table;
static array<String ^> ^language_string_id;
LanguageTable(void)
{
}
~LanguageTable(void)
{
}
};
}
The place from where i want to call LanguageTable class is as follows:
#pragma once
using namespace gfx_coder_prj_parser;
namespace Code_generator
{
public ref class CCodeGenerator : CCodeParserMultiLayer
{
CCodeGenerator(void)
{
}
~CCodeGenerator(void)
{
}
/*============I want to call LanguageTable class from here==========*/
};
}
If you don't want to add the assembly of LanguageTable class as a reference, you can reach it by System.Reflection. First load the assembly and create an instance of LanguageTable and now you can call methods,access properties of it by searching for by their names like
Assembly ^ langTableAssembly = Assembly::Load("assembly_name" or binary_data_of_assembly );
object ^ langTable = langTableAssembly->CreateInstance("gfx_viewer_win32::LanguageTable", ...with_other_params);
Type ^ langTableType = langTable->GetType();
MemberInfo ^ langStringID = langTableType.GetMember("language_string_id")[0];
MethodInfo ^ someMethod = langTableType.GetMethod("method_name");
someMethod->Invoke(langTable, ...other_params);
It is not a good approach though. It depends on the names, any change of the names (via refactoring etc.) you have to fix the code above. And I cannot say, this has the best performance.
Lastly, once loaded, the assembly of LanguageTable will not be unloaded during the execution of program. If you wish to unload it, this is another story called "playing with Appdomains".
Here and here are some links to begin with.

Create Managed Object From Unmanaged Class Function

I am trying to create a Managed C++/CLI object in unmanaged code.
Is this possible?
If so, am I doing it right? see code below
#include <vcclr.h>
#include <ManagedClass.h>
// compiled with /clr
namespace X
{
class UnmanagedClass
{
UnmanagedClass(){}
~UnmanagedClass(){}
gcroot<Y::ManagedClass^> m_guiControl;
void functionA()
{
m_guiControl = new gcroot<Y::ManagedClass^>;
}
}
}
// compiled into Managed dll with /clr
// in file ManagedClass.h in a separate project
using namespace System::ComponentModel;
// more usings here ..etc
namespace Y {
public ref class ManagedClass : public System::Windows::Forms::UserControl
{
// implementation here
}
}
When I compile the UnmanagedClass source file, I keep getting a whole lot of errors with the first one being error C2039: 'ComponentModel' : is not a member of 'System'. How come it is not recognising ComponentModel?
I thought this was suppose to be IJW (it just works) ;-)
Here's an example for a wrapper:
class UnmanagedClass
{
gcroot<ManagedClass^> m_managed;
public:
UnmanagedClass()
{
m_managed = gcnew ManagedClass();
}
};
Look here:
C++/CLI - Managed class to C# events
wrapper to c++/cli
Edit:
When you get an error on a using statement, and you know it's supposed to exist, It's usually because that dll isn't referenced.
Go to the projects references, choose add reference.
You can add .Net assemblies in the .Net tab. Find the one you need and add it.

Resources