На главную

Библиотека Интернет Индустрии I2R.ru

Rambler's Top100

Малобюджетные сайты...

Продвижение веб-сайта...

Контент и авторское право...

Забобрить эту страницу! Забобрить! Блог Библиотека Сайтостроительства на toodoo
  Поиск:   
Рассылки для занятых...»
I2R » И2Р Программы » Программирование » C, C++

Написание экстра-маленьких Win32 приложений на С++ от 1 КБ используя лишь API, на примере программы Windows Hider

Введение


   Натыкаясь в Интернете на довольно интересные программы, я часто не решался их закачивать после того, как узнавал их размер. Какую ни возьми - все огромные. Да и ресурсов системных потребляют немало. В этой статье будет рассказано о том, как сделать программу в среднем в 10 - 100 раз меньше размером, чем попадаются аналогичные.

Цель


   Написать очень быструю и маленькую программу, скрывающую по CTRL+F12 заданные окна. При нажатии комбинации CTRL+F10 она должна показать спрятанные окна. Входные данные:

TXT Файл вида
------------
Internet Explorer
The Bat!
Visual C++
911
------------

Если будут найдены окна, содержащие в своем заголовке указанные строки, они будут спрятаны.
В вышеуказанном примере будут спрятаны все окна IE, окно Microsoft Visual C++, окно почтовой программы "The Bat!" и все окна, в заголовках которых содержится комбинация символов "911".
   Итак, писать будем на чистом Win32 API. Создадим окно, привяжем к нему горячие клавиши. По требованию будем осуществлять перебор видимых окон в системе и в заголовке каждого будем искать заданные комбинации символов.

Опции линкера


   Если ничего не предпринимать, то нам не удастся получить в итоге файл менее 32 КБ(примерно). Поэтому пишем:

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

На что теперь стоит обратить особое внимание? Обычно точка входа в программу выглядит так:
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR szCmdLine,int nCmdShow)
(кстати, для Win32 приложений второй параметр всегда NULL)

Но(!)... Так как мы отключили "Runtime library", нам теперь передается в этих параметрах разный мусор. Поэтому называем точку входа не WinMain а New_WinMain, которую объявим, как void New_WinMain(void), чтобы не забыть о том, что нам ничего не передается. А параметр HINSTANCE получаем функцией GetModuleHandle(NULL). Ах да, и выходить из программы будем функцией ExitProcess.
   Теперь если собрать нашу пустую программку, которая ничего делать не будет, размер ее будет 1 Кб. Но нам нужно еще дописать 3 Кб кода. Продолжим.
   Чтобы все дальнейшее было понятно даже новичку в программировании под Windows, я прокомментирую все.

Объявим кое-какие константы


Это понадобится для регистрации "горячих" клавиш функцией RegisterHotKey.
#define HOTKEYHIDE 1
#define HOTKEYSHOW 2


Размер буффера, куда будет считываться заголовок окна функцией GetWindowText.
#define SSZZ 256

Размер буфера, куда будет считываться файл со стоками фильтрации (используется в объявлении char FilterStrings[MAXFIL];)
#define MAXFIL 1024
(Примечание: При желании можно сделать и выделение памяти динамически - найти файл, узнать его размер и выделить блок. Приблизительный пример:

// .....................
WIN32_FIND_DATA FindData;
HANDLE hFind=FindFirstFile(szFilterStringsFile,&FindData);
if (hFind!=INVALID_HANDLE_VALUE)
{
  i=(FindData.nFileSizeHigh * MAXDWORD) + FindData.nFileSizeLow;
  HGLOBAL hGA=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE,i+1);
  // (+ end-ZERO)
  if (hGA!=NULL)
  {
    LPVOID lpStrings=GlobalLock(hGA);
    DWORD dw;
    if (lpStrings!=NULL) ReadFile(hFile,lpStrings,i,&dw,NULL);
    }
        
  }
  FindClose(hFind);
  CloseHandle(hFile);
