i tried the code shown below to call a c# dll function (COM) but when i do that i get the errors below "Invalid use of namespace 'MaxElementFn'"
My guess is that maybe i am calling the c# dll function incorrectly in c++ builder. any suggestion will be greatly appreciated. thank you in advance.
#include <Windows.h>
#include <cstdio>
using MaxElementFn = int(__stdcall *) (int a, int b);
int main()
{
HMODULE mod = LoadLibraryA("ExportedCodeSolution.dll");
MaxElementFn maxElement = reinterpret_cast<MaxElementFn>(GetProcAddress(mod, "maxElement"));
std::printf("max: %d\n", maxElement(1, 2));
}
[BCC32 Error] Unit1.cpp(145): E2070 Invalid use of namespace 'MaxElementFn'
[BCC32 Error] Unit1.cpp(151): E2451 Undefined symbol 'MaxElementFn'
these are the errors i am getting
// helper template
template<typename T>
bool GetFuncPointer(HMODULE module, const char* name, T& ptr)
{
ptr = (T)GetProcAddress(module, name);
if(!ptr) std::printf("function not found in dll: %s\n", name);
return ptr != nullptr;
}
// declare func pointer
int (__stdcall * maxElement) (int, int) = nullptr;
int main()
{
HMODULE mod = LoadLibraryA("ExportedCodeSolution.dll");
// make sure we actually have the function before calling
if(GetFuncPointer(mod, "maxElement", maxElement))
{
std::printf("max: %d\n", maxElement(1, 2));
}
return 0;
}
Related
I have a working example in single file with its spapidllm64.h but wanna split into separate files for easier coding. I have tried to reduce it into a minimal version as follows:
// spapidll.h
#define SPDLLCALL __stdcall
typedef void (SPDLLCALL *LoginReplyAddr)(char *user_id, long ret_code, char *ret_msg);
typedef void (SPDLLCALL *p_SPAPI_RegisterLoginReply)(LoginReplyAddr addr);
typedef int (SPDLLCALL *p_SPAPI_Login)();
//main.cpp
void SPDLLCALL LoginReply(char *user_id, long ret_code, char *ret_msg);
p_SPAPI_RegisterLoginReply SPAPI_RegisterLoginReply;
p_SPAPI_Login SPAPI_Login;
int main(void)
{
HINSTANCE hInst = LoadLibrary("spapidllm64.dll");
SPAPI_RegisterLoginReply = (p_SPAPI_RegisterLoginReply)GetProcAddress(hInst, "SPAPI_RegisterLoginReply");
SPAPI_RegisterLoginReply(LoginReply);
SPAPI_Login = (p_SPAPI_Login)GetProcAddress(hInst, "SPAPI_Login");
int rc = SPAPI_Login();
printf("\nSPAPI_Login: %d\n", rc);
Sleep(3000);
FreeLibrary(hInst);
return 0;
}
void SPDLLCALL LoginReply(char *user_id, long ret_code, char *ret_msg)
{
printf("\nLoginReply[%s]: Ret code: %d, Ret msg: %s",user_id, ret_code, (ret_code == 0)?"OK":ret_msg);
}
now I want to put those codes into a class like this:
// test.h
class ApiTester
{
public:
HINSTANCE hInst;
ApiTester(void){
hInst = LoadLibrary("spapidllm64.dll");
}
~ApiTester(void){
FreeLibrary(hInst);
}
void RegisterDLL();
int Login();
void SPDLLCALL LoginReply(char *user_id, long ret_code, char *ret_msg);
void SPDLLCALL ConnectingReply(long host_type, long con_status);
p_SPAPI_RegisterLoginReply SPAPI_RegisterLoginReply;
p_SPAPI_RegisterConnectingReply SPAPI_RegisterConnectingReply;
p_SPAPI_Login SPAPI_Login;
};
// test.c
#include "tester.h"
void ApiTester::RegisterDLL()
{
SPAPI_RegisterLoginReply = (p_SPAPI_RegisterLoginReply)GetProcAddress(hInst, "SPAPI_RegisterLoginReply");
SPAPI_RegisterLoginReply(LoginReply); // Error E0167 C3867
SPAPI_Login = (p_SPAPI_Login)GetProcAddress(hInst, "SPAPI_Login");
}
int ApiTester::Login()
{
int rc = SPAPI_Login();
printf("\nSPAPI_Login: %d\n", rc);
}
void SPDLLCALL ApiTester::LoginReply(char *user_id, long ret_code, char *ret_msg){
printf("\nLoginReply[%s]: Ret code: %d, Ret msg: %s",user_id, ret_code, (ret_code == 0)?"OK":ret_msg);
}
Then Windows VS C++ shows this error:
Error (active) E0167 argument of type "void (__stdcall ApiTester::*)(char *user_id, long ret_code, char *ret_msg)" is incompatible with parameter of type "LoginReplyAddr"
Error C3867 'ApiTester::LoginReply': non-standard syntax; use '&' to create a pointer to member
Not sure why it works in single file but couldn't work in this way. I thought it should be straight-forward(Hopefully, there is no typo). I'd be appreciate if there is any help.
typedef void (SPDLLCALL *LoginReplyAddr)(char *user_id, long ret_code, char *ret_msg);
typedef void (SPDLLCALL *p_SPAPI_RegisterLoginReply)(LoginReplyAddr addr);
According to the definition above, LoginReplyAddr is a function pointer, not a class member function pointer.
void ApiTester::RegisterDLL()
{
SPAPI_RegisterLoginReply = (p_SPAPI_RegisterLoginReply)GetProcAddress(hInst, "SPAPI_RegisterLoginReply");
SPAPI_RegisterLoginReply(LoginReply); // Error E0167 C3867
...
In this code, LoginReply is class member function pointer.
void (__stdcall ApiTester::*)(char *user_id ...
I guess that is the problem.
If you want to use the class member function as a callback, you also have to pass the 'this' of the class.
Or you can use the static member function.
The link below could help you.
Using a C++ class member function as a C callback function
I have some code which "works" in VS2008 in that it will build and run and do what I expect. However I have a build error in VS2013, I've managed to reproduce it with just this code:
#include "stdafx.h"
#include <Windows.h>
#include <vector>
template < class T >
class SignatureScanner
{
public:
SignatureScanner(const BYTE* aPattern, const char* aMask, int aExpectedMatches = 1, int aOffSetToFuncStart = 0)
{
}
const std::vector<T> Funcs() const
{
return iFuncs;
}
private:
std::vector<T> iFuncs;
};
// Workaround/hack to define a thiscall function
static void __fastcall fake_this_call_func(void *thisPtr, void* not_used_hack, int aParam)
{
printf("this [%x] param [%d]\n", thisPtr, aParam);
}
// type_traits(396): error C3865: '__thiscall' : can only be used on native member functions
int _tmain(int argc, _TCHAR* argv[])
{
typedef void(__thiscall* myFuncPtr)(int thisPtr, int aParam);
// I use this in some hook code to find a function and redirect it to fake_this_call_func
// which works when it builds
SignatureScanner< myFuncPtr > p(0, 0);
return 0;
}
I want to know why did 2008 not have an error when 2013 does, and how should I go about resolving this error? It only needs to build for Windows XP 32-bit - so platform specific hacks are OK.
I am using Qt creator, and it generates this error:
"warning: format '%s' expects argument of type 'char*',
but argument 2 has type 'const void*' [-Wformat]"
The console app is working, but I am interested if there is way to avoid this error, just interested
#include <iostream>
#include <stdio.h>
using namespace std;
bool isOpen(FILE *file);
void print(const void *text);
#define FILE_IS_OPEN "The file is now open"
int main()
{
FILE *f;
f = fopen("This.txt", "w");
if(isOpen(f))
print(FILE_IS_OPEN);
fclose(f);
return 0;
}
bool isOpen(FILE *file) { return file != NULL ? true : false; }
void print(const void *text) { printf("%s\n", text); }
Simply change
void print(const void *text);
to
void print(const char *text);
The same applies in function definition.
Format specifier %s indicates that you're trying to output a string to console, so it requires you to give the address of the string which is nothing but char * here,
you can cast it to (char *)text and pass it to printf.
Also you can't output the contents of a void * pointer they have to any of the primitive data types.
I want to use CUDA runtime API functions accepting CUDA kernel function pointers with kernel templates.
I am able to do the following without templates:
__global__ myKernel()
{
...
}
void myFunc(const char* kernel_ptr)
{
...
// use API functions like
cudaFuncGetAttributes(&attrib, kernel_ptr);
...
}
int main()
{
myFunc(myKernel);
}
However the above does not work when the kernel is a template.
Another example:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
template<typename T>
__global__ void addKernel(T *c, const T *a, const T *b)
{
int i = threadIdx.x;
c[i] = a[i] + b[i];
}
int main()
{
cudaFuncAttributes attrib;
cudaError_t err;
//OK:
err = cudaFuncGetAttributes(&attrib, addKernel<float>); // works fine
printf("result: %s, reg1: %d\n", cudaGetErrorString(err), attrib.numRegs);
//NOT OK:
//try to get function ptr to pass as an argument:
const char* ptr = addKernel<float>; // compile error
err = cudaFuncGetAttributes(&attrib, ptr);
printf("result: %s, reg2: %d\n", cudaGetErrorString(err), attrib.numRegs);
}
The above results in a compile error:
error : no instance of function template "addKernel" matches the
required type
Edit:
The only workaround I've found so far is to put the stuff inside myFunc (see first code example) into a macro, which is ugly, but it requires no pointer argument passing and it works fine:
#define MY_FUNC(kernel) \
{ \
...\
cudaFuncGetAttributes( &attrib, kernel ); \
...\
}
Usage:
MY_FUNC( myKernel<float> )
Referring to your code contained in "another example:"
change this:
const char* ptr = addKernel<float>; // compile error
to this:
void (*ptr)(float *, const float *, const float *) = addKernel<float>;
And I believe it will compile and run correctly.
I don't know if it's useful or not in the overall scope of what you are trying to do.
EDIT responding to a question in the comments:
Once I have the pointer "extracted" from the function, I can then cast it to another type. Try it. For example, the following code also works:
void (*ptr)(float *, const float *, const float *) = addKernel<float>;
const char *ptr1 = (char *)ptr;
err = cudaFuncGetAttributes(&attrib, ptr1);
So, to answer your question, you can cast your function pointer to const char* if you want to, once you have your function pointer.
By the way, the code you posted as an answer throws compile errors for me on gcc 4.1.2 and gcc 4.4.6:
$ nvcc -arch=sm_20 -O3 -o t201 t201.cu
t201.cu: In function âint main()â:
t201.cu:25: error: address of overloaded function with no contextual type information
t201.cu:29: error: address of overloaded function with no contextual type information
$
And I get errors also if I remove the & in those two lines:
$ nvcc -arch=sm_20 -O3 -o t201 t201.cu
t201.cu: In function âint main()â:
t201.cu:25: error: insufficient contextual information to determine type
t201.cu:29: error: insufficient contextual information to determine type
$
So some of this may be compiler dependent, in terms of what steps are needed to get from point A to point B.
The type of addKernel<void> is not char *, it's a function type.
Instead, get the address of addKernel<float> like this:
typedef void (*fun_ptr)(float*,const float *, const float*);
fun_ptr ptr = addKernel<float>; // compile error
err = cudaFuncGetAttributes(&attrib, ptr);
Edit: added a templated version based on cuda runtime and the answer of Robert Crovella.
Here is a full working example using void function pointers and templates.
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
template <typename T>
__global__ void addKernel(T *c, const T *a, const T *b)
{
int i = threadIdx.x;
c[i] = a[i] + b[i];
}
cudaError_t func1( cudaFuncAttributes* attrib, void (*ptr)() )
{
return cudaFuncGetAttributes(attrib, ptr);
}
cudaError_t func2( cudaFuncAttributes* attrib, const char* ptr )
{
return cudaFuncGetAttributes(attrib, ptr);
}
template <typename T>
cudaError_t func2( cudaFuncAttributes* attrib, T ptr )
{
return func2( attrib, (const char*) ptr);
}
int main()
{
cudaFuncAttributes attrib;
cudaError_t err;
void (*ptr2)() = (void(*)())(addKernel<float>); // OK on Visual Studio
err = func1(&attrib, ptr2);
printf("result: %s, reg1: %d\n", cudaGetErrorString(err), attrib.numRegs);
err = func2(&attrib, addKernel<double> ); // OK nice and standard
printf("result: %s, reg2: %d\n", cudaGetErrorString(err), attrib.numRegs);
}
please consider these files:
p.h:
#ifndef _p_h_
#define _p_h_
class p{
public:
static void set_func(int(*)());
private:
static int (*sf)();
};
#endif
p.cpp:
#include "p.h"
#include <cstdio>
int (p::*sf)() = NULL; //defining the function pointer
void p::set_func(int(*f)()){
sf = f;
}
main.cpp:
#include "p.h"
#include <iostream>
int function_x(){
std::cout << "I'm function_x()" << std::endl;
return 1234;
}
int main(){
p::set_func(function_x);
}
when compiling, I get this:
$ g++ -o pp main.cpp p.cpp
/tmp/ccIs0M7r.o:p.cpp:(.text+0x7): undefined reference to `p::sf'
collect2: ld returned 1 exit status
but:
$ g++ -c -o pp p.cpp
compiles right.
What's wrong with the code? I just can't find where the problem is, please your help will be more than appreciated.
Thanks.
Your attempt at defining p::sf is incorrect – yours is a definition of a global variable named sf that is of type int (p::*)(), i.e. a pointer to a member function. Consequently p::sf remains undefined, hence the linker error.
Try this instead:
int (*p::sf)() = 0;
// or,
typedef int (*p_sf_t)();
p_sf_t p::sf = 0;
The difference is because error only occurs when you actually link the program. The problem is in your declaration of the static function pointer. The correct syntax is:
int (*p::sf)() = NULL; //defining the function pointer
You define a member function pointer and not a function pointer. I'm not sure what the correct syntax is, but I would have tried something like this:
int (*p::sf)() = NULL;
I will not give another answer (ildjarn answer is correct) but i will suggest you another way of achieving the same without static initialization (and the burdens it implies)
class p{
public:
typedef int (*func_t)();
static void set_func(func_t v) {
func_t& f = getFuncRef();
f = v;
}
static void call_func() {
func_t& f = getFuncRef();
assert( f != 0);
f();
}
private:
static func_t& getFuncRef() {
static func_t sf = 0;
return sf;
}
};
in this way you delegate the static initialization to a static function variable, which doesn't have the initialization order problems that affect static data variables, and is lazy-initialised