Сообщений 25    Оценка 90 [+1/-0]         Оценить  
Система Orphus

Библиотека XWPL – Extreme Windows Programming Library

Автор: Роман Акопов
Опубликовано: 11.11.2002
Исправлено: 15.04.2009
Версия текста: 1.1.1

Зачем всё это нужно?
Как начать?
Правила именования
Краткий обзор основных макросов
Краткий обзор основных функций
Краткий обзор основных классов
Общий обзор, первая программа
Работа с памятью
Ну и напоследок

Исходники библиотеки
Сайт проекта

Зачем всё это нужно?

На самом деле это довольно сложный вопрос. В начале (а прошёл уже год более или, скорее, менее активной работы) это был метод что-то доказать себе, нежели желание принести пользу. Не знаю, наверное, это болезнь всех, кто начинал на медленных машинах (80286), желание оптимизировать… Помню как мне слегка (и это не преуменьшение) не понравилась стандартная библиотека Borland Pascal 7.0, и я полностью переписал её всю (CRT, Graph, DOS + свои модули) на ассемблере. Ну вот, с тех пор и страдаю болезнью замены Run-Time Libraries :)

Начиналась писаться XWPL ещё на 6-й студии. Но потом плавно перетекла под седьмую. Правда, совместимость не потеряна. Если всё же что-то не скомпилируется на 6-й - сообщите, перепишу. Со временем библиотека обросла классами, функциями, и теперь стала довольно большой по размеру и, даже полезной. Кому она нужна? Я вот сейчас с её помощью пишу GUI приложения, сервисы, консольные пока не выйдут, но и это в планах. Но кроме оконных, она содержит, и кучу других, не менее полезных, классов. XWPL писалась так, чтобы при необходимости любой её класс или функцию можно было использовать независимо от остальных.

Как начать?

Подключите проект XWPL и добавьте в нужное место

#include "xwpl.h"

Ну вот вроде и всё :) Да, для тех, кто не знает, можно указывать относительные пути:

#include "..\xwpl\xwpl.h"

Правила именования

Названия структур - полностью из прописных букв. Между словами подчерк. Названия полей - каждое слово с прописной буквы, первое со строчной буквы.

typedef struct _STRUCT_NAME_TAG_
 {
  TYPE memberName;
 } STRUCT_NAME, * LPC_STRUCT_NAME;

Названия классов - каждое слово с прописной буквы с префиксом C_. Этот префикс продуман специально под технологию IntelliSence, чтобы, набрав его и нажав Ctrl+Пробел можно было получить названия всех классов. Использовать буквенные префиксы (вроде gl) не хотелось. Названия полей - каждое слово с прописной буквы, первое с строчной. Названия методов - каждое слово с прописной буквы. Исключение это методы обёртки вызовов функции SendMessage для оконных классов. Их названия начинаются с префикса sm_ и состоят только из строчных букв.

typedef class _CClassName_tag_
 {
  public:
   TYPE memberName;
  private:
   RET_TYPE1 MemberFunction(PARAM_TYPE paramaterName);
   RET_TYPE2 sm_messagename(MESSAGE_PARAM_TYPE messageParamType);
 } C_ClassName, * LPC_ClassName;

Краткий обзор основных макросов

Отладочный макрос. Единственный параметр - истинное в нормальной ситуации выражение.

DEBUG_CHECK

Макросы работы со строками. Конвертирование строк. C_Str соответствует классу C_StringA или C_StringW в зависимости от того ANSI или UNICODE сборка.

STR_A_TO_T
STR_W_TO_T
STR_T_TO_W
STR_T_TO_A
STR_A_TO_T_LEN
STR_W_TO_T_LEN
STR_T_TO_W_LEN
STR_T_TO_A_LEN
C_Str

Краткий обзор основных функций

Функции для работы с памятью. Пока транслируются в Heap***. Но в будущем это должно измениться. Предполагается наличие собственного менеджера кучи.

