Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > сам импортирую API функцию MessageBox / VS 6.0


Автор: SaikstiN 15.10.2009, 14:52
 smile Доброго времени суток всем

С с++ знаком не очень давно, зато с гуглом уже на ты (это, так сказать, небольшое замечание)

Вообще, я гуглил практически везде где можно, но ничего путного в том числе и примеров не нашел...

Проблема в следующем.. Есть у меня обычный проект Win32 в VS 6.0 (если не ошибаюсь, About говорит о 94-98)

Хотел я там создать окошко через API (люблю я это : ) полупрозрачное.. 
Естественно, линковщик заругался на отсутствие описания функции SetLayeredWindowAttributes и несколько констант к ним...
 + в коде мне нужно было отслеживать WM_LEAVE с помощью TrackMouseEvent, чего в VS 6.0 тоже нет...почему нет, мне ответил гугл... (он еще, разумеется, посоветовал юзать VS 2008 ну или какая там последняя, но переход на новый IDE не состоялся : )

Ок, я решил написать их описание у себя и столкнулся с проблемой незнания как это всё написать  smile 
поиск дал немного инфы, ничего путного я не нашел...
вконце концов гугл посоветовал мне юзать LoadLibrary и GetProcAddress
ок, вышло супер...

но я подумал, а если вообще не подключать windows.h (смущает огромное количество инструкций внутри; макросов, обьявлений, подключений других библиотек и т.д.) и все функции загружать автоматически (т.е. динамическая линковка) (зачем я так подумал даже не спрашивайте)

ок...отключил..куча ошибок...прописал дефайны на типы и несколько структур...ошибок поменьшало....

теперь стал остро вопрос...откуда брать (адреса ф-ций) LoadLibrary и GetProcAddress?
ответ -> гугл....пошарив с полдня, Хром от большого количества вкладок вырубился, что впрочем ничуть не огорчило - инфы там особо не было...

нашел я только два момента - __declspec(dllimport) и DEF-файл

второй способ работает только с длл (?) и в IMPORTS внешних функций содержать вроде как не может....
первый вроде оно самое, но как его использовать не увидел (всмысле как использовать для внешних функций, вроде вызова MessageBeep от user32.dll, или той же LoadLibrary от кернела)

я копал микрософтские header'ы, но, то, что я там находил, и пытался вставить к себе в проект, не работало...

если кто-то знает (или же может это очень заезженная тема, киньте ссыль), напишите хотя бы возможно ли это, и если да, малююсенький пример  smile  (только кодом в с++, затей с асмом не надо : )

если так никто и не понял о чем это я, могу привести код и описание ошибок (хотя, на мой взгяд, всё наглядно)

Спасибо  smile 

Автор: jonie 15.10.2009, 16:42
Цитата
теперь стал остро вопрос...откуда брать (адреса ф-ций) LoadLibrary и GetProcAddress?
я не стал бы этого делать. дело в том что начиная с висты майкрософт стала динамически выбирать (из 256 вариантов вроде) базу kernel-а при загрузке приложения+еще что-то для защиты сделала. Кроме того подобные программы будут с 99% вероятностью блокироваться антивирусным и прочим анти- ПО. 

Автор: SaikstiN 15.10.2009, 16:59
и что же...максимум что я могу делать, это подключать windows.h для LoadLibrary и GetProcAddress и потом уже загружать через них остальные функции?

весело.... smile 

а это только загрузку kernel'а так сделали хреново динамически, или и остальных библиотек тоже?

...антивирусники и в таком случае (через LoadLibrary и GetProcAddress) будут сигналить?

Автор: DrHex 15.10.2009, 17:58
Цитата

LoadLibrary и GetProcAddress

Это одни из самых базовых функций. 

Не хочешь юзать системные???
Пиши сам.

Не хочеш подключать windows.h 
Сделай свою ручками таблицу импорта.....

А вообще зачем такое на С++ пишу на асме............



Автор: GremlinProg 15.10.2009, 18:18
Цитата(jonie @  15.10.2009,  18:42 Найти цитируемый пост)
Кроме того подобные программы будут с 99% вероятностью блокироваться антивирусным и прочим анти- ПО.

с чего бы это?
динамическая загрузка - шанс распознать и учесть особенности платформы, на которой выполняется приложение,
например: отсутствие какой-либо библиотеки, или различие имен библиотек или функций

иногда без динамической загрузки вообще не обойтись,
например: при использовании драйверов, не поставляющихся с операционкой,
особенно, когда программа заточена не только для работы с этим устройством

