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());
}
Related
I am using VS2019
Trying to call a thread in DLL. to run two executables simultaneously with detach
following threads worked when I Run a normal c++ program
I get error
Error C3867 'myClass::runexeone': non-standard syntax; use '&' to create a pointer to member myGateway C:\Users\user\Downloads\Demo\myGateway\myplugin.cpp 21
plugin header
#include <windows.h>
#include <iostream>
#include <thread>
#define MYPLUGIN_EXPORT __declspec(dllexport)
extern "C"
{
MYPLUGIN_EXPORT void WINAPI OnStart();
}
pluging.cpp
#include "plugin.h"
using namespace std;
class myClass
{
public:
myClass()
{
}
~myClass()
{
}
void onStart()
{
std::thread(runexeone).detach();
std::thread(runexetwo).detach();
}
void runexeone()
{
int exerunpne = system("cmd /C \"%MY_ROOT%\\bin\\Mytest.exe\" -ORBEndpoint iiop://localhost:12345 -d");
}
void runexetwo()
{
int exeruntwo = system("cmd /C \"%MY_ROOT%\\bin\\Mytest_2.exe\" -ORBEndpoint iiop://localhost:12345 -d");
}
};
myClass& getmyclass()
{
static myClass myclass;
return myclass;
}
MYPLUGIN_EXPORT void WINAPI OnStart()
{
getmyClass().onStart();
}
The problem is that runexeone is an unqualified name of a member function, and std::thread needs something executable. runexeone isn't. VC++ tries to guess from context what you mean, but the suggestion isn't enough. Even if you had written &myClass::runexeone, it still wouldn't have worked, because myClass::runexeone also needs a this pointer. You can fix the latter problem by making it static.
Compiler suggestions work best when there's just one problem.
As MSalters already mentioned, you provided the wrong data type for the functor for std::thread. If you cannot make the method static (which you can actually at least for the current state of your code, but to let this not be unstated here), you can do this
void onStart()
{
std::thread(std::bind(&myClass::runexeone, this)).detach();
}
But be careful about the lifetime/existence of your object/this!
So I've got this interface class that I include, both in the dll and the client project
// InterfaceClass.h
#pragma once
class InterfaceClass
{
public:
virtual void Update() = 0;
};
This is the dll class that calls one of its own methods inside update
// DLLClassThatDoesSomething.cpp
#include "InterfaceClass.h"
#include <iostream>
#include <string>
class __declspec(dllexport) DLLClass : public InterfaceClass
{
public:
void Update()
{
std::cout << this->GetString();
}
std::string& GetString()
{
std::string thestring = "bruhmoment";
return thestring;
}
};
extern "C"
{
__declspec(dllexport) InterfaceClass* CreateInstance()
{
return new DLLClass();
}
}
And this is the "Client" project
// main.cpp
#include "InterfaceClass.h"
#include <Windows.h>
typedef InterfaceClass* (__cdecl *Class) ();
int main()
{
HINSTANCE dll = LoadLibrary(L"DLLClass.dll");
Class klass = (Class)GetProcAddress(dll, "CreateInstance");
InterfaceClass* IKlass = klass();
IKlass->Update();
FreeLibrary(dll);
return 0;
}
The moment I call IKlass->Update() I get an exception for Access Memory Violation because of the DLLClass calling its own method.
I haven't tried anything since I barely know how to load a DLL on runtime and I've used this nifty tutorial
How can I let it call the method and not get thrown an exception? I'm trying to let ppl that will create mods for my game create their own mods with their custom classes for bosses, mobs and etc. in DLLs.
EDIT:
Turns out it was a syntax mistake on my end. Instead of return new DLLClass;, it had to be return new DLLClass();. After fixing it, it works as intended.
You return a reference to a local variable thestring, and by the time you try to access it in
std::cout << this->GetString(), referenced data is already destroyed. In fact, it is destroyed right after the end of enclosing scope of compound statement where the variable was declared.
It may "appear" to work sometimes due to the stack not being overwritten yet, but eventually it will fail miserably like it did in your case. This triggers UB (undefined behavior).
Here is the error I am receiving when running the project that I am using the DLL in:
The odd thing is that this was working at one point. I took a break from this project for a while and now it is not working. Not much has changed besides changing a couple of the parameters.
My setup includes a project in which I build the DLL. This project is then used in a solution with another project that I use to test it. I followed this example: https://msdn.microsoft.com/en-us/library/ms235636.aspx in which I also followed the first time and had it working, now it has stopped.
After realizing it seems to be only one of the functions that is causing the problem I have removed all of the extra code, tried renaming the function, removing everything in it and it is STILL not working.
You can see the function definitions and signatures to see how I am attempting to get this to work below
I have also tried using the "SCOREINTERFACECPP" macro I created on the function instead of the class and I get the same error.
In the project I am testing it in I added the DLL project as a reference and a dependent project, then imported the header file. The other functions I have in the dll (that I have removed from this code for simplicity sake) seem to be working.
Header:
#ifdef SCOREINTERFACECPP_EXPORTS
#define SCOREINTERFACECPP __declspec(dllexport)
#else
#define SCOREINTERFACECPP __declspec(dllimport)
#endif
#include <time.h>
#include <queue>
namespace ScoreInterfaceCPP
{
class SCOREINTERFACECPP ScoreInterface
{
public:
ScoreInterface();
~ScoreInterface();
static void SubmitLogin(const std::string &displayName, const std::string &password);
static void Shutdown();
static SIEvent* GetNextEvent();
static void ClearEvents();
static int GetEventCount();
private:
static std::queue< SIEvent* > mSIEvents;
static bool mGameIsAuthorized;
static std::string mGameName;
static std::string hexedKey;
static std::wstring mAddress;
static void SubmitEventString(std::string eventString);
static int SubmitWithNewThread(void* data);
static void PostMessage(std::string data, std::string iv);
};
}
Source:
#include <sstream>
#include <SDL/SDL_thread.h>
#include <boost/tokenizer.hpp>
#include "ScoreInterfaceCPP.h"
#include "Network.h"
using namespace ScoreInterfaceCPP;
/*
ScoreInterfaceCPP.h
Handles the sending and receiving of events.
*/
ScoreInterface::ScoreInterface()
{
}
ScoreInterface::~ScoreInterface()
{
}
void ScoreInterface::SubmitLogin(const std::string &displayName, const std::string &password)
{
}
void ScoreInterface::SubmitEventString(std::string eventString)
{
}
int ScoreInterface::SubmitWithNewThread(void* data)
{
return 0;
}
SIEvent* ScoreInterface::GetNextEvent()
{
return NULL;
}
int ScoreInterface::GetEventCount()
{
return 0;
}
void ScoreInterface::ClearEvents()
{
}
void ScoreInterface::Shutdown()
{
}
Test file:
#include "ScoreInterfaceCPP.h"
using namespace ScoreInterfaceCPP;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
ScoreInterface si = ScoreInterface();
si.SubmitLogin("noplayer", "nopassword");
return 0;
}
In my experience, usually problems of this type come with two things you should check (assuming the DLL was built successfully):
Check that the DLL being loaded at runtime is the correct version.
Ensure that the function in question is actually exported.
For the first issue, you can use a utility such as Process Explorer and look at the DLL handles that are loaded for your running exectuable. If you are using Visual C++, you can also look at the Output Window listing of the DLL's that are loaded, and ensure that the version you're using is being loaded.
Many times during development, you may have several (either by accident or by design) versions of your DLL lying in a directory that is accessible by Windows (see DLL Search Order), and thus an old or different version of your DLL is being loaded when you run your application.
For the second issue, there is dumpbin.exe, but I find the Dependency Walker a little more friendly to use. These utilities will show you the functions that are exported from the DLL.
If it is discovered that the function was not exported, then you need to rebuild your DLL, ensuring that __declspec(dllexport) has been used on the function or class you're exporting.
I work with an application that appears (just started a few weeks ago, so I am still learning the older apps) to be built in C and my company wants to use that program's ability to make a call to an outside DLL to extend some new functionality. To do this, I started working on my POC, which is the first two files below. The only specification we were given was that the dll has to export the following function:
extern int __stdcall TestMethod_LoadCustomer(const char * name, char * id);
I tried to implement that as follows:
TestDLL.h
#define TestDLL_API __declspec(dllexport)
namespace TestDLL
{
class TestDLL
{
public:
static TestDLL_API int TestMethod_LoadCustomer(const char* name, char* id);
};
}
TestDLL.cpp
// TestDLL.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "TestDLL.h"
#include <string.h>
extern "C" int __declspec(dllexport) __stdcall TestMethod_LoadCustomer(const char* name, char* id)
{
if (strlen(name) <= 8) {
strcpy(id, name); // name contains customer id
} else {
id[0] = 0; // Customer not found
}
return 0;
}
These two files compile fine. The problem comes in when I try to test this dll via a separate little console app shown here:
RunTEST.cpp
// RunTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include "TestDLL.h"
using namespace std;
int _tmain()
{
char* id= "";
TestDLL::TestDLL::TestMethod_LoadCustomer("77777", id);
cout << id;
cin >> id;
return 0;
}
All I am looking for is to be able to pass in a character string into the call TestMethod_LoadCustomer() and have it be added to the id field.
When I actually try to build this solution, I get the following error:
"error LNK2019: unresolved external symbol "public: static int __cdecl TestDLL::TestDLL::TestMethod_LoadCustomer(char const *, char *)" (?TestMethod_LoadCustomer#TestDLL#1#SAHPBDAD#Z) referenced in function _wmain"
I am assuming it has something to do with the way I am trying to reference it in my client app, but I am not sure. I have looked at other LNK2019 errors on StackOverflow, but none of those solutions seemed to work here, of I have incorrectly implemented them. Can any one assist in helping me get rid of this error message?
On the TestDLL.cpp file is missing two things:
1) The namespace TestDLL.
2) the TestDLL:: before the method name.
// TestDLL.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "TestDLL.h"
#include <string.h>
namespace TestDLL {
extern "C" int __declspec(dllexport) __stdcall TestDLL::TestMethod_LoadCustomer(const char* name, char* id)
{
if (strlen(name) <= 8) {
strcpy(id, name); // name contains customer id
} else {
id[0] = 0; // Customer not found
}
return 0;
}
}
While defining the function in TestDLL.cpp you didn't mention that the function is member of the class TestDLL.
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 :-)