LNK2020 when making a variable static - c++-cli

I use C++/CLI to link between a .NET application and a dynamically loaded C dll.
So far all access to the DLL is instance based.
The class
namespace NxCore {
public class NativeConnector {
has variable for various references to methods:
HMODULE hLib;
NxCoreProcessTape pfNxProcessTape;
NxCorePriceToDouble pfNxPriceToDouble;
NxCoreGetDefinedString pfNxCoreGetDefinedString;
NxCoreGetSymbolAtom32 pfNxGetSymbolAtom32;
NxCoreStateGetMMQuotes pfNxStateGetMmQuotes;
I load those in a connect method:
hLib = ::LoadLibrary("NxCoreAPI.dll");
then
pfNxProcessTape = (NxCoreProcessTape)::GetProcAddress(hLib, cszNxCoreProcessTape);
pfNxPriceToDouble = (NxCorePriceToDouble)::GetProcAddress(hLib, cszNxCorePriceToDouble);
pfNxCoreGetDefinedString = (NxCoreGetDefinedString)::GetProcAddress(hLib, cszNxCoreGetDefinedString);
etc.
Now I need to move that to multi instances, so I want to load on first connect, unload on last disconnect. This means the variables must go static.
In C# I would just make them static. I try one:
static HMODULE hLib;
and linking fails:
4>NativeConnector.obj : error LNK2020: unresolved token (0A00006D) "private: static struct HINSTANCE__ * NxCore::NativeConnector::hLib" (?hLib#NativeConnector#NxCore#Connectivity#Tradex##0PAUHINSTANCE__##A)
Anyone an idea how to fix it? The header file is used on the .cpp file, so - it should not have different definitions.
Anyone can tell he how to fix that issue? As i said - I want to move the variables to be static and then use "usage counting" myself to make sure that I release on last disconnect.

From the code shown I'm not exactly clear on whether the problem occurs in a ref class (.NET class) or a native C++ class.
Here is my advice assuming a native type: You need to define the declared member
header
struct X
{
static int s_data;
};
cpp source:
#include "X.h"
int X::s_data /* = 42 */;
For ref types I'd actually expect the same semantics for static as with C#

Related

C++/CLI cannot access native member from different assembly

I have a C++/CLI dll where I have the source code but I cannot modify it and I have my own dll where I want to access a member variable:
Assembly 1 (cannot be modified):
public ref class A
{
public:
int m_iInteger;
SomeClass* m_pPointer;
};
Assembly 2 (own):
A^ a;
int i = a->m_iInteger; // no problem
SomeClass* x = a->m_pPointer; // C2248
The Problem is that the compiler shows an error:
error C2248: 'A::m_pPointer' : cannot access private member declared in class 'A'
The "Object Browser" shows:
public SomeClass* m_pPointer Member of A
Is there any way to access an native public member from a different assembly?
I'm using Visual Studio 2012
Edit:
class "SomeClass" is defined in a native dll (which I cannot modify too)
Edit 2:
I have found a Solution. Its not very nice but it works:
System::Reflection::Pointer^ ptr = (System::Reflection::Pointer^)typeof(A)->GetField("m_pPointer")->GetValue(a);
SomeClass* result = static_cast<SomeClass*>(System::Reflection::Pointer::Unbox(ptr));
All native types are private by default (in terms of managed accessibility outside the assembly). So, even though it is listed as public, since the type SomeClass is private, it makes it inaccessible. You can change this by prefixing the the SomeClass definition with public (if you can modify the SomeClass source code). Or, if you can't modify the SomeClass source code, but you can modify code within that dll, you can use the pragma:
#pragma make_public(SomeClass)
That said, based on your description it sounds like you cannot modify Assembly1 at all, in which case you are out of luck.

calling a class constructor present in a dll managed C++

I've a class created in a DLL (which uses /clr runtime, ManagedC++) and a constructor defined in that class. Code as follows:
//Following is defined in something.h//
namespace ABC
{
public ref Class XYZ
{
public: int a;
public: XYZ();
};
//In something.cpp, I've the below code to define the constructor of the class created//
#include something.h
namespace ABC
{
XYZ::XYZ()
{
a = 100;
}
}
Above project is built into a DLL
In another project, I try to use the Class XYZ as follows:
#include something.h
using namespace ABC;
//inside main, I've following code
{
ABC::XYZ^ prq = gcnew ABC:XYZ();
prq->a=200;
......
...
}
In this, I get the an error saying -
unresolved token (06000001) ABC.XYZ::.ctor
Could you please help what's the problem here?
The problem is that the linker can't find the definition of the constructor. It is located in another DLL. In a managed project, you solve that by adding a reference to the assembly. Right-click your project, Properties, Common Properties, Framework and References. Click the Add New Reference button. Use the Project tab if the project is located in the same solution. The Browse tab otherwise.
Also note that you now no longer need the .h file anymore. Declarations are imported from the metadata in the assembly.

Visual C++ 2010: ``unresolved token" LNK2020

I have a VC++ 2010 solution containing two projects: ProjectX and ProjectXTests. In the current configuration, ProjectX builds as a static library and ProjectXTests as a DLL intended to test various methods in ProjectX. Now, in ProjectX I have a class User with a method getUserName(), as follows:
// User.h
public ref class User
{
public:
User(String^ userName);
String^ getUserName();
private:
String^ userName;
};
The constructor and method are implemented in User.cpp. In ProjectXTests, I have a class UserTests, which tests, among other things, the getUserName() method, in a, say, getUserNameTest() method. It is declared in UserTests.h and implemented as follows in UserTests.cpp:
// UserTests.cpp
#include "UserTests.h"
#include "User.h"
void UserTests::getUserNameTest()
{
User^ testUser = gcnew User("name");
Assert::AreEqual("name", testUser->getUserName());
}
In the project properties (Common Properties -> Framework and References) of ProjectXTests, I have added a reference to ProjectX. In VC++ Directories, I have added the appropriate directories for header files and library files. When building the solution, the header file "User.h" is found. However, I get a link error
error LNK2020: unresolved token (06000005) User::getUserName
The same thing happens for all other methods being tested. I just can't figure out why this happens. So far, the only thing I've found to work, is to include the file "User.cpp" instead of "User.h" in "UserTests.cpp", but this seems like cheating. Does anybody know what I might be missing?
Somehow you have to include the code from ProjectX in ProjectXTests. This is not done by literally using the #include directive, instead the simplest is to add the source files from ProjectX to the ProjectXTests project workspace. If ProjectX is made as a static of dynamic library, then link with that instead.

C++ Class read as variable, default-type int? Say what?

So, I have two classes...Very basic in structure. I try to import one into the other, and declare a new object of that class type...however, it seems to read the class name as the name of a variable?!
The header class provided below will not read the "ApplicationManager" class properly.
Code:
####ifndef _GAME_H_
####define _GAME_H_
####include "application.h"
####include "applicationmanager.h"
class Game : public Application
{
public:
Game();
~Game();
void LoadContent() override;
void UnloadContent() override;
void Draw() override;
private:
//int ApplicationManager; //WHY DOES THIS COMPILE??!
ApplicationManager management; //This DOES NOT WORK?
};
####endif
Here is the header for the "ApplicationManager" class.
Code:
####ifndef _APPMANAGER_H_
####define _APPMANAGER_H_
####include "game.h"
####include "application.h"
class ApplicationManager
{
public:
ApplicationManager(void);
~ApplicationManager(void);
private:
};
####endif
The error that occurs, tells me that I need a ";" before "management", and that "ApplicationManager" is missing a type specifier, so it is assumed to be default-type int.
...any ideas why it won't compile properly? Can someone else try this and report the results? I copied the code, and pasted it in a different solution, to see if something became corrupted....it still didn't work.
You have a cyclic reference. When game.h is included from applicationmanager.h, the ApplicationManager class has not yet been read by the compiler.
To fix, remove the line
#include "game.h"
from applicationmanager.h.
Why do you have circular dependency between Game.h and AppicationManager.h?
Aside from that, I'd say check your header guard (#ifdef _*_H) in Application.h. A fairly often occurence in C++, when copy/pasting code or copying files, is to forget to change the header guard define name for a new class, so you end up with two different headers guarded by the same define. In which case, if both are included into some other file, only the first will actually be expanded into anything useful.
THe error message is some what misleading. It basically says "For some reason (probably an error in the referenced type) I cannot recognize the type you're using (in you case ApplicationManager)".
If you need ApplicationManager to know about Game make a pure virtual base class (interface in other terms) and have Game inherit from that (with out extending the interface) and have ApplicationManager include the base class header file

C++ CLI error C3767: candidate function(s) not accessible

I'm new to C++ CLI coming from unmanaged C++ world.
I'm getting this error:
candidate function(s) not accessible
when I pass a std::string as part of the method argument.
Here's the exact code:
Lib Project (compiled as .dll project)
//Lib.h
#pragma once
public ref class Lib
{
public:
Lib(void);
public:
void Extract( std::string& data_ );
};
//Lib.cpp
#include "Lib.h"
Lib::Lib(void)
{
}
void Lib::Extract( std::string& data_ )
{
data_.empty();
}
LibTest Project (compiled as application.exe)
// LibTest.h
#pragma once
ref class LibTest
{
public:
LibTest(void);
};
// LibTest.cpp
#include "LibTest.h"
LibTest::LibTest(void)
{
Lib^ lib = gcnew Lib;
lib->Extract( std::string("test") );
}
int main()
{
return 0;
}
Compiler Error:
1>------ Build started: Project: LibTest, Configuration: Debug Win32 ------
1>Compiling...
1>LibTest.cpp
1>.\LibTest.cpp(7) : error C3767: 'Lib::Extract': candidate function(s) not accessible
The problem is that std::string will compile as a internal (non public) type. This is actually a change in VS 2005+:
http://msdn.microsoft.com/en-us/library/ms177253(VS.80).aspx:
Native types are private by default outside the assembly
Native types now will not be visible outside the assembly by default. For more information on type visibility outside the assembly, see Type Visibility. This change was primarily driven by the needs of developers using other, case-insensitive languages, when referencing metadata authored in Visual C++.
You can confirm this using Ildasm or reflector, you will see that your extract method is compiled as:
public unsafe void Extract(basic_string<char,std::char_traits<char>,std::allocator<char> >* modopt(IsImplicitlyDereferenced) data_)
with basic_string being compiled as:
[StructLayout(LayoutKind.Sequential, Size=0x20), NativeCppClass, MiscellaneousBits(0x40), DebugInfoInPDB, UnsafeValueType]
internal struct basic_string<char,std::char_traits<char>,std::allocator<char> >
Note the internal.
Unfortunately you are then unable to call a such a method from a different assembly.
There is a workaround available in some cases: You can force the native type to be compiled as public using the make_public pragma.
e.g. if you have a method Extract2 such as:
void Extract2( std::exception& data_ );
you can force std::exception to be compiled as public by including this pragma statement beforehand:
#pragma make_public(std::exception)
this method is now callable across assemblies.
Unfortunately make_public does not work for templated types (std::string just being a typedef for basic_string<>)
I don't think there is anything you can do to make it work. I recommend using the managed type System::String^ instead in all your public API. This also ensures that your library is easily callable from other CLR languages such as c#
if you simply must access the internal methods another work around would be making the projects as Friend Assemblies like that:
//Lib Project
#pragma once
//define LibTest as friend assembly which will allow access to internal members
using namespace System;
using namespace System::Runtime::CompilerServices;
[assembly:InternalsVisibleTo("LibTest")];
public ref class Lib
{
public:
Lib(void);
public:
void Extract( std::string& data_ );
};
//LibTest Project
#pragma once
#using <Lib.dll> as_friend
ref class LibTest
{
public:
LibTest(void);
};
In addition to the solutions described above, one can subclass the templated type to obtain a non-templated type, and include its definition in both projects, thus overcoming some of the problems mentioned above.