смешно бы было: `работа программы "рога и копыта" невозможна без устройства "копыта", так что бреются все, кого интересуют только "рога"`
просто антивирусному ПО сложнее анализировать такие динамические вложения,
но это совсем не значит, что только поэтому они их блокируют
Цитата(SaikstiN @  15.10.2009,  16:52 Найти цитируемый пост)
первый вроде оно самое, но как его использовать не увидел (всмысле как использовать для внешних функций, вроде вызова MessageBeep от user32.dll, или той же LoadLibrary от кернела)

для примера мог хотя бы заглянуть в тот же winuser.h
все ведь описано:
Код

WINUSERAPI
int
WINAPI
MessageBoxW(
    __in_opt HWND hWnd,
    __in_opt LPCWSTR lpText,
    __in_opt LPCWSTR lpCaption,
    __in UINT uType);


Код

#define WINAPI      __stdcall

Код

#define WINUSERAPI DECLSPEC_IMPORT

Код

#define DECLSPEC_IMPORT __declspec(dllimport)

для статической загрузки, по типу того, что представлено выше, требования примерно те же, что и для динамической,
т.е. тут участвует та же пара : библиотека и имя функции

__declspec(dllimport) обеспечивает привязку к имени функции,
а библиотеку можно подключить разными способами, вот один из них:
Код

#pragma comment(lib,"User32")

Автор: SaikstiN 15.10.2009, 18:49
Цитата

а библиотеку можно подключить разными способами, вот один из них:


Именно это я (наверно) и искал! smile 
Не понимал, откуда __declspec(dllimport) будет брать библиотеку, но теперь ясно...


Цитата

для примера мог хотя бы заглянуть в тот же winuser.h
все ведь описано:


именно так я и делал, но..почти всегда, даже когда я все макросы #define позаменял ручками, ничего не хотело работать...причем брал header'ы с самых разных компиляторов, и искал в них, но всё отказывалось работать...наверное проблема была в чем-то маленьком и незаметном как всегда smile

сейчас попробовал опять собрать, уже с вашим кодом, вывело такую ошибку

Код

error LNK2001: unresolved external symbol "__declspec(dllimport) int __stdcall MessageBoxA(void *,char const *,char const *,unsigned int)" (__imp_?MessageBoxA@@YGHPAXPBD1I@Z)
Release/smiletop.exe : fatal error LNK1120: 1 unresolved externals


я так понял, адрес ищет внутри екзешника?

вот код:

Код

#define WINVER        0x0500

typedef void *HANDLE;
typedef HANDLE HWND;

typedef const char          *LPCSTR;
typedef unsigned int        UINT;

#pragma comment(lib,"User32")

#define WINAPI      __stdcall
#define WINUSERAPI DECLSPEC_IMPORT
#define DECLSPEC_IMPORT __declspec(dllimport)

WINUSERAPI
int
WINAPI
MessageBoxA(
     HWND hWnd,
     LPCSTR lpText,
     LPCSTR lpCaption,
     UINT uType);


#pragma comment(linker,"/MERGE:.rdata=.text")
#pragma comment(linker,"/FILEALIGN:512 /SECTION:.text,EWRX /IGNORE:4078")
#pragma comment(linker,"/ENTRY:main")
#pragma comment(linker,"/NODEFAULTLIB")


void WINAPI main(){
    MessageBoxA(0,"hello","world",0);
}





и ещё вопросик smile 

Цитата

просто антивирусному ПО сложнее анализировать такие динамические вложения,
но это совсем не значит, что только поэтому они их блокируют


- это когда перед запуском антивирус его проверяет? (ну пусть по эвристическому анализу, или как там)

у меня, например, Касперский перед запуском новых или измененных екзешников окошечко выводит, для проверки , и частенько довольно долго проверяет... это, конечно же, не может нравиться пользователю...

значит, все таки лучше вписывать объявления функций, как выше..  smile 
тогда объявления пишутся в таблицу импорта, так ведь?

Автор: GremlinProg 15.10.2009, 19:34
нужно отключить декорирование плюсов: поставить extern "C"

упростил немного типизацию, для наглядности:
Код

typedef void*            HINSTANCE;
typedef void*            HWND;
typedef char*            LPSTR;
typedef const char*        LPCSTR;
typedef unsigned int    UINT;
#define WINAPI            __stdcall
#define APIENTRY        WINAPI

#pragma comment(lib,"user32")

extern "C" __declspec(dllimport) int WINAPI MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType );

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
    MessageBoxA(0,0,0,0);
    return 0;
}

