I'm using Libtooling to parse Windows SDK headers but there is a problem in getting functions calling conventions, The libtooling always return __cdell for WINAPI or __stdcall calling convention which is the defualt calling convention of Win32 API's.
This is an input example
VOID
__stdcall
TestFunction (_In_ BOOLEAN is_valid);
This is my Function Visitor function of my RecursiveASTVisitor
virtual bool VisitFunctionDecl(clang::FunctionDecl *func)
{
// ...
if (m_AstContext->getSourceManager().isInMainFile(func->getLocation()))
{
if (func->hasAttrs())
{
auto stdcall = func->hasAttr<StdCallAttr>(); // always return False
}
const clang::FunctionProtoType * prototype = func->getType()->getAs<FunctionProtoType>();
if (prototype)
{
auto stdcall = prototype->hasAttr(attr::Kind::StdCall); // always return False
errs() << clang::FunctionType::getNameForCallConv(prototype->getCallConv()).str() << " "; // always return cdecl
}
func->dumpColor(); // But there is __attribute__((stdcall)) in dumped output!
}
// ...
}
And finally output of func->dumpColor(); for input example!
^
FunctionDecl 0x218c95bb6f0 <C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\um\winnt.h:430:14, C:\ExampleInput.h:18:36> col:1 TestFunction 'void (BOOLEAN) __attribute__((stdcall))':'void (BOOLEAN)'
`-ParmVarDecl 0x218c95bb5c0 <col:20, col:28> col:28 is_valid 'BOOLEAN':'unsigned char'
I ran it with/without this options too, for compatibility reasons but no difference at all :-(
-fms-compatibility
-fms-extensions
-fms-compatibility-version=19
Any idea?
Update
I found the problem, It's because of defualt compile config of #Clang. It's 64-bit (in 64-bit toolchain), And it doesn't work with __stdcall in 64-bit mode
If I use the 32-bit version (or -m32 option) then it will works correctly
Any idea why it happens in 64-bit mode?
Related
I have problems with FTD2xx driver.
I'm using QT(C++) in Fedora 26 (64-bit) and the last version of FTD2xx for "2232H" device.
Also the build method is:
qmake /Address/ProjectName.pro -r -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug
Problem:
The FT_Status return 0(FT_OK) at ft_openex(....) command, but that return none_zero(FT_OK) for other functions of FTD2xx lib;
A section of my code:
FT_HANDLE ftH;
FT_STATUS ftStatus;
ftStatus = FT_OpenEx(const_cast<char*>("MYDevName"), FT_OPEN_BY_SERIAL_NUMBER, &ftH);
std::cout<<"FTST open:"<< ftStatus<<std::endl;
char a[10];DWORD b;
ftStatus = FT_SetBitMode(&ftH,0xff,0);
std::cout<<"FTST RESET:"<< ftStatus<<std::endl;
ftStatus = FT_SetBitMode(&ftH,0xff,0x40);
std::cout<<"FTST SPEED:"<< ftStatus<<std::endl;
ftStatus = FT_Close(&ftH);
std::cout<<"FTST CLOSE:"<< ftStatus<<std::endl;
And output :
FTST open:0
FTST RESET:1
FTST SPEED:1
FTST CLOSE:1
ftStatus =1 ;means FT_INVALID_HANDLE.
and
Command <<rmmod ftdi_sio >> is using.
and
Lib directory: /dev/local/lib
and
QT setting:
LIBS += -L$$PWD/../../../usr/local/lib/ -lftd2xx
INCLUDEPATH += $$PWD/../../../usr/local/include
DEPENDPATH += $$PWD/../../../usr/local/include
The FT_HANDLE is an output parameter in FT_OpenEx. You are correctly passing &ftH so that the function can overwrite ftH.
The FT_HANDLE is an input parameter to the other functions. You are incorrectly passing &ftH and should pass just ftH.
FT_Close(&ftH);
FT_Close(ftH);
Unfortunately FT_HANDLE is defined in a loosely-typed way:
typedef void* PVOID;
typedef PVOID FT_HANDLE;
Since void** implicitly converts to void*, the compiler cannot help you catch this mistake1. In general opaque handle types should be declared as
typedef struct AlwaysIncompleteType * MY_HANDLE;
and then the pointer and double-pointer types will be appropriately incompatible.
1 Even worse, in C, the reverse conversion from void* to void** is also implicit and you would be allowed to call FT_OpenEx(..., ftH) probably resulting in an immediate access violation (aka segmentation fault) and possibly resulting in unpredictable memory corruption. At least C++ got this right... but void* is still not conducive to strong type checking.
i'm working on a program in c++ where i'm trying to use the WriteProcessMemory() function in windows. for that i need a function that gets the target process id. i'm able to do that using the following function:
#pragma once
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
//get process id from executable name using tlhelp32snapshot
DWORD GetProcID(wchar_t *exeName){
PROCESSENTRY32 procEntry = {0};
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (!hSnapshot) {
return 0;
}
procEntry.dwSize = sizeof(procEntry);
if (!Process32First(hSnapshot, &procEntry)) {
return 0;
}
do {
if (!wcscmp(procEntry.szExeFile, exeName)) {
CloseHandle(hSnapshot);
return procEntry.th32ProcessID;
}
} while (Process32Next(hSnapshot, &procEntry));
CloseHandle(hSnapshot);
return 0;
}
//main function
int main() {
using namespace std;
cout << "some output" << endl;
return 0;
}
i'm able to compile using visual studio if i set the character set to unicode but when i try using g++ i get a conversion error:
g++ -std=c++17 write.cpp
write.cpp:1:9: warning: #pragma once in main file
#pragma once
^
write.cpp: In function 'DWORD GetProcID(wchar_t*)':
write.cpp:21:43: error: cannot convert 'CHAR* {aka char*}' to 'const wchar_t*' for argument '1' to 'int wcscmp(const wchar_t*, const wchar_t*)'
if (!wcscmp(procEntry.szExeFile, exeName)) {
^
write.cpp: In function 'MODULEENTRY32 GetModule(DWORD, wchar_t*)':
write.cpp:40:46: error: cannot convert 'char*' to 'const wchar_t*' for argument '1' to 'int wcscmp(const wchar_t*, const wchar_t*)'
if (!wcscmp(modEntry.szModule, moduleName)) {
^
i'm able to compile with cl using the arguments:
cl /EHsc /D UNICODE write.cpp
here /D UNICODE is the same as going in visual studio > rmb on project > properties and seting Character Set to Use Unicode Character Set.
is there an option to force unicode in g++ like in cl?
cl (Microsoft C/C++ Compiler) and g++ (Gnu C++ Compiler) have a very close arguments syntax on certain parameter. The delta is more of the usual difference Dos / Shell (slash vs dash).
The equivalent of /DMY_IDENTIFIER (cl) is on g++:
-DMY_IDENTIFER
Which means in your case: -DUNICODE
The complete compilation command line would have to look like:
g++ -DUNICODE -std=c++17 write.cpp
The correct answer here is to use the compiler switch -municode which defines everything you need, and links to the correct CRT files as to provide you with the proper definition of _wmain.
This is not available on ye olde MinGW, so you'll need a MinGW-w64 toolchain for that. Chances are you are already using that anyway. If that is not the case, you can download the installer from here.
I've built a VRPN client on Linux. It's based on this: http://www.vrgeeks.org/vrpn/tutorial---use-vrpn
Here's some of the code:
vrpn_Analog_Remote * analog = NULL;
vrpn_Button_Remote * button = NULL;
vrpn_Tracker_Remote * tracker = NULL;
// Things happen...
analog = new vrpn_Analog_Remote("pathToAnalog");
analog->register_change_handler(NULL, handleAnalog);
button = new vrpn_Button_Remote("pathToButton");
button->register_change_handler(NULL, handleButton);
tracker = new vrpn_Tracker_Remote("pathToTracker");
tracker->register_change_handler(NULL, handleTracker);
Here are the callbacks refered to in this code:
void handleAnalog(void * userData, const vrpn_ANALOGCB a) {
// Do stuff...
}
void handleButton(void * userData, const vrpn_BUTTONCB b) {
// Do stuff...
}
void handleTracker(void * userData, const vrpn_TRACKERCB t) {
// Do stuff...
}
And here is where all of these references to VRPN are defined:
https://github.com/vrpn/vrpn/blob/master/vrpn_Analog.h#L168
https://github.com/vrpn/vrpn/blob/master/vrpn_Button.h#L225
https://github.com/vrpn/vrpn/blob/master/vrpn_Tracker.h#L284
These compile without even a warning on Linux and can actually be used. Everything worked as expected. All the types here seem to satisfy the compiler, g++.
But on Windows, whether I use Visual Studio 2015 or MinGW's g++, I get this for the first two callback registrations:
invalid conversion from 'void (*)(void*, vrpn_ANALOGCB) {aka void (*)(void*, _vrpn_ANALOGCB)}' to 'vrpn_ANALOGCHANGEHANDLER {aka
void (__attribute__((__stdcall__)) *)(void*, _vrpn_ANALOGCB)}' [-fpermissive]
invalid conversion from 'void (*)(void*, vrpn_BUTTONCB) {aka void (*)(void*, _vrpn_BUTTONCB)}' to 'vrpn_BUTTONCHANGEHANDLER {aka
void (__attribute__((__stdcall__)) *)(void*, _vrpn_BUTTONCB)}' [-fpermissive]
And for the last one, I get a different error:
call of overloaded 'register_change_handler(NULL, void (&)(void*, vrpn_TRACKERCB))' is
ambiguous
Now that I'm typing this, I'm thinking maybe VRPN was compiled differently on Windows and that's why the compiler now has a problem with my code. But I'm very lost as to what to do.
Try declaring your callbacks like this:
void VRPN_CALLBACK handleAnalog(void * userData, const vrpn_ANALOGCB a) {
// Do stuff...
}
For linux, the VRPN_CALLBACK define is empty, so you did not notice any problems there. For windows, the VRPN library devs decided that they expect a callback that adheres to the __stdcall calling-convention. Thus you have to declare your function accordingly, and the most painless+portable way is to use the very same VRPN_CALLBACK define that they provide.
Clues to this came from your links to the code at github:
[vrpn_Analog.h]
typedef void(VRPN_CALLBACK *vrpn_ANALOGCHANGEHANDLER)(void *userdata,
const vrpn_ANALOGCB info);
and the callback define is made here:
[vrpn_Configure.h]
#ifdef _WIN32 // [ ...
#define VRPN_CALLBACK __stdcall
#else // ... ] WIN32 [
#define VRPN_CALLBACK
#endif // ] not WIN32
I'm trying to wrap a c++ function called i_receive() by following this tutorial, I first created a wrap.c file, the content of this file is like this:
int i_receive(const uint32_t *f, int32_t t){
static int (*real_i_receive)(const uint32_t *, int32_t)=NULL;
printf("hello world");
return real_i_receive;
}
I compiled this file with gcc -fPIC -shared -o wrap.so wrap.c -ldl, when I used the LD_PRELOAD to run some C++ code with LD_PRELOAD=/full/path/to/wrap.so ./mycppcode I got this message:
ERROR: ld.so: object '/full/path/to/wrap.so' from LD_PRELOAD cannot be preloaded: ignored`.
I was guessing the reason might be that the wrap file is a C file, and I'm using it with C++ code, am I right?
I changed the file to wrap.cc with the same content, when compiling in the same way as before, I got:
ERROR: invalid conversion from 'int (*)(const uint32_t*, int32_t)' to 'int'
First of all, your 2nd error your are getting becase you are returning a Pointer to function type instead of a int type.
If you want to return an int, call the function from the code :
return real_i_receive(f,t);
Notice the "()" which means a function call.
Regarding your guess : it doesn't matter if you are using C or C++ code, the libaries are all assembly code.
One difference between exporting C functions and C++ functions is the name mangling. You would rather export a function as a C function to be able to access it inside your library through unmagled name.
To export a function without name mangling it, you can use extern "C" .
Replace
return real_i_receive;
with
return real_i_receive(f, t);
As it is, the return type of your function is int but you're returning a function pointer.
hi i have compiled the below specified code
long (*interlocked_increment) (volatile long *);
long InterlockedIncrement(volatile long & value) const {
return interlocked_increment(&value);
}
static long m_interlocked_increment(volatile long * pv) {
#ifdef WIN32
return InterlockedIncrement(pv);
#elif defined(HAS_SYNC_FUNCTIONS)
return __sync_fetch_and_add(pv, 1L);
#else
return ++(*pv);
#endif
}
in g++ compiler it will works fine. but while i try the same in visual c++ 2008 it shows the below specified error.ho can i resolve this problem.
Error 5 error C3861: 'InterlockedIncrement': identifier not found
The InterlockedIncrement() function takes volatile long &, whereas you're passing it a volatile long *, thus the compiler can't find the corresponding function signature.