I am calling back to java from a c++ dll and CallVoidMethod causes an EXCEPTION_ACCESS_VIOLATION. What am I missing - java-native-interface

Environment
C++ DLL created using Visual Studio 2017
Java program running under Intellij using its supplied Java environement
When I run the java application I get the std::cout messages up to the callback message
Then the system halts
When I attach the debugger in Visual Studio I get an access violation at address 0x0...0240
Something about the CallVoidMethod is incorrect but I am unsure what. So far I have been unable to find answers that apply to this simple case online.
Code
JAVA
public class Main {
public native void executeNativeCode();
static {
System.loadLibrary("JNITarget" );
}
// write your code here
public static void main(String[] args) {
new Main().executeNativeCode();
System.out.println("Java Done");
}
public void helloWorld() {
System.out.println("Hello World from Java!");
}
}
C++
// JNITarget.cpp : Defines the exported functions for the DLL application.
//
//#include "stdafx.h"
#include <iostream>
#include <string>
#include "jni.h"
#include "com_poc_Main.h"
#include "JNITarget.h"
JNIEXPORT void JNICALL Java_com_poc_Main_executeNativeCode(JNIEnv * env, jobject thisObj) {
std::cout << "Hello World from C++!" << std::endl;
std::cout << "Get java class object" << std::endl;
jclass thisClass = env->GetObjectClass(thisObj);
std::cout << "Get callback method" << std::endl;
jmethodID callback = env->GetMethodID(thisClass, "helloWorld", "()V");
std::cout << "Call callback method" << std::endl;
env->CallVoidMethod(thisClass, callback);
std::cout << "C++ done" << std::endl;
return;
}```

Ok, for anyone else who runs into this changing the CallVoidMethod arguments to
env->CallVoidMethod(thisObj, callback)
instead of
env->CallVoidMethod(thisClass, callback)
fixes the problem

Related

C++ - Passing object to return value of hooked function

Im quite new to C++ and Im currently learning Function Hooking.
In my case the target applicationĀ“s function I want to hook returns an class looking like this:
EventsForMe.dll:
RandomEventListener GetEventReg() {
return RandomEventListener();
}
class RandomEventListener {
public:
void RegisterToEvent(EventTypeEnum eventType, IListener listener) {
....
}
}
enum EventTypeEnum {
APP_OPENED,
APP_CLOSED
}
Now at the moment im hooking the function that returns the "EventRegister". That works fine...i get notified everytime the class is used (which is 3 times).
My plan is to attach to an event from the injected dll. Problem is the "IListener" type is only existing in my other app. And I think the point of hooking is that you dont have to include the code of the other program.
Im using easyhook for this and this what i got so far:
(I rebuilt the enum cause I found no other way)
App.exe
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <iostream>
#include <windows.h>
#include <shlobj.h>
#include <easyhook.h>
#include <string>
#include <fstream>
enum EventTypeEnum {
APP_OPENED,
APP_CLOSED
}
class MyListener {
static EventTypeEnum GetTypeOfEvent() {
return EventTypeEnum::APP_CLOSED;
}
void OnEventHappening() {
std::cout << "App closing!!!!! And im registered from outside!" << std::endl;
}
}
extern struct RandomEventListener { /* PlaceHolder Structure */
void RegisterToEvent(EventTypeEnum eventType, MyListener listener);
};
void RandomEventListener::RegisterToEvent(EventTypeEnum eventType, MyListener listener)
{}
typedef RandomEventListener(__cdecl* fRandomEventListener)();
fRandomEventListener orig;
extern "C" void __declspec(dllexport) __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo);
void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo)
{
HOOK_TRACE_INFO hHook = { NULL }; // keep track of our hook
HMODULE dll = LoadLibrary(L"EventsForMe.dll");
FARPROC addressConnect = GetProcAddress(dll, "GetEventReg");
if (NULL != addressConnect) {
orig = (fRandomEventListener)GetProcAddress(dll, "connect");
orig.RegisterToEvent(EventTypeEnum::APP_CLOSED, MyListener());
}
// If the threadId in the ACL is set to 0,
// then internally EasyHook uses GetCurrentThreadId()
ULONG ACLEntries[1] = { 0 };
// Disable the hook for the provided threadIds, enable for all others
LhSetExclusiveACL(ACLEntries, 1, &hHook);
RhWakeUpProcess();
}
The call does not break the code so no error appears but if I close my App it should print "App closing!!!!! And im registered from outside!" right after "Closing app..." which is in the App.exe.
So the question I have is: Is it possible to pass an class as listener from the Injector to the Injected App? Cause my expected output is not happening... (I stripped my code a bit for this post)

Using singleton in delayed loaded shared library

I have a static C++ library that defines a singleton class. The static member variable of the singleton is a std::unique_ptr. I also have a shared library that defines a plugin which is delayed-loaded by the main application (using dlopen). Both the main application and the shared library link to the static library and make use of its singleton. All parts are compiled using compiler flags -fPIC and -rdynamic using GCC 7.5.0. The shared library and the executable are not linked at link-time.
At run-time, all components seem to make correct use of the same singleton instance. However, even though the constructor of the singleton class is only called once, its destructor is called twice, resulting in a double delete and therefore a segfault. The destructor seems to be called once for each compilation unit it is used in. If the shared library is linked to the main application at link time, this does not happen.
This issue occurred to me first when trying to use Poco::Logger from the C++ Poco library as the static library.
I looked at the question posed here and tried the example (using GCC 7.5.0) replacing the raw pointer with a std:unique_ptr. This results in the same double delete. The only way I seem to be able to prevent the double delete is to link the main application to the shared library at link-time and remove the direct link of the shared library to the static library. This would ensure only 1 copy of the shared library exists at run time. However, I wonder if that would be a good solution (besides that I don't seem to be able to do that through CMake).
Linking the shared library to the main application does not seem to make sense, since not all plugins will be known at compile time and this would defy the purpose of a plug in.
The following minimal example has been based on the example from bourneli
The static library contains the following files:
/*
* singleton.h
*
* Based on: bourneli
* Adaptation: mojoritty
*/
#ifndef SINGLETON_H_
#define SINGLETON_H_
#include <memory>
class singleton
{
private:
singleton();
static std::unique_ptr<singleton> pInstance;
public:
~singleton();
static singleton& instance();
public:
int num;
};
#endif /* SINGLETON_H_ */
and
/*
* singleton.cpp
*
* Based on: bourneli
* Adaptation: mojoritty
*/
#include "singleton.h"
#include <iostream>
singleton::singleton()
{
std::cout << "Constructed " << this << std::endl;
num = -1;
}
singleton::~singleton()
{
std::cout << "Destroyed" << this << std::endl;
}
static singleton& singleton::instance()
{
if (!pInstance)
{
pInstance.reset(new singleton());
}
return *pInstance;
}
std::unique_ptr<singleton> singleton::pInstance;
The shared library contains the following files:
// plugin.h
#include "singleton.h"
#include <iostream>
extern "C" void hello();
and
// plugin.cpp
#include "plugin.h"
void hello()
{
std::cout << "singleton.num in hello.so : " << singleton::instance().num << std::endl;
++singleton::instance().num;
std::cout << "singleton.num in hello.so after ++ : " << singleton::instance().num << std::endl;
}
Finally, the main application contains the following code:
/* main.cpp
*
* Author: bourneli
* Adaptation: mojoritty
*/
#include <iostream>
#include <dlfcn.h>
#include "singleton.h"
int main() {
using std::cout;
using std::cerr;
using std::endl;
singleton::instance().num = 100; // call singleton
cout << "singleton.num in main : " << singleton::instance().num << endl;// call singleton
// open the library
void* handle = dlopen("./libplugin.so", RTLD_LAZY);
if (!handle) {
cerr << "Cannot open library: " << dlerror() << '\n';
return 1;
}
// load the symbol
typedef void (*hello_t)();
// reset errors
dlerror();
hello_t hello = (hello_t) dlsym(handle, "hello");
const char *dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol 'hello': " << dlerror() << '\n';
dlclose(handle);
return 1;
}
hello(); // call plugin function hello
cout << "singleton.num in main : " << singleton::instance().num << endl;// call singleton
dlclose(handle);
}
Building and running this application results in the follwing terminal output:
created 0x563018c48e70
singleton.num in main : 100
singleton.num in hello.so : 100
singleton.num in hello.so after ++ : 101
singleton.num in main : 101
destroyed 0x563018c48e70
destroyed 0x563018c48e70
free(): double free detected in tcache 2
Aborted (core dumped)

CppUnitTestingFramework with templated TEST_CLASSes

Firstly, there is a question with a similar goal described here: C++ unit test testing, using template test class.
This question is regarding my attempt to solve the same problem.
Using the Microsoft CppUnitTestFramework, we can create unit tests using something like the following:
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace MyUnitTests {
TEST_CLASS(NameOfMyTestClass) {
public:
TEST_METHOD(MyMethod1) {
Assert::IsTrue(false);
}
};
}
I'd like to test a collection of similar tests (without using a For loop to put all of the Asserts in a single TEST_METHOD), so I looked at the TEST_CLASS macro:
#define TEST_CLASS(className) \
ONLY_USED_AT_NAMESPACE_SCOPE class className : public ::Microsoft::VisualStudio::CppUnitTestFramework::TestClass<className>
This can't be used with a template directly - as far as I can see there is no way to specify a className value that would include template parameters with the correct syntax to compile.
As a result, I attempted the following:
namespace MyUnitTests {
ONLY_USED_AT_NAMESPACE_SCOPE
template<MyEnumClass MeasurementType, char ExpectedShift>
class templatedScaleTestClass : public TestClass<templatedScaleTestClass<MeasurementType,ExpectedShift>>
{
public:
TEST_METHOD(Test_ExpectedShift) {
Assert::AreEqual(ExpectedShift, Calculations::getShiftAmount(MeasurementType));
}
};
ONLY_USED_AT_NAMESPACE_SCOPE template class templatedScaleTestClass<MyEnumClass::FIRST,3>;
ONLY_USED_AT_NAMESPACE_SCOPE template class templatedScaleTestClass<MyEnumClass::THIRD,1>;
}
This compiles, and looks to me like it should allow me to define a collection of TEST_METHODs in the template class, then just instantiate the necessary collection of Enums and constant values to set them up (perhaps using some sort of constructor for other parameters in the future, although looking at CppUnitTest.h makes me wonder if that might be another problem...)
However, the class never appears in the test explorer, and trying to right click on the test (in the template code) and clicking "Run Test(s)" produces the following output:
[datetime Informational] Executing test method 'MyUnitTests.templatedScaleTestClass<MeasurementType, ExpectedShift>.Test_ExpectedShift'
[datetime Informational] No tests found to run.
Edit: Not sure how relevant the last part ("No tests found to run") is - doing the same with a normal test (no user-side templates) produces the same output. Clicking away from a specific test runs all tests in the .cpp file. Perhaps I'm using the right-click menu wrongly.
Despite having tried several attempts at getting this to display, and checking the output of a function like the following:
template<typename T>
void debugMethod(TestClass<T> *tc) {
const TestClassInfo* classInfo = tc->__GetTestClassInfo();
std::stringstream msg;
msg << "Tag: " << classInfo->metadata->tag << std::endl;
msg << "helpMethodName: " << classInfo->metadata->helpMethodName << std::endl;
msg << "helpMethodDecoratedName: " << classInfo->metadata->helpMethodDecoratedName << std::endl;
msg << "New method address: " << &(classInfo->pNewMethod) << std::endl;
const MemberMethodInfo* methodInfo = T::__GetTestMethodInfo_Debug();
msg << "methodInfo - Tag: " << methodInfo->metadata->tag << std::endl;
msg << "methodInfo - methodName: " << methodInfo->metadata->methodName << std::endl;
msg << "methodInfo - helpMethodName: " << methodInfo->metadata->helpMethodName << std::endl;
msg << "methodInfo - helpMethodDecoratedName: " << methodInfo->metadata->helpMethodDecoratedName << std::endl;
msg << "methodInfo - lineNo: " << methodInfo->metadata->lineNo << std::endl;
Logger::WriteMessage(msg.str().c_str());
}
... (namespace, test class etc)
TEST_METHOD(Debug) { debugMethod(this); }
and observing similar results in both a standard TEST_CLASS and my templated class, I was unable to get templated classes to display in the Test Explorer.
It is possible to template a class then call the test functions from a non-templated class:
template <MyEnum val>
class myClass : public TestClass<myClass<val>>
{
public:
TEST_METHOD(MyTest) {
Assert::AreEqual(val, MyEnum::exampleValue);
}
}
TEST_CLASS(DummyTests) {
TEST_METHOD(Test_across) {
auto a = myClass<MyEnum::MyEnumValue>();
a.MyTest();
}
}
but this still provides less than ideal feedback in the Test Explorer.
A further alternative (ugly as it is...) is to define a macro function that takes the parameter you want to template on, and then define your entire class inside the macro:
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#define SCALING_TEST(TYPE_TO_TEST, EXPECTED_SHIFT)\
TEST_CLASS(CATNAME(ScalingTest_, TYPE_TO_TEST)) {\
private:\
MyEnum type = MyEnum::TYPE_TO_TEST;\
public:\
TEST_METHOD(HasExpectedShift) {\
Assert::AreEqual((char)EXPECTED_SHIFT, Calculations::getShiftAmount(type));\
}\
}
namespace ScalingTests {
SCALING_TEST(SPEED, 3);
}

Multithreaded C++ code deadlocks when used in Objective-C++ environment (boost, asio and thread)

This is a fairly involved question, and unfortunately may involve compiling and running some code on your machine. Moreover, it's neither pure Objective-C nor it's C++, but rather using C++ from within Objective-C (i believe one might call it Objective-C++).
So, I'm using this library in my code. There's a class called ThreadsafeFace. For simplicity, one should think of it as an asynchronous socket (because that's what it uses underneath, in fact - unix socket). But the code I'm dealing with doesn't even get to the point where socket is being used for sending or receiving data.
Anyway, I have a C++ wrapper class FaceProcessor which looks like this:
FaceProcessor.h:
#include <stdio.h>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
namespace ndn {
class Face;
}
class FaceProcessorImpl;
class FaceProcessor {
public:
FaceProcessor(std::string host);
~FaceProcessor();
void start();
void stop();
bool isProcessing();
// non blocking
void dispatchSynchronized(boost::function<void(boost::shared_ptr<ndn::Face>)> dispatchBlock);
// blocking
void performSynchronized(boost::function<void(boost::shared_ptr<ndn::Face>)> dispatchBlock);
static boost::shared_ptr<FaceProcessor> forLocalhost();
private:
boost::shared_ptr<FaceProcessorImpl> _pimpl;
};
FaceProcessor.cpp:
#include "face-processor.hpp"
#include <boost/function.hpp>
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <ndn-cpp/threadsafe-face.hpp>
using namespace ndn;
using namespace boost;
using namespace boost::asio;
class FaceProcessorImpl : public enable_shared_from_this<FaceProcessorImpl>{
public:
FaceProcessorImpl(std::string host);
~FaceProcessorImpl();
void start();
void stop();
bool isProcessing();
// non blocking
void dispatchSynchronized(boost::function<void(boost::shared_ptr<ndn::Face>)> dispatchBlock);
// blocking
void performSynchronized(boost::function<void(boost::shared_ptr<ndn::Face>)> dispatchBlock);
bool initFace();
void runFace();
private:
std::string host_;
shared_ptr<io_service::work> ioWork_;
io_service io_;
shared_ptr<Face> face_;
thread t_;
bool isRunningFace_;
};
shared_ptr<FaceProcessor>
FaceProcessor::forLocalhost()
{
return make_shared<FaceProcessor>("localhost");
}
FaceProcessor::FaceProcessor(std::string host):
_pimpl(make_shared<FaceProcessorImpl>(host))
{
if (_pimpl->initFace())
_pimpl->runFace();
else
throw std::runtime_error("couldn't initialize face object");
}
FaceProcessor::~FaceProcessor() {
_pimpl->stop();
_pimpl.reset();
}
void FaceProcessor::start() { _pimpl->start(); }
void FaceProcessor::stop() { _pimpl->stop(); }
bool FaceProcessor::isProcessing() { return _pimpl->isProcessing(); }
void FaceProcessor::dispatchSynchronized(function<void (shared_ptr<Face>)> dispatchBlock)
{
return _pimpl->dispatchSynchronized(dispatchBlock);
}
void FaceProcessor::performSynchronized(function<void (shared_ptr<Face>)> dispatchBlock)
{
return _pimpl->performSynchronized(dispatchBlock);
}
//******************************************************************************
FaceProcessorImpl::FaceProcessorImpl(std::string host):host_(host)
{
}
FaceProcessorImpl::~FaceProcessorImpl()
{
stop();
}
void FaceProcessorImpl::start()
{
if (!isRunningFace_)
if (initFace())
runFace();
}
void FaceProcessorImpl::stop()
{
if (isRunningFace_)
{
isRunningFace_ = false;
face_->shutdown();
std::cout << "work reset" << std::endl;
ioWork_.reset();
std::cout << "t join" << std::endl;
t_.join();
std::cout << "stopped" << std::endl;
}
}
bool FaceProcessorImpl::isProcessing()
{
return isRunningFace_;
}
void FaceProcessorImpl::dispatchSynchronized(boost::function<void (boost::shared_ptr<ndn::Face>)> dispatchBlock)
{
if (isRunningFace_)
{
shared_ptr<Face> f = face_;
io_.dispatch([dispatchBlock, f](){
dispatchBlock(f);
});
}
}
void FaceProcessorImpl::performSynchronized(boost::function<void (boost::shared_ptr<ndn::Face>)> dispatchBlock)
{
if (isRunningFace_)
{
if (this_thread::get_id() == t_.get_id())
dispatchBlock(face_);
else
{
mutex m;
unique_lock<mutex> lock(m);
condition_variable isDone;
atomic<bool> doneFlag(false);
shared_ptr<Face> face = face_;
io_.dispatch([dispatchBlock, face, &isDone, &doneFlag](){
dispatchBlock(face);
doneFlag = true;
isDone.notify_one();
});
isDone.wait(lock, [&doneFlag](){ return doneFlag.load(); });
}
}
}
bool FaceProcessorImpl::initFace()
{
try {
if (host_ == "localhost")
face_ = make_shared<ThreadsafeFace>(io_);
else
face_ = make_shared<ThreadsafeFace>(io_, host_.c_str());
}
catch(std::exception &e)
{
// notify about error
return false;
}
return true;
}
void FaceProcessorImpl::runFace()
{
ioWork_ = make_shared<io_service::work>(io_);
isRunningFace_ = false;
shared_ptr<FaceProcessorImpl> self = shared_from_this();
t_ = thread([self](){
self->isRunningFace_ = true;
while (self->isRunningFace_)
{
try {
std::cout << "io run" << std::endl;
self->io_.run();
std::cout << "io run completed" << std::endl;
self->isRunningFace_ = false;
}
catch (std::exception &e) {
// notify about error and try to recover
if (!self->initFace())
self->isRunningFace_ = false;
}
}
});
while (!isRunningFace_) ;
}
As can be seen, the wrapper hides io_service-related complexity, allowing client code to simply create processor, call start and stop at will in order to execute runloop of io_service. Whenever created, FaceProcessor starts running automatically, and stops itself upon destruction. Stopping is performed in, what I believe, a graceful manner - no calls to io_service::stop (as it may prevent scheduled handlers from being executed), but instead io_service::work is reset and thread::join() is invoked in order to wait for full thread completion.
Now, to the question.
The test code itself is fairly simple:
{
boost::shared_ptr<FaceProcessor> f = FaceProcessor::forLocalhost();
sleep(3);
}
which means, that FaceProcessor should finish in graceful manner with no problems. One can try out this code from the latest commit of this branch of the library (please, see instructions on how to build the library, it should be fairly straightforward) and executing bin/test-get-async-threadsafe example.
Now, the problem is, when I test the exact same code in Objective-C, it deadlocks, i.e. for some reason, io_service::run never returns. I use Xcode Unit Tests for testing this code and the test case looks like this:
FaceProcessorTests.mm:
#include "face-processor.hpp"
using namespace boost;
using namespace ndn;
#interface FaceProcessorTests : XCTestCase
#end
#implementation FaceProcessorTests
-(void)testTestProcessor
{
shared_ptr<FaceProcessor> f = FaceProcessor::forLocalhost();
sleep(3);
}
#end
My original FaceProcessor class was written in Objective-C++ (Objective-C with boost::asio::io_service and boost::thread) and I literally spent a week debugging this case, adding debug output to io_service (BOOST_ASIO_ENABLE_HANDLER_TRACKING) and underlying ThreadsafeFace object from the library. When I realized that exact same code works in C++, my final effort was to port FaceProcessor code over to pure C++ and use this class in Objective-C wrapper class. However this didn't help - the code still deadlocks, io_service::run() does not return in Objective-C environment.
I can't figure out why is this happening. Quite possibly, I'm just missing something fundamentally simple. One thing I noticed - when I comment out all code from FaceProcessor related to face_, nothing deadlocks in Objective-C. Since Face uses just socket underneath (in fact, it's boost::asio::local::stream_protocol::socket) - could it be that sockets may work slightly differently in Objective-C runtime?
The environment is:
MacBook Pro (Retina, 15-inch, early 2013)
MacOS Sierra 10.12.3
Xcode Version 8.2.1 (8C1002)
The project is desktop application (not iOS)

C++ Dynamically load arbitrary function from DLL into std::function

How can I load an arbitrary dynamic-link library (dll) function into a std::function object using a single function?
For example I would like to compile two functions into a dll:
// test.dll
int plusFive(int value) {
return value + 5;
}
void printHello() {
std::cout << "Hello!" << std::endl;
}
And load them both at runtime using a single function like this:
// main.cc
#include <functional>
int main() {
std::function<int(int)> func1(loadDllFunc("test.dll", "plusFive"));
std::function<void()> func2(loadDllFunc("test.dll", "printHello"));
}
Use the WinAPI functions provided in windows.h (descriptions taken from MSDN Dev Center).
LoadLibrary - Loads the specified module into the address space of the calling process. Returns a handle to the module.
GetProcAddress - Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL). Returns the address of the exported function or variable.
Use this function to load a specific function and return a std::function object:
// main.cc
#include <iostream>
#include <string>
#include <functional>
#include <windows.h>
template <typename T>
std::function<T> loadDllFunc(const std::string& dllName, const std::string& funcName) {
// Load DLL.
HINSTANCE hGetProcIDDLL = LoadLibrary(dllName.c_str());
// Check if DLL is loaded.
if (hGetProcIDDLL == NULL) {
std::cerr << "Could not load DLL \"" << dllName << "\"" << std::endl;
exit(EXIT_FAILURE);
}
// Locate function in DLL.
FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL, funcName.c_str());
// Check if function was located.
if (!lpfnGetProcessID) {
std::cerr << "Could not locate the function \"" << funcName << "\" in DLL\"" << dllName << "\"" << std::endl;
exit(EXIT_FAILURE);
}
// Create function object from function pointer.
std::function<T> func(reinterpret_cast<__stdcall T*>(lpfnGetProcessID));
return func;
}
The DLL source should be written like this:
// test.cc (test.dll)
#include <iostream>
// Declare function prototypes with "extern C" to prevent name mangling.
// Declare functions using __declspec(dllexport) to signify the intent to export.
extern "C" {
__declspec(dllexport) int __stdcall plusFive(int);
__declspec(dllexport) void __stdcall printHello();
}
int plusFive(int value) {
return value + 5;
}
void printHello() {
std::cout << "Hello!" << std::endl;
}
And then use loadDllFunc like this:
// main.cc
int main() {
auto func1 = loadDllFunc<int(int)>("test.dll", "plusFive");
auto func2 = loadDllFunc<void()>("test.dll", "printHello");
std::cout << "Result of func1: " << func1(1) << std::endl;
func2();
}
Output:
Result of func1: 6
Hello!
As a sidenote the DLL can be compiled using GCC (4.7.2) like this:
g++ -shared -o test.dll test.cc -std=c++11
Edit:
I'm not sure that the cast in loadDllFunc gives the correct type:
std::function<T> func(reinterpret_cast<__stdcall T*>(lpfnGetProcessID));
It seems to cast it to __stdcall int (*)(int) when it should be int (__stdcall *)(int).
Here is another way to implement loadDllFunc using an auxiliary parser class. This solution will correctly cast the function pointer to int (__stdcall *)(int).
template <typename T>
struct TypeParser {};
template <typename Ret, typename... Args>
struct TypeParser<Ret(Args...)> {
static std::function<Ret(Args...)> createFunction(const FARPROC lpfnGetProcessID) {
return std::function<Ret(Args...)>(reinterpret_cast<Ret (__stdcall *)(Args...)>(lpfnGetProcessID));
}
};
template <typename T>
std::function<T> loadDllFunc(const std::string& dllName, const std::string& funcName) {
// Load DLL.
HINSTANCE hGetProcIDDLL = LoadLibrary(dllName.c_str());
// Check if DLL is loaded.
if (hGetProcIDDLL == NULL) {
std::cerr << "Could not load DLL \"" << dllName << "\"" << std::endl;
exit(EXIT_FAILURE);
}
// Locate function in DLL.
FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL, funcName.c_str());
// Check if function was located.
if (!lpfnGetProcessID) {
std::cerr << "Could not locate the function \"" << funcName << "\" in DLL\"" << dllName << "\"" << std::endl;
exit(EXIT_FAILURE);
}
// Create function object from function pointer.
return TypeParser<T>::createFunction(lpfnGetProcessID);
}