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.
Related
I wrote a DLL in C# in VS2012:
namespace COMTest
{
public class MyClass
{
public int Fun()
{
return 3;
}
}
}
And then I set "Make Assembly COM Visible=True" and in the Build page, I set "Register COM for intercrop". Then create a new VB6 project, add a reference to the generated dll file but failed……Later tried tlb file succeeded but without intellisense after saying "a." (No "Fun" tip)
Dim a As MyClass
Set a = New MyClass
MsgBox (a.Fun())
So my questions are:
1) Why must I refer tlb file instead of dll file?
2) Why no intellisense?
Try placing a check mark in:
Tools->Options->Editor->Auto List Members
If that does not help, then to resolve this problem, define a public interface by using methods and properties that you want to expose in the TLB, and then implement the interface in the class. Also, add the ClassInterface (ClassInterfaceType.None) attribute to the class. As you develop the component, you can use this approach to avoid using the ComVisible(False) attribute.
You can have more details here
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.
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.
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#
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.