How should defined class where are only global variables?
I did something like that:
public ref class Klient
{
public:
Klient(){}
// zmienne
static array<DWORD,2>^ klienty = gcnew array<DWORD,2>(40,2);
static int i = 0;
static DWORD pid;
static HANDLE handle;
static String^ nick;
//funkcje
};
But if i include it more than 1 time it won't compile and showing redefinition of class error.
Did you guard your header? In Visual Studio, you should place this directive at the top of all header files:
#pragma once
This is equivalent to the classic C++ header guard:
#ifndef HEADER_SYMBOL_X
#define HEADER_SYMBOL_X
// class declarations go here
#endif // HEADER_SYMBOL_X
If you don't guard your header, C++/CLI will indeed try to redefine your class on each include.
You'll have to be a little more clear, and paste the error you get. Also if you have a "ref" class the compiler generates a default constructor for you, so you don't need to write one.
This code worked for me, I was able to fetch the static int value into my WPF application:
#pragma once
#include "windows.h"
using namespace System;
namespace cppcli
{
public ref class Klient
{
public:
static array<DWORD,2>^ klienty = gcnew array<DWORD,2>(40,2);
static int i = 22;
static DWORD pid;
static HANDLE handle;
static String^ nick;
};
}
Update:
Noticed your comment, yes you need #pragma once in there. I assumed it was there since it's generated automatically by Visual Studio, well good to know that it works :-)
Related
I have a confusing issue using a static member variable as a default parameter. Since the same language construct works in a different place, it might be related to project (DLL) inter-dependencies. So please accept my apologies if my example is too complex, but I should draw the whole picture since I do not have any idea what is wrong.
I have a base class (representing kind of an error code)
ErrorBase.h
class ErrorBase
{
public:
typedef unsigned long ErrorCode;
/// here go the error codes. For reasons I do not want to explain, I cannot use an enumeration here.
static const ErrorCode ERROR_UNINITIALIZED;
static const ErrorCode ERROR_OK;
///...and so on
ErrorBase(ErrorCode theCode = ERROR_UNINITIALIZED);
};
...and in ErrorBase.cpp, I am assigning values to the codes...
const ErrorBase::ErrorCode ErrorBase::ERROR_UNINITIALIZED = 0xffffffff;
const ErrorBase::ErrorCode ErrorBase::ERROR_OK = 0x0;
//.. and so on...
ErrorBase is exported from a DLL which provides some general purpose classes to our project
Now I am deriving another error class for more specific errors which has additional attributes specific for the particular type of error. The class SpecificError is part of a different DLL which links to the general purpose DLL containing ErrorBase. I have not included the dllimport/dllexport shebang, but we are using this all over the place and it works in all cases. If you have doubts, I can edit my code example.
SpecificError.h
class SpecificError : public ErrorBase
{
public:
static const ErrorCode SPECIFIC_ERROR_UNINITIALIZED;
static const ErrorCode SPECIFIC_ERROR_SOMETHING_WENT_WRONG;
SpecificError(ErrorCode theCode = SPECIFIC_ERROR_UNINITIALIZED);
};
... and in the SpecificError.cpp I am defining these values:
const SpecificError::ErrorCode SpecificError::SPECIFIC_ERROR_UNINITIALIZED = ErrorBase::ERROR_UNINITIALIZED;
Like ErrorBase, SpecificError is exported from the DLL handling specific functionality. Note that both error classes declare a constructor using the "UNINITIALIZED" value as a default for the error code.
Now I have a program being dependent on both DLLs, thus linking to both of them through the corresponding import libraries. This program includes ErrorBase.h and SpecificError.h. It does not seem to have any problems with ErrorCode.h, but about SpecificError.h I am receiving an
LNK2001 unresolved external symbol SpecificError::ErrorCode SpecificError::SPECIFIC_ERROR_UNINITIALIZED referenced in main.obj.
(remark: main.cpp does not explicitly use SpecificError, it just includes the header file).
I was able to work-around the problem by removing the default parameter from the SpecificError constructor and declaring a default constructor which in its implementation calls the inherited constructor of ErrorBase passing SPECIFIC_ERROR_UNINITIALIZED to it. This leads me to the assumption that the symbol SPECIFIC_ERROR_UNINITIALIZED is properly declared and defined but cannot be used as a parameter default. However, this seems to apply to SpecificError only, everything seems fine in ErrorBase.
Toolset: I am using Visual C++ 2017 as a compiler.
I recreated the linked error. Make the following changes to your files and it should work just fine based on the code snippets that you showed above:
SpecificError.cpp
// I sent theCode to the Base class
SpecificError::SpecificError(ErrorCode theCode) : ErrorBase(theCode)
{
// ...
}
In ErrorBase.cpp I just added the constructor but you probably already have this:
ErrorBase::ErrorBase(ErrorCode theCode)
{
// ...
}
After I did this, I had to also move the initializations of the static consts to the .h from the .cpp files. Then I tested the code by doing:
SpecificError e; // theCode ends up being 0xffffffff
SpecificError e1(20); // theCode ends up being 20
I hope that this helps you.
Here is what my ErrorBase.cpp looks like:
#pragma once
#include"ErrorBase.h"
#include<iostream>
ErrorBase::ErrorBase(ErrorCode theCode) {
std::cout << theCode << std::endl;
}
ErrorBase.h:
#pragma once
class ErrorBase
{
public:
typedef unsigned long ErrorCode;
static const ErrorCode ERROR_UNINITIALIZED = 0xffffffff;
static const ErrorCode ERROR_OK = 0x0;
ErrorBase(const ErrorCode = ERROR_UNINITIALIZED);
};
SpecificError.cpp:
#pragma once
#include"SpecificError.h"
SpecificError::SpecificError(ErrorCode theCode) : ErrorBase(theCode)
{
}
SpecificError.h:
#pragma once
#include "ErrorBase.h"
class SpecificError : public ErrorBase
{
public:
static const ErrorCode SPECIFIC_ERROR_UNINITIALIZED = ErrorBase::ERROR_UNINITIALIZED;
static const ErrorCode SPECIFIC_ERROR_SOMETHING_WENT_WRONG = -42;
SpecificError(ErrorCode theCode = SPECIFIC_ERROR_UNINITIALIZED);
};
I tried this and it is working, the class name was missing in ErrorBase.cpp
const ErrorBase::ErrorCode ErrorBase::ERROR_UNINITIALIZED = 0xffffffff;
const ErrorBase::ErrorCode ErrorBase::ERROR_OK = 0x0;
If still not working then let me know.
You doing it wrong. The linker error means that it doesn't know where to get your constant value. You should use dynamic linkage with a first DLL. Let me show
Example of C++ class export:
C++ How to export a static class member from a dll?
And your code should be changed:
ErrorBase.h
#ifndef MAIN_DLL
#define MAIN_DLL 1 // or you can add MAIN_DLL definition to the your first project Macroses
#endif
#if MAIN_DLL
#define ERROR_API __declspec(dllexport) // export things to other modules
#else
#define ERROR_API __declspec(dllimport) // import things from the external DLL
#endif
class ERROR_API ErrorBase
{
public:
typedef unsigned long ErrorCode;
/// here go the error codes. For reasons I do not want to explain, I cannot use an enumeration here.
static const ErrorCode ERROR_UNINITIALIZED;
static const ErrorCode ERROR_OK;
///...and so on
ErrorBase(ErrorCode theCode = ERROR_UNINITIALIZED);
};
SpecificError.h
#pragma once
#define MAIN_DLL 0
#include "../Dll_stack_ovfl1/ErrorBase.h" // change it to your path
class SpecificError : public ErrorBase
{
public:
static const ErrorCode SPECIFIC_ERROR_UNINITIALIZED;
static const ErrorCode SPECIFIC_ERROR_SOMETHING_WENT_WRONG;
SpecificError(ErrorCode theCode = SPECIFIC_ERROR_UNINITIALIZED);
};
And the final step, configure the second DLL project to link it with exports of the first one:
Configuration Properties/Linker/Input/Additional dependencies
Add something like "$(SolutionDir)$(Configuration)\ErrorBase.lib"
Once again its just example, I don't know the real path of "lib" file and your project name for ErrorBase DLL - change it to your specific.
I have problems casting a class to LPVOID and than recasting it to interface class. Here is the simplified code:
public interface class IEventRaiser
{
void fireAppDisconnect()
// some other methods
}
interface class ISpecificEventRaiser : IEventRaiser
{
// some specific methods
}
public ref class ManagedItem
{
ManagedItem()
{
eventRaiser = gcnew EventRaiser();
LPVOID lP = reinterpret_cast<LPVOID>(GCHandle::ToIntPtr(GCHandle::Alloc(eventRaiser)).ToPointer();
item = new UnmanagedItem(lP);
}
// some implementation
ref class EventRaiser : public ISpecificEventRaiser
{
virtual void fireAppDisconnect();
// other methods
};
EventRaiser^ eventRaiser;
UnmanagedItem* item;
};
public class UnmanagedItem
{
UnmanagedItem(LPVOID eventRaiser)
{
IEventRaiser^ r;
IntPtr pointer(eventRaiser);
handle = GCHandle::FromIntPtr(pointer);
r = safe_cast<IEventRaiser^>(handle.Target); // InvalidCastException : Unable to cast object of type 'EventRaiser' to type 'IEventRaiser'.
}
};
There should be no problem with casting to EventRaiser^ to IEventRaiser^, because i tried it before. Before trying to LPVOID conversations, it was working fine. But when i cast it into LPVOID and recast it to IEventRaiser, it throws InvalidCastException. How can i do the castings via LPVOID properly?
Reason to have a LPVOID pointer to my unmanaged class was to get rid of duplicate header imports. So, although i pay attention to included header files, IEventRaiser's header file was imported to inhereted project in some way. So, as Hans Passant indicated on comments, it causes a cast problem because of different assembly names. What i did to solve the problem is adding #ifdef statements to base project's IEventRaiser header file includes. Like the following:
#ifdef BASE_DLL
#include "IEventRaiser.h"
#endif
Then, i added to "BASE_DLL" to preprocessor definitions. It guarantees that the event raiser header will be included once. The other alternative was using forward declarations for not to add "IEventRaiser.h" header file to unmanaged file header. It's also tried and working.
I want to use some code that executes a http-post, and because I'm not too familiar with c++ and what libraries you can use, and I am probably too dumb to get libcurl and curlpp to work, I found a link explaining how to use the .net version.
Alright so I created a class. Header File:
public ref class Element
{
public:
Element();
virtual ~Element();
void ExecuteCommand();
};
Class file:
#include "Element.h"
Element::Element()
{
}
Element::~Element()
{
Console::WriteLine("deletion");
}
void Element::ExecuteCommand(){
HttpWebRequest^ request = dynamic_cast<HttpWebRequest^>(WebRequest::Create("http://www.google.com"));
request->MaximumAutomaticRedirections = 4;
request->MaximumResponseHeadersLength = 4;
request->Credentials = gcnew NetworkCredential("username", "password", "domain");
HttpWebResponse^ response = dynamic_cast<HttpWebResponse^>(request->GetResponse());
Console::WriteLine("Content length is {0}", response->ContentLength);
Console::WriteLine("Content type is {0}", response->ContentType);
// Get the stream associated with the response.
Stream^ receiveStream = response->GetResponseStream();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader^ readStream = gcnew StreamReader(receiveStream, Encoding::UTF8);
Console::WriteLine("Response stream received.");
Console::WriteLine(readStream->ReadToEnd());
response->Close();
readStream->Close();
}
If I set the configuration type of this project to Application (exe), and create a new .cpp file where I create an Instance of this Element it works fine.
But my question is: Is it possible to create a .dll/.lib Library from this project and use it in a C++ project without CLI? (I don't want to use ^ for pointers :( )
Even if it's not possible, I have another problem.
When I link the library in a C++/CLI project. I get
unresolved token (06000001) Element::.ctor
unresolved token (06000002) Element::~Element
unresolved token (06000003) Element::ExecuteCommand
3 unresolved externals
the code for main.cpp in the second project is just the following:
#include <Element.h>
int main(){
return 0;
}
Thank you
As Hans Passant already stated: you must compile your C++/CLI code as Dynamic Library in order to be able to consume it from an unmanaged application. CLI/Managed code cannot run from/cannot reside in static libraries.
If you change the C++/CLI library target from Static library to Dynamic library you'll be able to compile successfully your unmanaged C++ application.
One thought from my side:
I think you'll be better if you use mixed mode C++/CLI DLLs to consume the managed functionality - you'll be able to free your consumer application completely from referencing the CLR.
The Header of such mixed mode Wrapper for your Element class would look like this:
#pragma once
#pragma unmanaged
#if defined(LIB_EXPORT)
#define DECLSPEC_CLASS __declspec(dllexport)
#else
#define DECLSPEC_CLASS __declspec(dllimport)
#endif
class ElementWrapperPrivate;
class __declspec(dllexport) ElementWrapper
{
private:
ElementWrapperPrivate* helper;
public:
ElementWrapper();
~ElementWrapper();
public:
void ExecuteCommand();
};
And the implementation would look like this:
#include "ElementWrapper.h"
#pragma managed
#include "Element.h"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
class ElementWrapperPrivate
{
public:
msclr::auto_gcroot<Element^> elementInst; // For Managed-to-Unmanaged marshalling
};
ElementWrapper::ElementWrapper()
{
helper = new ElementWrapperPrivate();
helper->elementInst = gcnew Element();
}
ElementWrapper::~ElementWrapper()
{
delete helper;
}
void ElementWrapper::ExecuteCommand()
{
helper->elementInst->ExecuteCommand();
}
Then just compile your Element.cpp + ElementWrapper.cpp to a DLL and use the ElementWrapper.h in your unmanaged applications.
So as the title states, I am looking to pass an object that is defined in an unmanaged C++ project into a managed C++/CLI project (both projects are in the same solution) while still being able to access the same methods as in the unmanaged C++ project.
This object is a class which imports functions from a separate unmanaged C++ dll (not in the same project or solution) through the means of using typedef's as shown below (excerpt of header):
#pragma unmanaged
typedef BOOL (WINAPI *someBoolFunc) (DWORD Name, DWORD Flags, TCHAR* Text);
class INeedThisClass
{
public:
INeedThisClass();
~INeedThisClass();
someBoolFunc BoolFunc;
};
extern INeedThisClass ReallyNeedThisClass;
I would really like to be able to access the externed object ReallyNeedThisClass from within my managed code by just only passing the object. By having this object I wish to access it's methods through ReallyNeedThisClass->BoolFunc. What is the best way of accessing this object from my managed code?
EDIT: I've been thinking maybe there is a way of using a property to "Get" the object from the unmanaged code and then "Set" the same object in the managed code. Could this be a proper angle to approach this issue from? I've cleaned up the question a bit to get rid of useless details.
UPDATE: I've made progress on this using a wrapper for the unmanaged C++ code, but of course there are still problems. Using the above class as an example here, I will show you what I have managed to do up until now.
Project 1: Unmanaged C++ class (example above)
Project 2: Managed C++/CLR wrapper class (example below)
Wrapper.h:
#pragma once
#include "INeedThisClass.h" //Unmanaged class INeedThisClass
using namespace System;
using namespace System::Runtime::InteropServices;
namespace INeedThisClassWrapper
{
public ref class INTC
{
public:
INTC(void);
virtual ~INTC(void);
delegate bool BoolFunc(UInt32 Name, UInt32 Flags, String^ Text);
private:
INeedThisClass *ReallyNeedThisClass;
};
}
Wrapper.cpp:
#include "Stdafx.h"
#include "Wrapper.h"
using namespace INeedThisClassWrapper
#include <msclr/marshal.h>
using namespace msclr::interop;
INTC::INTC(void)
{
ReallyNeedThisClass = new INeedThisClass();
}
INTC::~INTC(void)
{
if (ReallyNeedThisClass)
{
delete ReallyNeedThisClass;
ReallyNeedThisClass = NULL;
}
}
bool INTC::BoolFunc(UInt32 Name, UInt32 Flags, String^ Text)
{
return ReallyNeedThisClass->BoolFunc;
}
Now I am receiving errors from the compiler stating:
error C2065: 'WINAPI': undeclared identifier
error C2065: 'someBoolFunc': undeclared identifier
error C4430: missing type specifier - int assumed. Note C++ does not support default-int
Any ideas?
First, you have to export INeedThisClass from unmanaged dll and import from managed one.
//unmanaged header
#if UNMANAGED_COMPILE_DEFINITION
#define EXPORT_OR_IMPORT __declspec(dllexport)
#else
#define EXPORT_OR_IMPORT __declspec(dllimport)
#endif
class EXPORT_OR_IMPORT INeedThisClass
{
public:
INeedThisClass();
~INeedThisClass();
someBoolFunc BoolFunc;
};
Also unmanaged dll must be compiled with UNMANAGED_COMPILE_DEFINITION preprocessor definiton.
Second, remove extern INeedThisClass ReallyNeedThisClass; you don't need it. Because ReallyNeedThisClass is a member of wrapper class already.
Third, you need to marshal System::String^ to TCHAR* in order to call BoolFunc
Forth, I do not remember but if you include "Windows.h" or "Winnt.h", the error about WINAPI will be gone.
I have a new problem with my C++ DLL... I have tried exporting the entire class instead of only one method. But the program doesn't want to compile now because of that the global scope has no GetUrl
Here is my "UrlConnector.h":
#define ConnectMe __declspec( dllexport )
namespace ConnectHttps
{
class ConnectMe
{
void GetUrl(char *url, unsigned int bufferLength);
};
}
and here is the part of my UrlConnector.cpp that isn't compiling:
#include "UrlConnector.h"
#include "MyConnectionClass.h"
#include
using namespace std;
namespace ConnectHttps
{
void ConnectMe::GetUrl(char* url, unsigned bufferLength)
{
MyConnectionClass initSec;
string response = initSec.GetResult();
strncpy_s(url, bufferLength, response.c_str(), response.length());
}
}
Now, I would like to be able to create an DLL from this, and I would like to make a test program to call the class and the method GetUrl from a dll. I'm using Visual Studio 2010 with Visual C++ DLL.
I've also managed to read this from the MSDN and this tutorial as well, but I just can't seem to get it to work!
I would really appreciate any help!
Unless I'm mistaken, you don't seem to be giving your class a name.
You made ConnectMe not a class name but a macro to export your class, but your class should have a name
Maybe try
#define EXPORT_IT __declspec( dllexport )
namespace ConnectHttps
{
class EXPORT_IT ConnectMe
{
void GetUrl(char *url, unsigned int bufferLength);
};
}
Also I'm not 100% sure of this because I don't have access to a compiler at the moment, but typing:
namespace ConnectHttps {
...
}
In your .cpp file isn't correct. Instead you should have:
void ConnectHttps::ConnectMe::GetUrl(char* url, unsigned bufferLength)
{
MyConnectionClass initSec;
string response = initSec.GetResult();
strncpy_s(url, bufferLength, response.c_str(), response.length());
}