memInitialize
memFinalize
memAlloc
memRealloc
memFree
memSize

Функции для работы со строками. Все перегружены и имеют ANSI и UNICODE версию. Функции конвертирования имеют четыре версии ANSI->ANSI, ANSI->UNICODE, UNICODE->ANSI, UNICODE->UNICODE. Большинство функций транслируются в вызовы функций API lstr***. В любом случае это вспомогательные функции (что видно по подчерку в начале названия) и в обычной практике рекомендуется использовать класс C_String.

_str_convert
_str_convert_len
_str_convert_len
_str_convert_char
_str_len
_str_load
_str_cat
_str_copy
_str_lower
_str_upper
_str_comp
_str_compi

Краткий обзор основных классов

Обёртки для объектов синхронизации.

C_Event
C_Mutex
C_Semaphore

Обертка для работы с реестром.

C_Registry

Класс типизированного буфера с автоматическим освобождением памяти.

C_AutoPtr

Парсер математических выражений (пока в разработке). Используется стековый алгоритм Бауэра - Земельзона.

C_MathParser

Шаблоны структур данных (пока в разработке).

C_Stack
C_Queue
C_HashElement
C_SortedHash

Шаблон строки (пока в разработке). Определены классы C_StringA и C_StringW для ANSI и UNICODE строк соответственно.

C_String

Обёртки для соответствующих структур (есть проблемы с конструкторами C_Variant).

C_Variant
C_SafeArray
C_Decimal
C_Currency

Совместимые с OLE потоки для работы с файлами и pipe-ами.

C_StreamFile
C_StreamFileMapping
C_StreamPipe

Классы для GDI графики.

C_Desktop
C_DC
C_Font

Обёртки для меню и окна.

C_Menu
C_Window

Обёртки простых контролов.

C_Button
C_ComboBox
C_Edit
C_ListBox
C_Static
C_RichEdit

И продвинутых.

C_Animation
C_ComboBoxEx
C_DateTimePicker
C_DragListBox
C_FlatScrollBar
C_ImageList
C_IpAddress
C_ListView
C_Pager
C_ProgressBar
C_PropertySheet
C_Rebar
C_StatusBar
C_Tab
C_Toolbar
C_Tooltip
C_TreeView

Обёртки диалогов открытия и сохранения файлов.

C_OpenFileName
C_SaveFileName

Обёртки для иконок в системном трее и Active Desktop (пока в разработке).

C_NotifyIcon
C_ActiveDestop

Окно с картой сообщений. Реализация сильно отличается от MFC-шной.

C_AdvancedWindow

Классы для работы с сетью. Почему нет C_UdpSocket? Руки пока не дошли. C_TcpIpSocket кстати говоря, совместим с ISequentialStream.

CNetwork - уже созданный объект. По смыслу его не нужно больше чем один.

C_TcpIpSocket
CNetwork

Универсальное, не типизированное хранилище табличных данных. Тип указывается как параметр столбца в виде переменной типа VARTYPE (константы VT_***). Работа на уровне двоичных буферов.

C_DataColumn
C_DataGrid

ODBC интерфейс к базам данных. Результаты запросов (если есть) записываются в C_DataGrid.

C_ODBC
C_ODBCConnection
C_ODBCSQLStatement

Обёртки для потоков, процессов и модулей. CApplication - уже созданный объект. По смыслу его не нужно больше чем один.

C_Thread
C_Process
C_Module
CApplication

Общий обзор, первая программа

ПРЕДУПРЕЖДЕНИЕ

Библиотека XWPL использует свою версию CRT которая пока не поддерживает SEH/C++ exceptions, но я сейчас этим занят и вы можете помочь мне это реализовать.

Для начала, надо сказать, что подключить XWPL к уже готовому проекту не очень просто. Входная процедура для вас XWPLMain. Переименуйте ваш WinMain в XWPLMain (параметры немного другие, но смысл сохранён) и решите много проблем. В любом случае я бы хотел начать с простого приложения ориентированного только на XWPL. Итак.