+ по-моему, при отключении CRT прагма comment lib уже не будет распознанаваться,
в этом случае, можно просто из свойств проекта подключить библиотеки,
но это уже смотри сам, VS 6 под рукой нету, не подскажу

Добавлено через 28 секунд
Цитата(SaikstiN @  15.10.2009,  20:49 Найти цитируемый пост)
тогда объявления пишутся в таблицу импорта, так ведь?

да

Автор: jonie 15.10.2009, 19:51
Цитата(GremlinProg @ 15.10.2009,  18:18)
Цитата(jonie @  15.10.2009,  18:42 Найти цитируемый пост)
Кроме того подобные программы будут с 99% вероятностью блокироваться антивирусным и прочим анти- ПО.

с чего бы это?
динамическая загрузка - шанс распознать и учесть особенности платформы, на которой выполняется приложение,
например: отсутствие какой-либо библиотеки, или различие имен библиотек или функций
....поскипано
а библиотеку можно подключить разными способами, вот один из них:
[/code]

B где у вас динамическая линковка? Я её не вижу. Вижу статическую, в бинарнике будет ссылка на user32.dll, и на функцию из него.

Тут же человек хочет получить адрес функции GetProceAddress без использования GetProcAddress, чтобы в дальнейшем через неё получить адрес LoadLibrary и выполнить её...

Добавлено через 43 секунды
GremlinProg, ну не динамическое это, вам не кажется?)

Добавлено через 1 минуту и 54 секунды
или под 
Цитата

теперь стал остро вопрос...откуда брать (адреса ф-ций) LoadLibrary и GetProcAddress?
человек имел ввиду как их вызвать (получить в таблице импорта), а не как получить адреса в runtime?

Автор: GremlinProg 15.10.2009, 20:16
Цитата(jonie @  15.10.2009,  21:51 Найти цитируемый пост)
B где у вас динамическая линковка? Я её не вижу. Вижу статическую, в бинарнике будет ссылка на user32.dll, и на функцию из него.

динамическую я и не писал )
как и SaikstiN
Цитата(jonie @  15.10.2009,  21:51 Найти цитируемый пост)
Тут же человек хочет получить адрес функции GetProceAddress без использования GetProcAddress, чтобы в дальнейшем через неё получить адрес LoadLibrary и выполнить её...

да, уже понял,
я просто связал в цепочку "LoadLibrary и GetProcAddress" и "подобные программы будут с 99% вероятностью блокироваться",
а на первую часть цитаты не обратил внимания, мои извинения jonie

непонятно только, зачем искать в секции импорта адреса из Kernel32, которая уже заведомо участвует в работе приложения )
объявить обе функции статически и все

строим замки на пустом месте?

Цитата(jonie @  15.10.2009,  21:51 Найти цитируемый пост)
человек имел ввиду как их вызвать (получить в таблице импорта), а не как получить адреса в runtime?

Цитата(SaikstiN @  15.10.2009,  16:52 Найти цитируемый пост)
 а если вообще не подключать windows.h

видимо, SaikstiN все таки хочет просто подключить API без windows.h,
а статически или динамически - не имеет значения

Автор: GoldFinch 15.10.2009, 20:17
Цитата(jonie @  15.10.2009,  17:42 Найти цитируемый пост)
дело в том что начиная с висты майкрософт стала динамически выбирать (из 256 вариантов вроде) базу kernel-а при загрузке приложения+еще что-то для защиты сделала. Кроме того подобные программы будут с 99% вероятностью блокироваться антивирусным и прочим анти- ПО. 

Редко кто получал базу kernel32 по статическим адресам, т.к. в каждой ОС (и сервиспаке) она разная

Никто получение базы kernel32  блокировать не будет, т.к. это нормальный код для упаковщиков. 
Нормальные антивирусы это проигнорируют, а недоантивирусы (типа авиры) этого не заметят, т.к. сигнатуру на такой код делать глупо, будут ложные срабатывания на кучу программ, а эмулятора у недоантивирусов нет.

Код получения базы kernel32, и затем адресов ее функций гуглится с 1го запроса,
однако нормальный импорт конечно проще.

Автор: GremlinProg 15.10.2009, 20:47
Цитата(GoldFinch @  15.10.2009,  22:17 Найти цитируемый пост)
Редко кто получал базу kernel32 по статическим адресам, т.к. в каждой ОС (и сервиспаке) она разная

по статическим адресам?
может все таки по фиксированным адресам?