// ...............................
// Но так как вряд ли файл настроек у нас будет больше одного
// килобайта, я оставил статичный массив.
)

Зададим глобальные переменные


Массив хендлов окон (вряд ли будет у нас более 300 окон)
HWND aHwnd[300];

Кол-во инициализированных элементов в этом массиве
unsigned int cHwnd=0;

Дескрипторы окон - главное и два дочерних - кнопка "Hide" и кнопка "Edit filter strings"
HWND hwndMain, hwndButtonHide, hwndButtonEditFilter;

Тут будет что-то типа "c:\programs\winhider\winhider.settings.txt"
char szFilterStringsFile[MAX_PATH]="(с)2002 KMiNT21";

Соответственно, хендл файла с именем "что-то типа"
HANDLE hFile;

А это место, куда будем считывать все из этого файла
char FilterStrings[MAXFIL];

Функции


Обработка сообщений главного окна
LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);

Функция, которая будет вызываться для каждого окна при переборе всех окон
static BOOL FAR PASCAL my_EnumWindowsProc(HWND hwnd, DWORD lParam);

Проверка наличия строки str2 в str1
BOOL Contain(char* str1, char* str2);

Скрывание с экрана очередного окна
inline void HideNext(HWND hwnd){ ShowWindow(aHwnd[cHwnd++]=hwnd,SW_HIDE); }

Возврат всех спрятанных окон на экран
inline void ShowAll(void) { while(cHwnd) ShowWindow(aHwnd[--cHwnd],SW_SHOW);}

Пройдемся по главным строкам функции NewWinMain


* Получим INSTANCE модуля. Это нам нужно для регистрации оконного класса
   HINSTANCE hInst=GetModuleHandle(NULL);