// 
#include "..\xwpl\xwpl.h"
// Класс главного окна
xwpl::C_AdvancedWindow CWindowMain;
// Класс окна RichEdit в котором можно вводить текст
xwpl::C_RichEdit       CRichEdit;
// Обработчик попытки закрытия окна
LRESULT CALLBACK OnClose(HWND hWnd,WPARAM wParam,LPARAM lParam)
 {
  DestroyWindow(hWnd);
  PostQuitMessage(0);
  return 0;
 }
// Обработчик попытки использовать контекстное меню
LRESULT CALLBACK OnMenu(HWND hWnd,WPARAM wParam,LPARAM lParam)
 {
  // Local variables
  // Окно у которого фокус
  xwpl::C_Window CWindow(GetFocus());
  // Code
  // послать окну у которого фокус соответствующее сообщение
  if (LOWORD(wParam) == STD_STRID_EDIT_CUT)
   {
    CWindow.sm_cut();
   }
  if (LOWORD(wParam) == STD_STRID_EDIT_COPY)
   {
    CWindow.sm_copy();
   }
  if (LOWORD(wParam) == STD_STRID_EDIT_PASTE)
   {
    CWindow.sm_paste();
   }
  return 0;
 }
// Обработчик события клика мышью на ссылке. Ссылкой становиться любой текст введённый в RichEdit 
// если он имеет нужный формат. Например http://xwpl.narod.ru
LRESULT CALLBACK OnNotify(HWND hWnd,WPARAM wParam,LPARAM lParam)
 {
  // Класс автоматического рапределения памяти
  xwpl::C_AutoPtr<TCHAR,MAX_PATH> CLinkText;
  TEXTRANGE tr;
  // Если нужное действие (отпустили левую кнопку)
  if (((ENLINK *)lParam)->msg != WM_LBUTTONUP)
   {
    return 0;
   }
  // Получить текст ссылки
  tr.lpstrText = (LPTSTR)CLinkText;
  tr.chrg = ((ENLINK *)lParam)->chrg;
  xwpl::C_RichEdit CRichEdit(((ENLINK *)lParam)->nmhdr.hwndFrom);
  CRichEdit.sm_gettextrange(&tr);
  // И открыть в эксплорере
  ShellExecute(NULL,T("OPEN"),T("iexplore.exe"),(LPTSTR)CLinkText,NULL,SW_SHOW);
  return 0;
 }
//
int XWPLMain(HINSTANCE hInstance,C_Str CStrCommandLine,int nCmdShow)
 {
  // Пременная класса окна
  WNDCLASSEX wce;
  // Обнулить переменную
  ZeroMemory(&wce,sizeof(wce));
  // Задний фон - обычный
  wce.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  // Зарегистрировали класс. Имя класса создано автоматически.
  ATOM classAtom = CWindowMain.RegisterClass(&wce);
  // Начать регистрировать обработчики сообщений
  XWPL_MSGMAP_BEGIN(classAtom)
  // Зарегистрировать обработчики сообщений для оконного класса
  XWPL_MSGMAP_MESSAGE(OnClose,WM_CLOSE)
  XWPL_MSGMAP_MENU_ID(OnMenu,STD_STRID_EDIT_CUT);
  XWPL_MSGMAP_MENU_ID(OnMenu,STD_STRID_EDIT_COPY);
  XWPL_MSGMAP_MENU_ID(OnMenu,STD_STRID_EDIT_PASTE);
  XWPL_MSGMAP_NOTIFY_MESSAGE(OnNotify,EN_LINK);
  // Закончить регистрировать обработчики сообщений
  XWPL_MSGMAP_END
  // Создать окно
  CWindowMain.CreateAdvancedWindow(0,T("caption"),WS_CAPTION|WS_SIZEBOX|WS_SYSMENU,0,0,550,550,NULL);
  // Создать дочернее окно
  CRichEdit.CreateRichEdit(0,NULL,WS_CHILD|WS_BORDER|WS_VSCROLL|ES_MULTILINE,10,10,530,500,CWindowMain);
  // Показать дочернее окно
  CRichEdit.ShowWindow(SW_SHOWNORMAL);
  CRichEdit.UpdateWindow();
  // Установить обработчик OLE запросов по умолчанию. Теперь в RichEdit можно вставлять картинки и другие объекты.
  CRichEdit.sm_setolecallback(XWPL_RICHEDIT_CALLBACK_DEFAULT);
  // Включить автоматическое распознавание адресов типа URL и преобразование их в ссылки
  CRichEdit.sm_autourldetect(TRUE);
  // Включить оповещение родительского окна прии операциях над ссылками.
  CRichEdit.sm_seteventmask(ENM_LINK);
  // Запустить главный цикл окна. Первы параметр типа ACCEL – клавишный ускоритель, 
  // второй HWND окна с классом MDICLIENT или NULL если приложение не имеет MDI интерфейса.
  return xwpl::CApplication.RunMessageLoop(NULL,NULL);
 }