в секции импорта статически задаются только расположения адресов, а не сами адреса,
база библиотеки тут не имеет значения,
т.к. загрузчик уже сам корректирует эти адреса в соответствии с базами по статическим расположениям,
т.е. на выходе образа в адресное пространство, все адреса функций уже корректны,
в этом и фишка статической адресации

Автор: SaikstiN 15.10.2009, 20:58
GremlinProg, спасибо, работает.
Даже не знал о таком extern "C", теперь понял smile 

я подключил user32.lib через Link -> General Object/Library Modules

Всем спасибо за ответы ;)

Автор: jonie 15.10.2009, 21:30
GoldFinch, не надо нам тут. Получение базы кернела это признак не упаковщика, а защиты вроде asprotect или армадиллы... и это плохой подход и плохой код. У меня включена DEP - попробуйте позапускайте такие "игрушки"  в win vista под гостем ..

Автор: GoldFinch 15.10.2009, 21:47
GremlinProg, по "статически прописанным в коде", типа 0x7C800000 для xpsp2
секция импорта тут ни при чем вообще, база (HMODULE) kernel32 нужна чтобы вызвать аналог GetProcAddress(Kernel32Base,"funcname")

jonie, упаковщики ничем не отличаются от протекторов в плане получения импорта
DEP тут вообще ни при чем, это запрет исполнения кода в страницах памяти где исполнение кода запрещено. С импортами это никак не связано. 

Учите матчасть.

Автор: jonie 16.10.2009, 08:27
GoldFinch, учите матчасть. В любом нормальном упаковщике GetProcAddress присуствует в импорте - покажите где нет?

Автор: SaikstiN 16.10.2009, 10:55
Снова здравствуйте  smile 

Не хочу прерывать наметившуюся здесь дискуссию, но у меня возник вопрос в процессе дальнейшего написания этой программки, и ответа я найти не смог... smile 

Точнее сказать, такой проблемы наверное ни у кого не возникало...

В-общем, в продолжении, у меня в программе имеются импортированные функции SetLayeredWindowAttributes и TrackMouseEvent  +несколько define'ов и  typedef'ов

Наверное я где-то что-то напутал с обьявлением, хотя по msdn правильно, но при вызове TrackMouseEvent в WM_MOUSEMOVE (для получения WM_LEAVE) программа закрывается вылетает

Продебаггить этот участок я не смог, но с помощью незаменимых MessageBox'ов, стало ясно что проблема возникает именно когда я вызываю TrackMouseEvent

Тогда я засунул вызов TrackMouseEvent до начала цикла обработки сообщений окна (TranslateMessage), и, о чудо, работает и даже возвращает первый WM_LEAVE...

самое смешное что я совершенно не догадываюсь от чего это оно так себя ведёт..

вот обьявление
Код

#define WM_MOUSEHOVER    0x2a1
#define WM_MOUSELEAVE    0x2a3
#define WM_MOUSEWHEEL    0x20A

typedef struct tagTRACKMOUSEEVENT {
    DWORD cbSize;
    DWORD dwFlags;
    HWND hwndTrack;
    DWORD dwHoverTime;
} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT;

#define TME_HOVER 1
#define TME_LEAVE 2
#define TME_NONCLIENT 16
#define TME_QUERY    0x40000000
#define TME_CANCEL    0x80000000

typedef INT (_cdecl *pTrackMouseEvent)(LPTRACKMOUSEEVENT);
pTrackMouseEvent                _TrackMouseEvent;
...
_TrackMouseEvent = (pTrackMouseEvent)GetProcAddress(hUser32Lib,"TrackMouseEvent")


а вот код которым вызываю
Код

TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hMainWnd;
_TrackMouseEvent(&tme);


я почти уверен что ошибок там нет...

подскажите пожалуйста, я уже почти сошел с ума от безысходности.. smile 

Автор: 586 16.10.2009, 11:01
Цитата(SaikstiN @  16.10.2009,  11:55 Найти цитируемый пост)
typedef INT (_cdecl *pTrackMouseEvent)(LPTRACKMOUSEEVENT);

Почему здесь _cdecl, там должен быть __stdcall.

Автор: SaikstiN 16.10.2009, 11:16
 smile 

Ура!!!!, огромное спасибо, 586

Автор: GoldFinch 16.10.2009, 17:30
Цитата(jonie @  16.10.2009,  09:27 Найти цитируемый пост)
В любом нормальном упаковщике GetProcAddress присуствует в импорте - покажите где нет? 

да пусть так, я хз как там в упаковщиках, но только при чем тут DEP, при чем тут антивирусы, и почему это плохой код?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)