* Зарегистрируем оконный класс

 WNDCLASS wc;
  wc.style = CS_HREDRAW|CS_VREDRAW ;
  wc.lpfnWndProc = (WNDPROC)MainWndProc;
  wc.hInstance = hInst;
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
  wc.lpszClassName = "CKMINT21WINDOWSHIDERPRO";
  wc.hCursor = LoadCursor(NULL,IDC_ARROW);
  wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
  wc.lpszMenuName=NULL;
  wc.cbClsExtra=0;
  wc.cbWndExtra=0;
  if (!RegisterClass(&wc)) MessageBox(0,"I can't register window
               class.","Error:",0), ExitProcess(0);

* Создаем главное окно приложения
   hwndMain=CreateWindow(wc.lpszClassName,"Small windows hider!", WS_BORDER|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, CW_USEDEFAULT,0,291,180, NULL, NULL, hInst, NULL);

И помещаем на него две кнопки. Как видим, кнопки имеют класс "BUTTON". Они являются дочерними окну hwndMain.
hwndButtonHide=CreateWindow("BUTTON","Hide!", WS_VISIBLE | WS_CHILD , 10,10,261,90, hwndMain, NULL, hInst, NULL);
   ShowWindow(hwndButtonHide,SW_SHOW), UpdateWindow(hwndButtonHide);
hwndButtonEditFilter=CreateWindow("BUTTON","Edit filters", WS_VISIBLE|WS_CHILD|WS_BORDER|WS_TABSTOP , 10,110,261,30, hwndMain, NULL, hInst, NULL);
   ShowWindow(hwndButtonEditFilter,SW_SHOW), UpdateWindow(hwndButtonEditFilter);


Наконец, показываем главное окно
ShowWindow(hwndMain,SW_SHOW), UpdateWindow(hwndMain);

Примечание: Так как кто-то этого может не знать, хочу отметить, что в языке С++ есть "операция следования" - запятая. Т.е. просто последовательно выполнятся обе функции ShowWindow и UpdateWindow (как отдельный блок). В вышеуказанной строке можно было бы и просто поставить ";", а вообще иногда это помогает избавиться от огромного количества фигурных скобок {}, в тексте программы.

* Затем регистрируем в системе HotKeys. Они будут привязаны к главному окну, которому будут передаватся сообщения WM_HOTKEY.
RegisterHotKey(hwndMain,HOTKEYHIDE,MOD_CONTROL,VK_F12)
RegisterHotKey(hwndMain,HOTKEYSHOW,MOD_CONTROL,VK_F10)


* Затем считываем настройки из файла и запускаем главный цикл обработки оконных сообщений для текущего процесса.
   MSG msg;
   while(GetMessage(&msg,NULL,0,0)) TranslateMessage(&msg), DispatchMessage(&msg);

Оконная процедура


// Тут все довольно стандартно. Делаем  switch (msg).
// ...
case WM_HOTKEY:
    if (HOTKEYSHOW == (int)wParam)
    // показываем все, что мы до этого прятали, а так же главное
    // окно программы
      ShowAll(), ShowWindow(hwnd,SW_SHOW);

    if (HOTKEYHIDE == (int)wParam)
    // Скрываем наше главное окно и запускаем перебор всех окон в
    // системе - EnumWindows. Теперь будет вызываться функция
    // my_EnumWindowsProc для каждого обнаруженного в системе окна.
      ShowWindow(hwnd,SW_HIDE), EnumWindows((int (__stdcall *)(struct
                               HWND__ *,long))my_EnumWindowsProc, 0);
    break;
// ...

// Если программу пытаются минимизировать, просто скрываем ее
// .........................
  case WM_SYSCOMMAND:
    if(SC_MINIMIZE == wParam) { ShowWindow(hwnd,SW_HIDE); return 0; }
    break;       
    // Внимание, после ShowWindow(hwnd,SW_HIDE) мы пишем return 0,
    // вместо break. Почему? Да потому что не хотим, чтобы это
    // сообщение пошло дальше в систему. Мы его уже обработали
    // по-своему.
// ...
// А затем обрабатываем нажатия на кнопки.
    case BN_CLICKED: 
      if (hwndButtonHide==(HWND)lParam)ShowWindow(hwndMain,SW_HIDE);
      if (hwndButtonEditFilter==(HWND)lParam)ShellExecute(NULL,"open",
                      szFilterStringsFile,NULL,NULL,SW_SHOWMAXIMIZED);
      break;

Рассмотрим функцию my_EnumWindowsProc


Пропустим все невидимые окна
   if (!IsWindowVisible(hwnd)) return TRUE;

Получим TITLE очередного окна
   GetWindowText(hwnd, szWindowsTitle, SSZZ)

Затем перебираем все стоки из файла настроек

  for(i=0;i<MAXFIL;i++)
    if (FilterStrings[i]) // если это начало строки, то
    {
     if (Contain(szWindowsTitle, FilterStrings+i)) HideNext(hwnd);
     // скроем окно, если эта строка содержится в szWindowsTitle
     while(FilterStrings[i]) i++;
     // сместим указатель на следующий 0
    }

Продолжаем дальнейший перебор окон

return TRUE;

(Если бы было return FALSE, перебор бы закончился.)

В остальных функциях особо описывать нечего.


Underground InformatioN Center

Другие разделы
C, C++
Java
PHP
VBasic, VBS
Delphi и Pascal
Новое в разделе
Базы данных
Общие вопросы
Теория программирования и алгоритмы
JavaScript и DHTML
Perl
Python
Active Server Pages
Программирование под Windows
I2R-Журналы
I2R Business
I2R Web Creation
I2R Computer
рассылки библиотеки +
И2Р Программы
Всё о Windows
Программирование
Софт
Мир Linux
Галерея Попова
Каталог I2R
Партнеры
Amicus Studio
NunDesign
Горящие путевки, идеи путешествийMegaTIS.Ru

2000-2008 г.   
Все авторские права соблюдены.
Rambler's Top100