Всех приветствую не первый раз сталкиваюсь с тем что невозможно определить указатель на функцию в C++ которая принимает переменное число аргументов и имеет соглашение __stdcall если пишеш func(...) то требует __cdecl а если func() то вообще не принимает в Си можно спокойно написать typedef void (__stdcall*)(); и это работает для переменного числа аргументов и при этом стек не чистится после вызова как бы так сделать в C++ вот код в котором надо передавать переменное число и не чистить стек после вызова Код (Text): typedef void(__thiscall*fn_t)(void*_this); class test{ public: virtual void f1(){} virtual void f2(){} }; int main(){ test o; fn_t *func = *(fn_t**)&o; func[0](&o); func[1](&o); // func[2](&o, arg1, arg2, arg3, ...); } надо нечто такого typedef void(__thiscall*fn_t)(void*_this, ...); и чтоб стек не корректировался после вызова но на это пишет error C2217: '...' requires '__cdecl' и вообще как в MSVC++ добится передачи переменного числа аргументов с соглашением __stdcall или __thiscall ?
Извине, но думаю вы плохо предстовляете что это такое, вообщем в гугуле можно найти ... Argument Passing and Naming Conventions http://msdn.microsoft.com/en-us/library/984x0h58%28v=VS.80%29.aspx naked (C++) http://msdn.microsoft.com/en-us/library/h5w10wxs%28v=VS.80%29.aspx
osox посмотрите что это такое - стдкалл и сами ответьте себе - возможно ли вообще к нему применять переменное число параметров.
А теперь скажите нам, что такое "__stdcall, но с переменным числом аргументов и стек не чистится после вызова". Это и есть cdecl так не бывает
ЭТО В СИ ВОЗМОЖНО я непонимаю чему вы удивляетесь потому что это уже есть и работает но в Си а не в Си++ в Си я могу винапишку описать без инклудов как например void __stdcall MessageBoxA(); и это работает компилятор примет любое количество аргументов и соглашение при вызове будет __stdcall из за этого это собирается компоновщиком в С++ я так не могу вернее могу но максимум это __cdecl соглашение но тогда линкер ругается из за несовпадения линкер ищет _MessageBoxA а экспортируется _MessageBoxA@16 это один из примеров что нужно неконтролируемое количество параметров и чтоб соглашение компилятор юзал stdcall в Си это ВОЗМОЖНО как сделать тоже самое в С++ ? или вот еще пример компилятор написал виртуальные функции с соглашением __thiscall я не хочу для каждой описывать сигнатуру хочу чтоб сколько при вызове указываю все передавал как в __cdecl но так как виртуальные функции сами чистят стек хочу чтоб после моих вызовов компилятор не корректировал стек в Си это так void __stdcall Func(); как такое же в С++ сделать ?
у студентов сессия пошла, скоро и школьники с каникулами догонят.. зачем ты классы юзаешь, горе, если ты на си писал? ) напиши враппер, если тебе стёк надо сохранять, в конце-концов)
osox как много слов. и все навалены как нибудь. если можно, то 2мя-3мя предложениями то что вам надо. по пунктам, с отступами и форматированием. и без эмоций. стдкалл не примет переменное количество аргументов. вне зависимости от языка и компилятора
Возможно это поможет: Код (Text): ////////////////////////////////////////////////////////////////////////////// // // Test a detour of a member function (member.cpp of member.exe) // // Microsoft Research Detours Package, Version 2.1. // // Copyright (c) Microsoft Corporation. All rights reserved. // // By default, C++ member functions use the __thiscall calling convention. // In order to Detour a member function, both the trampoline and the detour // must have exactly the same calling convention as the target function. // Unfortunately, the VC compiler does not support a __thiscall, so the only // way to create legal detour and trampoline functions is by making them // class members of a "detour" class. // // In addition, C++ does not support converting a pointer to a member // function to an arbitrary pointer. To get a raw pointer, the address of // the member function must be moved into a temporrary member-function // pointer, then passed by taking it's address, then de-referencing it. // Fortunately, the compiler will optimize the code to remove the extra // pointer operations. // // If X::Target is a virtual function, the following code will *NOT* work // because &X::Target is the address of a thunk that does a virtual call, // not the real address of the X::Target. You can get the real address // of X::Target by looking directly in the VTBL for class X, but there // is no legal way to 1) get the address of X's VTBL or 2) get the offset // of ::Target within that VTBL. You can of course, figure these out for // a particular class and function, but there is no general way to do so. // #include <stdio.h> #include <windows.h> #include <detours.h> #include "..\slept\verify.cpp" //////////////////////////////////////////////////////////////// Target Class. // class CMember { public: void Target(void); }; void CMember::Target(void) { printf(" CMember::Target! (this:%p)\n", this); } //////////////////////////////////////////////////////////////// Detour Class. // class CDetour /* add ": public CMember" to enable access to member variables... */ { public: void Mine_Target(void); static void (CDetour::* Real_Target)(void); // Class shouldn't have any member variables or virtual functions. }; void CDetour::Mine_Target(void) { printf(" CDetour::Mine_Target! (this:%p)\n", this); (this->*Real_Target)(); } void (CDetour::* CDetour::Real_Target)(void) = (void (CDetour::*)(void))&CMember::Target; ////////////////////////////////////////////////////////////////////////////// // int main(int argc, char **argv) { (void)argc; (void)argv; ////////////////////////////////////////////////////////////////////////// // #if (_MSC_VER < 1310) void (CMember::* pfTarget)(void) = CMember::Target; void (CDetour::* pfMine)(void) = CDetour::Mine_Target; Verify("CMember::Target", *(PBYTE*)&pfTarget); Verify("*CDetour::Real_Target", *(PBYTE*)&CDetour::Real_Target); Verify("CDetour::Mine_Target", *(PBYTE*)&pfMine); #else Verify("CMember::Target", (PBYTE)(&(PBYTE&)CMember::Target)); Verify("*CDetour::Real_Target", *(&(PBYTE&)CDetour::Real_Target)); Verify("CDetour::Mine_Target", (PBYTE)(&(PBYTE&)CDetour::Mine_Target)); #endif printf("\n"); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); #if (_MSC_VER < 1310) pfMine = CDetour::Mine_Target; DetourAttach(&(PVOID&)CDetour::Real_Target, *(PBYTE*)&pfMine); #else DetourAttach(&(PVOID&)CDetour::Real_Target, (PVOID)(&(PVOID&)CDetour::Mine_Target)); #endif LONG l = DetourTransactionCommit(); printf("DetourTransactionCommit = %d\n", l); printf("\n"); #if (_MSC_VER < 1310) pfTarget = CMember::Target; pfMine = CDetour::Mine_Target; Verify("CMember::Target", *(PBYTE*)&pfTarget); Verify("*CDetour::Real_Target", *(&(PBYTE&)CDetour::Real_Target)); Verify("CDetour::Mine_Target", *(PBYTE*)&pfMine); #else Verify("CMember::Target", (PBYTE)(&(PBYTE&)CMember::Target)); Verify("*CDetour::Real_Target", *(&(PBYTE&)CDetour::Real_Target)); Verify("CDetour::Mine_Target", (PBYTE)(&(PBYTE&)CDetour::Mine_Target)); #endif printf("\n"); ////////////////////////////////////////////////////////////////////////// // CMember target; printf("Calling CMember (w/o Detour):\n"); (((CDetour*)&target)->*CDetour::Real_Target)(); printf("Calling CMember (will be detoured):\n"); target.Target(); return 0; }
никак... это связано с тем, что в либ файлах имена "украшенные"... если найдете и подключите user32.lib с "неукрашенными" именами проблемы с компиляцией не будет, но будет проблема со стеком... вы не можете объяснить, что вам нужно... но я вам отвечу... вас спасет преобразование указателей на функцию перед вызовом... попробуйте... а когда поймете, что это не удобно, придете сюда и снова ничего не сможете объяснить... но я вам отвечу сразу, что вам помогут темплейты, или препроцессором можно сделать...
Ты знаешь что такое stdcall? При stdcall функция сама должна стэк от параметров очистить. Как она это сделает, если не знает сколько их там? И да, твой пример просто гениальный. В Си так можно, оно не собирается, а если собирается, то не работает, но так можно, честно.
cppasm Чё вы народ путаете - единственное отличие cdecl от stdcall в том, что в stdcall стек очищает вызываемый (т.е. функция), тогда как в cdecl стек очищает вызывающий. Прядок передачи параметров через стек ОДИНАКОВЫЙ. Разберитесь сами сначала, перед тем как такие советы раздавать. UPD: Вот вам в догонку ссылко: http://unixwiz.net/techtips/win32-callconv.html, учите матчасть
Спасибо дядя, когда мне надо будет - я загуглить в состоянии. Да, попутал с pascal. stdcall это по сути гибрид pascal и cdecl. В любом случае, вопрос по очистке стэка остаётся в силе. По твоей же ссылке написано: При чём здесь не понятно. Ты в любом другом компиляторе можешь это сделать?
Дык отвечаьт другим надо или правильно или никак osox в СИ как и в С++ это невозможно по тем же причинам!
Кто-то спорит что-ли? Или ты никогда не ошибаешься? Просто есть разница между тем чтобы исправить чужую ошибку, и понтоваться типа "учите матчасть".
Товарищу нужно получить указатель на начало функции, но не в виде void (*func)(), а в виде void *func. Например, чтобы потом просплайсить её. При чем здесь модель вызова? Хочется показать, что вы знаете какой код создаёт компилятор? И даже тут некоторые умудрились ошибиться.