« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга


ПнВтСрЧтПтСбВс
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
    Популярное
Тестировщик

Интервью со Страуструпом

Ввод данных в декларацию

Функция AccessResource

Функция PostAppMessage

Рассылка электронной почты из MS Access

Программирование запросов и ответов

Функция GlobalSize

Получение файла из сети

Драйверы - фильтры




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 147
Пользователей: 0

Статьи:: C/С++ :: C++ Builder :: Написание маленьких приложений на Borland C++ Builder



отправить ссылку другу версия для печати  Обсудить на форуме

Написание маленьких приложений на Borland C++ Builder



Натыкаясь в Интернете на довольно интересные программы, я часто не решался их закачивать после того, как узнавал их размер. Какую ни возьми - все огромные. Да и ресурсов системных потребляют немало. В этой статье я расскажу о том, как сделать программу в среднем в 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:programswinhiderwinhider.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// если это начало строки, то
    {
     if (Contain(szWindowsTitle, FilterStrings+i)) HideNext(hwnd);
     // скроем окно, если эта строка содержится в szWindowsTitle
     while(FilterStrings[i]) i++;
     // сместим указатель на следующий 0
    }

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

return TRUE;

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

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

FAQ, возникший в результате множества заданных мне вопросов.

Q: Почему программа не линкуется?

A: Попробуйте собрать не debug, а release версию. А если вам нужна возможность отладки, воспользуйтесь обычными #define. И все-таки есть еще одни вариант. В отладочной версии линкер не может собрать файл потому, что не находит "__chkesp", которая содержится в "CHKESP.OBJ". Что мы можем сделать? Да взять и заменить тот obj на свой, который будет меньше размером и не будет содержать ненужный нам код.

Q: Как теперь получить переданную командную строку?

A: Ну тут все просто. Пользуйтесь стандартными API. То же самое и для Instance приложения. Вот они - GetCommandLine, GetModuleHandle.

Q: А какой минимальный align возможен?

A: Для того, чтобы ваша программа запускалась нормально в любой версии Windows, используйте 512 байт.

Q: А можно ли делать такими маленькими DLL?

A: Да. Назначьте свою точку входа вместо _DllMainCRTStartup. Вот пример.

Q: А почему пропали функции strcmp, strlen и т.п.?

A: Так как они были реализованы в RTL, теперь вы не можете их использовать. Но это не беда. В модуле kernel есть отличная замена этим функциям. Названия те же, но с буквой "l" вначале. Например - lstrlen, lstrcmp, lstrcat.

Q: А теперь стали недоступны функции работы с памятью - memset, CopyMemory?

A: RTL сам предоставляет интефейс для работы с памятью. Во-первых, чтобы соблюдать снандарт, во-вторых, чтобы упростить работу с памятью в среде Win32. Вот посмотрите на функцию CopyMemory - она на самом деле не является настоящей API функцией. Попробуйте слинковать проект без RTL, в котором используется эта функция. Результат - неудачная попытка линковки - ссылка на _memcpy. Еще один пример - функция new. В среде Win32 вы должы воспользоваться функциями GlobalAlloc, GlobalLoc и т.п. Однако вы можете просто заменить RTL функции своими. В файле add.txt вы можете взять уже готовые функции, если не хотите писать их сами.

Q: У меня есть один вопрос, которого нет в этом FAQ, что делать?

A: В таком случае вы можете задать вопрос на нашем форуме. www.uinc.ru/forum/

Links:

Special thanks: Dr.Golova[uinC], NiFi[uinC].
[c] Copyright 2002. Украина, Запорожье.
KMiNT21 (mailto:kmint21@mail.ru).
uinC Member
[c]uinC



Рубрика: C++ Builder




Вышел MySQL 5.1.30, первый стабильный рели....

MySQL

После публикации 29 тестовых версий анонсирован первый стабильный релиз MySQL 5.1, пригодный для промышленной эксплуатации и обеспечивающий увеличение производительности для "тяжелых" SQL запросов, по сравнению с MySQL 5.0, примерно на 15-20%. Главные новшества появившиеся в MySQL 5.1:


Подробнее... | Рубрика: MySQL | Добавлено: 28.11.2008

Тестирование параллельных программ.

Тестирование

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


Подробнее... | Рубрика: Тестирование | Добавлено: 28.11.2008

Архитектура AMD64 (EM64T).

Архитектура AMD

Аннотация. В статье кратко рассматривается архитектура AMD64 компании AMD и ее реализация EM64T компании Intel. Описаны особенности архитектуры, ее возможности, достоинства и недостатки.


Подробнее... | Рубрика: Архитектура AMD | Добавлено: 27.11.2008

Остальные статьи:

Платформа 2009. Определяя будущее
Windows Vista Bridge Sample Library - упра...
Оптимизация 64-битных программ
Подгрузка через AJAX HTML-кода, содержащег...
Обзор нового релиза самой мощной Ajax библ...
Firebug 1.3 и 1.4 alpha — что нового и инт...
Релиз Microsoft Silverlight 2.0. Что новог...
XML документация в C#
Курсоры в MySQL 5
Microsoft опубликовала подробности о сесси...
Microsoft делится подробностями о том, что...
Тестируем новый javascript от нового брауз...
MySQL Query Cache
Использование провайдеров компиляции в As...
Чего мы ждем от C# 4.0
Delphi 2009 и C++Builder 2009
Джоэл Спольски и Джеф Этвуд запустили новы...
Поиск кода Google /* что нового? */
10 jQuery скриптов для улучшения интерфейс...
Генераторы отчетов FastReport 4 и QuickRep...


Цитата дня (все,добавить):

Портал фрилансеров

работа на дому


    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование


Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия