Оконная функция - ЧЛЕН КЛАССА?!
От: Anrie  
Дата: 20.04.01 21:06
Оценка:
Может ли быть оконная процедура главного окна членом класса?
Как это реализовать? Все мои попытки заканчивались сообщениями об ошибках :(
Re: Оконная функция - ЧЛЕН КЛАССА?!
От: IT Россия linq2db.com
Дата: 20.04.01 23:06
Оценка:
>Может ли быть оконная процедура главного окна членом класса?
>Как это реализовать? Все мои попытки заканчивались сообщениями об ошибках :(

Может, но только статическим, иначе ты всегда получишь первым параметром указатель на this.
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Оконная функция - ЧЛЕН КЛАССА?!
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.01 16:58
Оценка:
Здравствуйте IT, 20.04.2001 17:06:30 вы писали:

>>Может ли быть оконная процедура главного окна членом класса?

>>Как это реализовать? Все мои попытки заканчивались сообщениями об ошибках :(
>
>Может, но только статическим, иначе ты всегда получишь первым параметром указатель на this.
Это не совсем так! ATL и WTL спокойно используют для этого нормальные функции, но не напрямую, а через разные увертки и ужимки. Подробнее смотри реализацию CWindowImpl<>.
Если окно свое, то можно записать указатель на объект нужного класс в область данных окна. При этом в качестве ф-ии окна можно использовать или глобальную ф-ю или статическую. Эта ф-я вынимает адрес объекта и производит вызов нужного метода.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Оконная функция - ЧЛЕН КЛАССА?!
От: av Россия  
Дата: 24.04.01 00:39
Оценка:
>Может, но только статическим, иначе ты всегда получишь первым параметром указатель на this.

Э-э-э... А каким таким образом статическая фнукция может получать доступ к нестатическим полям? По-моему все можно сделать двумя методами. Первый (дубовый, используктся в Borland VCL и по-моему в MFC) — это написать для каждого класса свою собственную функцию (не член класса), содержащая нечто вроде:

LRESULT CALLBACK MyClassWndProc (HWND hwndWindow, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
MYCLASS* MyClass;

// за правильность констант не ручаюсь, пишу по памяти
if (uMsg == WM_CREATE) {
// присоединить к окну адрес его класса, который должен передаваться как параметр
SetWindowLong (hwndWindow, GWL_USER, lParam);
}
MyClass = (MYCLASS*) GetWindowLong (hwndWindow, GWL_USER);
MyClass->MyMethod (uMsg, wParam, lParam);
}

void MyClass::CreateWindow (...)
{
...

hwndWindow = ::CreateWindow (... ,
(LPARAM) this); // параметр созания — как раз указатель на класс
}

Второй способ — поизящнее (но я его по памяти уже не напишу, изложу только идею). Смысл прост: создается класс/структура/массив/да_неавжо_что, содержащее в себе инструкции запихивания в стек адрес класса (то есть this). После этого просто выполняется jump на метод данного класса. И тогда вместо указателя на процедуру передаем указатель на _класс_ — все остальное он сделает сам. Минус — придется повозиться с реализацией. Плюс — один объект на всю программу. Если кому сильно надо — поищу равлизацию (где-то в архивах валялась).

Вот вроде все. Если у кого винды свалятся в результате применения написнного — ногами только не бейте! :-)
Re[3]: Оконная функция - ЧЛЕН КЛАССА?!
От: deltaone  
Дата: 25.04.01 13:32
Оценка:
Здравствуйте av, 23.04.2001 18:39:40 вы писали:

>Второй способ — поизящнее (но я его по памяти уже не напишу, изложу только >идею). Смысл прост: создается класс/структура/массив/да_неавжо_что, содержащее >в себе инструкции запихивания в стек адрес класса (то есть this). После этого >просто выполняется jump на метод данного класса. И тогда вместо указателя на >процедуру передаем указатель на _класс_ — все остальное он сделает сам. Минус ->придется повозиться с реализацией. Плюс — один объект на всю программу. Если >кому сильно надо — поищу равлизацию (где-то в архивах валялась).


Если не затруднит, plz на deltaone@mail.ru
Заранее thx ;)
Re[4]: Оконная функция - ЧЛЕН КЛАССА?!
От: sluge  
Дата: 25.04.01 14:06
Оценка:
Здравствуйте deltaone, 25.04.2001 07:32:43 вы писали:

>Здравствуйте av, 23.04.2001 18:39:40 вы писали:

>
>>Второй способ — поизящнее (но я его по памяти уже не напишу, изложу только >идею). Смысл прост: создается класс/структура/массив/да_неавжо_что, содержащее >в себе инструкции запихивания в стек адрес класса (то есть this). После этого >просто выполняется jump на метод данного класса. И тогда вместо указателя на >процедуру передаем указатель на _класс_ — все остальное он сделает сам. Минус ->придется повозиться с реализацией. Плюс — один объект на всю программу. Если >кому сильно надо — поищу равлизацию (где-то в архивах валялась).
>
>Если не затруднит, plz на deltaone@mail.ru
>Заранее thx ;)
>
и плиз на форум, интересно
Re[4]: Оконная функция - ЧЛЕН КЛАССА?!
От: dimedrol haven't
Дата: 25.04.01 14:22
Оценка:
Здравствуйте deltaone, 25.04.2001 07:32:43 вы писали:

>Здравствуйте av, 23.04.2001 18:39:40 вы писали:

>
>>Второй способ — поизящнее (но я его по памяти уже не напишу, изложу только >идею). Смысл прост: создается класс/структура/массив/да_неавжо_что, содержащее >в себе инструкции запихивания в стек адрес класса (то есть this). После этого >просто выполняется jump на метод данного класса. И тогда вместо указателя на >процедуру передаем указатель на _класс_ — все остальное он сделает сам. Минус ->придется повозиться с реализацией. Плюс — один объект на всю программу. Если >кому сильно надо — поищу равлизацию (где-то в архивах валялась).
>
>Если не затруднит, plz на deltaone@mail.ru
>Заранее thx ;)
>И на dimedrol_2002@mail.ru.Заранее благодарен
Re[3]: Оконная функция - ЧЛЕН КЛАССА?!
От: ivartanov https://mvp.support.microsoft.com/profile=3317CC31-AB7A-4D36-864E-47DEFF433151
Дата: 26.04.01 18:28
Оценка:
Здравствуйте av, 23.04.2001 18:39:40 вы писали:

>Э-э-э... А каким таким образом статическая фнукция может получать доступ к нестатическим полям? По-моему все можно сделать двумя методами. Первый (дубовый,


Согласен, и его дубовость может сослужить плохую службу, поскольку GWL_USERDATA может пользоваться совершенно другой кусок кода... И тогда все просто рухнет.

>Второй способ — поизящнее


... только я что-то ничего не понял, как он работает.
Суть проблемы — статическая функция не получает this, а ей все же нужно тем или иным способом получить его. Поскольку наша оконная функция стандартным способом получает хэндл окна, для которого нужно обработать сообщение, именно его ей нужно использовать для получения указателя на объект класса, ассоциированного с данным hwnd. Следовательно, нужно иметь статический (глобальный) указатель на массив указателей на объекты и прямым поиском искать объект, связанный с полученным хэндлом окна(дубовый способ), либо иметь карту <хэндл_окна-указатель_на_объект> (изящный способ).
---
С уважением,
Игорь
Re[5]: Оконная функция - ЧЛЕН КЛАССА?!
От: av Россия  
Дата: 27.04.01 12:29
Оценка: 9 (2)
>и плиз на форум, интересно

Ну ловите, коль интересно (я так его в архивах и не нашел. Написал по новой и снабдил некоторыми комментариями)

--- TEST_CALLER.CPP -------------------------------------------------------------------
// Method caller
// Преобразовывает __stdcall (aka CALLBACK, WINAPI, etc) в thiscall.
// Created on April 26-27, 2001 by AV.
// Use free, but please уважайте копирайты! :-)

// Да, чуть не забыл: у MSVC++ и Borland C++ Builder'a разные методы вызова
// thiscall-функций (то бишь методов): MSVC++ запихивает this в ECX, а
// Builder — последним параметром в стек. В связи с этим на Builder'е для реализации
// нижеприведенного придется повозиться побольше. А пока что хочу только заметить:

// *** INCOMPATIBLE WITH C++ BUILDER! FOR USE ONLY IN MICROSOFT VISUAL C++!!! ***

// В любом случае за последствия от использования кода ответственности никакой не несу.
// Сами проверяйте! :-)

#include <windows.h>

// Итак, эдесь начинается объект Caller.
//-----------------------------------------------------------
//
// Создание и привязка: wc.lpfnWndProc = CreateCaller (wnd, CWnd::WndProc);
// Удаление: DeleteCaller (Caller);

#define CreateCaller(Class, Method) ((WNDPROC) (__CreateCaller ((void*) (Class), ConvertAnything (Method))))
#define DeleteCaller(Caller) (delete [] ((char*) (Caller)))

// Ввиду того, что C++ не разрешает casting из
// LRESULT (CClass::*_thiscall)(HWND, UINT, WPARAM, LPARAM) в void*, приходится
// извращаться. Данная функция просто возвращает первый параметр как void*, а
// многоточие (...) отключает проверку типов.

__declspec (naked) void* _cdecl ConvertAnything (...)
{
_asm {
mov eax, [esp+4] // :-)
ret
}
}

// Необходимо для отключения выравнивания переменных внутри структуры TCallerSuruct
#pragma pack (push, 1)

// Итак, собственно главная функция
char* __CreateCaller (void* Class, void* Method)
{
// Реально Caller представляет из себя две инструкции:
// mov ecx, address_of_class_instance
// jmp class_method

struct TCallerStruct {
unsigned char Mov_ECX_imm32;
void* Class_Addr;
unsigned char Jmp_rel32;
unsigned long Method_Offset;
} *Caller = (TCallerStruct*) new char [sizeof (TCallerStruct)];

// Эти две инструкции мы в него и запихиваем

Caller->Mov_ECX_imm32 = 0xB9;
Caller->Class_Addr = Class;
Caller->Jmp_rel32 = 0xE9;
Caller->Method_Offset = (unsigned long) Method — ((unsigned long)
&Caller->Method_Offset + sizeof (Caller->Method_Offset));

return (char*) Caller;
}

// Восстановить предыдущий параметр выравнивания
#pragma pack (pop)

//--------------------------------------------------------------
// Все. Дальше — простая иллюстрация работы


class CWindow {
private:
HWND hwnd; // no comments

static ATOM WClass; // класс этого окна. Один на все экземпляры, потому и static
static WNDPROC Caller; // экземпляр Caller'a. Так как один на класс, то тоже один.
static int UsageCount; // количество экземпляров данного окна. Как только оно достигает
// нуля, класс и Caller освобождаются.

public:
CWindow ();
LRESULT WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
~CWindow ();


};

ATOM CWindow::WClass = NULL;
WNDPROC CWindow::Caller = NULL;
int CWindow::UsageCount = 0;

// Итак, собственно пример использования.

CWindow::CWindow ()
{
// Если еще не создано ни одного экземпляра, надо создать класс окна.
if (!WClass) {
WNDCLASS wc;

wc.style = CS_HREDRAW | CS_VREDRAW;

// Watch this!
wc.lpfnWndProc = Caller = CreateCaller (this, WndProc);

wc.cbClsExtra = wc.cbWndExtra = 0;
wc.hInstance = (HINSTANCE) GetModuleHandle (NULL);
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW);
wc.lpszMenuName = NULL;
wc.lpszClassName = "CLASS_WIN";

// Сохраним класс
WClass = RegisterClass (&wc);
}

hwnd = CreateWindow ((LPSTR) WClass, "A Window", WS_OVERLAPPEDWINDOW, 100, 100,
400, 200,
NULL, NULL, (HINSTANCE) GetModuleHandle (NULL), NULL);

if (hwnd) {
ShowWindow (hwnd, SW_SHOW);
UpdateWindow (hwnd);

// Увеличим счетчик
UsageCount++;
}
}

CWindow::~CWindow ()
{
// Уменьшим счетчик. Если он равен нулю (окон больне не осталось), освободим
// занятые ресурсы.
if (!--UsageCount) {
UnregisterClass ((LPSTR) WClass, (HINSTANCE) GetModuleHandle (NULL));
WClass = NULL;
DeleteCaller (Caller);
}
}

// Это наша НУ ПРОСТО СУПЕР навороченная оконная процедура :-)
LRESULT CWindow::WndProc (HWND hwndWindow, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Вообще-то этого здесь не надо...
if (uMsg == WM_DESTROY)
PostQuitMessage (0);
return DefWindowProc (hwndWindow, uMsg, wParam, lParam);
}

// А теперь посмотрите на WinMain. Просто создаем экземпляр CWindow и радуемся жизни!
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
{
MSG msg;
CWindow wnd;

while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}

return msg.wParam;
}

---------------------------------------------------------------------------------------
Все замечания просьба направлять сюда и/или на av_13@imail.ru
Re[4]: Оконная функция - ЧЛЕН КЛАССА?!
От: av Россия  
Дата: 27.04.01 18:32
Оценка:
> ... только я что-то ничего не понял, как он работает.
> Суть проблемы — статическая функция не получает this, а ей все же нужно тем или иным способом получить его. Поскольку наша оконная функция стандартным способом получает хэндл окна, для которого нужно обработать сообщение, именно его ей нужно использовать для получения указателя на объект класса, ассоциированного с данным hwnd. Следовательно, нужно иметь статический (глобальный) указатель на массив указателей на объекты и прямым поиском искать объект, связанный с полученным хэндлом окна(дубовый способ), либо иметь карту <хэндл_окна-указатель_на_объект> (изящный способ).

(протяжно так) Не-е-е... Ты, в общем, source посмотри, я его тут куда-то запостил. Там hwnd для определения экземпляра не используется вообще (да и геморно это — представь себе: есть, скажем, 10 окон одного класса (хотя так не бывает), так что же, элемент твоего списка 10 раз дублировать?)
Re: Оконная функция - ЧЛЕН КЛАССА?!
От: AIDS Великобритания  
Дата: 04.05.01 02:41
Оценка:
Здравствуйте Anrie, 20.04.2001 15:06:08 вы писали:

>Может ли быть оконная процедура главного окна членом класса?

>Как это реализовать? Все мои попытки заканчивались сообщениями об ошибках :(

Может если она объявлена как статическая.
Re[6]: Оконная функция - ЧЛЕН КЛАССА?!
От: Игорь Ткачёв Россия linq2db.com
Дата: 07.05.01 05:51
Оценка:
Кажется вот здесь про это было http://www.rsdn.ru/article/?wtl/wtl-1.xml
Автор(ы): Александр Шаргин
Дата: 21.04.2001

Первая часть статьи посвящена основам WTL. Автор даёт краткий обзор WTL, описывает процесс её установки, а затем объясняет базовые средства поддержки оконного интерфейса: иерархию оконных классов, циклы сообщений и карты сообщений.
Если нам не помогут, то мы тоже никого не пощадим.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.