//
// end of file
// 

Работа с памятью

Её нужно выделять и освобождать. Как? Просто!

// Выделили память, 100 байтов, изначально заполненных нулями.
// Сколько реально выделилось памяти так, сразу, не известо.
LPVOID lpPointer = memAlloc(100);
//
if (lpPointer == NULL)
 {
  // Если не выделилось...
 }
// Но можно узнать вот так, меньше чем 100 (заказанный размер) в любом случае не выделится.
UINT   realSize = memSize(lpPointer);
// А вот нам понадобилось ещё 150 байт, итого 250 байт. Остаток (последние 150 байт) инициализированы нулями. 
// Первые 100 имеют старые значения. 
LPVOID lpPointerNew = memRealloc(lpPointer,250);
// Если не выделилось дополнительные 150 байт
if (lpPointerNew == NULL)
 {
  // то
 }
else
 {
  lpPointer = lpPointreNew;
 }
// Ну и освободим память.
memFree(lpPointer);
//
{
 // Локальная переменная, типизированный буфер. Первый параметр шаблона - тип содержимого
 // второй параметр – количество элементов. То есть в нашем случае реально выделенное 
 // количество байт не меньше 1024*sizeof(TCHAR). Выделенная память инициализируется нулями.
 C_AutoPtr<TCHAR,1024> CStrPtr;
 // Если память не выделилась, то debug версия орёт об этом во всё горло, а release просто запишет NULL.
 // Есть два перегруженных оператора UINT и TYPE * возвращающие количество элементов и адрес блока памяти с данными.
 ZeroMemory(CStrPtr,CStrPtr); // Это лишнее – память и так обнулена
 // Возможности изменить количество выделенной памяти нельзя.
 // А память освободится здесь, в деструкторе, при выходе из зоны видимости.
}

Ну и напоследок

Как вы уже успели заметить - здесь всё ещё в стадии разработки. Если кто хочет помочь - милости просим! Если есть замечания, дополнения, идеи, наработки, ну или если вы считаете, что здесь всё неправильно и можете это обосновать - пишите.

СОВЕТ

Вы вполне можете использовать мой почтовый адрес в качестве простейшей поддержки. Если есть вопросы или проблемы пишите обязательно. Ваши письма – материал для улучшения библиотеки.

В исходниках библиотеки есть файл changes.txt. В нём есть полезная информация.

Огромное спасибо всем тем, кто отвечал на мои вопросы с форумах. По информативности MSDN-у до RSDN-на еще плыть и плыть.

ПРЕДУПРЕЖДЕНИЕ

Windows торговая марка Microsoft.

IntelliSence тоже, наверное, кто-то зарегистрировал.

Хотя XWPL и не является зарегистрированной торговой маркой, я всё же обижусь, если кто-то сознательно будет прикрываться этим именем. Ребята, давайте жить дружно.


Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
    Сообщений 25    Оценка 90 [+1/-0]         Оценить