| 
			| 
					
						| Peacedeath 
								Интересующийся    Offline | 
								|  | «  : 29-03-2011 12:54 »  |  | 
 
 Объясните начинающему... Хочу создать класс, в котором будет диалог созданный с помощью CreateDialog. Функции класса будут функции работы с полем РичЕдит в этом диалоге, а также приватные поля...  (Собственно кусок код) class MyClass{
 HWND hwndWin;
 HINSTANCE hInst;
 
 BOOL CALLBACK GoToProc(HWND, UINT, WPARAM, LPARAM);
 int ChooseColor();
 
 public:
 MyClass(HINSTANCE);
 ~MyClass();
 int Put(char *);
 };
 
 
 MyClass::MyClass(HINSTANCE hInstance)
 {
 hInst = hInstance;
 char lpszBuf[80];
 
 if (!IsWindow(hwndWin))
 {
 hwndWin = CreateDialog( hInst, "IDD_DLG", NULL, (DLGPROC)GoToProc );
 if (!hwndWin)
 {
 FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),LANG_SYSTEM_DEFAULT,lpszBuf,80,NULL );
 MessageBox( NULL, lpszBuf, "Ошибка", MB_OK | MB_ICONWARNING );
 }
 }
 };
 
 MyClass::~MyClass()
 {
 DestroyWindow(hwndWin);
 hwndWin = NULL;
 };
 
 BOOL CALLBACK MyClass::GoToProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 {
 switch (message)
 {
 case WM_INITDIALOG:
 {
 ShowWindow( hDlg, SW_SHOW );
 return TRUE;
 }
 case WM_COMMAND:
 switch ( LOWORD(wParam) )
 {
 case IDCANCEL:
 ShowWindow( hDlg, FALSE );
 return FALSE;
 case IDB_TLIGHT:
 ChooseColor();
 return FALSE;
 }
 return FALSE;
 }
 return FALSE;
 };
 
 int MyClass::ChooseColor() {return 0};
 
 int MyClass::Put(char *st)
 {
 SETTEXTEX param;
 param.flags = ST_DEFAULT | ST_SELECTION;
 param.codepage = CP_ACP;
 if (!SendMessage(GetDlgItem(hwndWin, IDC_REDIT1), EM_SETTEXTEX, (WPARAM)¶m, (LPARAM)st));
 return 0;
 }
А теперь вопросы:  1. Как создать класс не используя статическую CALLBACK функцию диалога, что бы можно было создавать несколько экземпляров данного класса?  2. Если я создаю статическую CALLBACK функцию диалогового окна в классе (иначе если CALLBACK функция мембер - CreateDialog ругается "приведение типов: невозможно преобразовать 'overloaded-function' в 'DLGPROC' "), диалог создается, но при попытке обратиться из CALLBACK функции к другому члену класса, ругается "MyClass::ChooseColorA: недопустимый вызов нестатической функции-члена ". Почему так и как это решить? P.S. Выслушаю любую критику и советы, но хотелось бы получить ответы на свои вопросы.    |  
						| 
								|  |  
								| « Последнее редактирование: 29-03-2011 13:41 от Джон » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #1 : 29-03-2011 13:26 »  |  | 
 
 Peacedeath, а чем тебя не устраивает статическая функция? В ней нет ничего специфического для экземпляра класса, за исключением ChooseColor.
 В WinAPI передать метод объекта нельзя. Ведь для вызова метода внутри WinAPI должен быть известен сам объект, метод которого вызывают. А эта информация не передаётся вместе с указателем на функцию-член.
 
 Поэтому тут два пути:
 
 1) Если получится, накрутить при помощи шаблонов или чего-нибудь в этом духе упаковку объекта с методом в функцию - т.е. создать функтор. Но не функтор в смысле STL - там всё же при помощи шаблонов модифицируются алгоритмы, если я правильно это понимаю.
 
 2) Завести статическое поле типа map, в котором хранить пары: ключ - HWND hDlg и значение - указатель на объект. Тогда твой статический метод по hDlg всегда сможет достать нужный объект и вызвать его метод.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Peacedeath 
								Интересующийся    Offline | 
								|  | « Ответ #2 : 30-03-2011 05:44 »  |  | 
 
 А если я захочу создать несколько экземляров этого класса, и в кажом будет окно со своей процедурой обработки событий... где то я видел, что со статическими функциями класса такое не прокатит.... Или я не прав? |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #3 : 30-03-2011 07:51 »  |  | 
 
 Peacedeath, если экземпляр класса, с которым работает статическая функция, каждый раз разный, то не вижу никаких проблем. Не прокатит, только если у тебя и сам экземпляр один и статический (singleton, то есть). |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #4 : 30-03-2011 08:55 »  |  | 
 
 Peacedeath, конечно, ты можешь написать несколько классов типа того, который ты привёл - если количество экземпляров фиксировано и в runtime не меняется. Такие вещи удобно делать через шаблоны, чтобы не делать copy-paste кода. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Peacedeath 
								Интересующийся    Offline | 
								|  | « Ответ #5 : 30-03-2011 10:12 »  |  | 
 
 Когда я сделал функции статическими, появились сообщения "недопустимая ссылка на нестатический член 'MyClass::hwndWin'" . Когда я сделал статическими HWND hwndWin и HINSTANCE hInst, появились ошибки "неразрешенный внешний символ ""private: static struct HWND__ * MyClass::hwndWin" (?hwndWin@MyClass@@0PAUHWND__@@A)""  и такая же для hInst. Что я делаю не так? Может есть какая то литература по написанию таких классов??    |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #6 : 30-03-2011 14:54 »  |  | 
 
 Peacedeath, ты объявляешь эти члены private. Такие члены закрыты для внешнего доступа. Когда ты передаёшь свой callback внутрь WinAPI, то WinAPI по отношению к твоему классу, естественно, находится "снаружи" и поэтому не может "видеть" private полей.
 Насколько я знаю, нет литературы по написанию таких классов. Поскольку на WinAPI пишет подавляющее меньшинство программистов, а задача у тебя специфическая. Фактически ты пытаешься сделать то, что уже давно реализовано в любой объектной библиотеке-обёртке над WinAPI - книжек по устройству библиотек не пишут (хотя бы и из соображений контроля технологий), пишут руководства по их использованию.
 |  
						| 
								|  |  
								| « Последнее редактирование: 30-03-2011 14:56 от Dimka » |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Peacedeath 
								Интересующийся    Offline | 
								|  | « Ответ #7 : 01-04-2011 09:21 »  |  | 
 
 Перенес вообще все в public. Ничего не изменилось, такая же ошибка, только вместо private - public. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #8 : 01-04-2011 10:22 »  |  | 
 
 а вот так class MyClass{
 static  HWND hwndWin;
 };
 
 HWND MyClass::hwndWin=0;
 
 ...
 ...
 
 |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #9 : 01-04-2011 11:33 »  |  | 
 
 Алексей1153++, а смысл? Если потребуется несколько экземпляров? 
 Я считаю, полезно будет посмотреть, как это в WTL/ATL/MFC сделано, и не изобретать велосипед.
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Peacedeath 
								Интересующийся    Offline | 
								|  | « Ответ #10 : 01-04-2011 12:22 »  |  | 
 
 Алексей1153++, а смысл? Если потребуется несколько экземпляров? 
 да, именно несколько  экземляров. а как глянуть это в WTL/ATL/MFC ? |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #11 : 01-04-2011 16:03 »  |  | 
 
 Вад, я только ответил на часть с "неразрешенный внешний символ"
 а про мап уже Димка сказал
 
 Добавлено через 5 минут и 24 секунды:
 Вад, как это в WTL/ATL/MFC сделано - понятия не имею, но лично я делал через статический мап (вернее - два, взаимодополняющих)
 
 std::map<HWND, WndPROC> m_HWND_PROC;
 std::map<WndPROC, HWND> m_PROC_HWND;
 
 изменяются строго одновременно. Если есть многопоточность - ввести синхронизацию
 |  
						| 
								|  |  
								| « Последнее редактирование: 01-04-2011 16:08 от Алексей1153 » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #12 : 02-04-2011 08:45 »  |  | 
 
 Peacedeath, исходники ATL, на котором нынче построены и WTL, и MFC, доступны в Visual Studio (хотя бы потому, что там шаблоны). Можно изучать. Смотреть надо где-то в районе CDialog или CDialogImpl - точно не помню, где там корни всего.  |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #13 : 02-04-2011 16:28 »  |  | 
 
 Вад, скорее в районе CWnd |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Chaa | 
								|  | « Ответ #14 : 04-04-2011 08:29 »  |  | 
 
 В ATL используется довольно сложная система для получения из хэндла окна указателя на класс. Корни всего находятся в CWindow и CWndProcThunk. Если не использовать ATL, то лучше  сделать так: class MyClass{
 HWND hwndWin;
 
 static BOOL CALLBACK StaticWndProc(HWND, UINT, WPARAM, LPARAM);
 BOOL CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 
 public:
 MyClass();
 ~MyClass();
 };
 
 MyClass::MyClass()
 {
 hwndWin = CreateDialog( hInst, "IDD_DLG", NULL, (DLGPROC)StaticWndProc);
 SetWindowLongPtr(hwndWin, GWLP_USERDATA, static_cast<LONG_PTR>(this));
 };
 
 MyClass::StaticWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 {
 MyClass* pThis = static_cast<MyClass*>(GetWindowLongPtr(hDlg,
 GWLP_USERDATA));
 if (pThis) {
 return pThis->WndProc(hDlg, message, wParam, lParam);
 } else {
 return DefWindowProc(hDlg, message, wParam, lParam);
 }
 };
 
 MyClass::WndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 {
 // Можно использовать члены класса
 };
Общая идея - указатель на экземпляр класса сохраняется в пользовательском атрибуте окна - GWLP_USERDATA. При вызове оконной процедуры с помощью этого указателя вызывается метод WndProc класса. |  
						| 
								|  |  
								| « Последнее редактирование: 04-04-2011 09:10 от Chaa » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #15 :  04-04-2011 08:59 »   |  | 
 
 Chaa, крутой способ, спасибо   |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Chaa | 
								|  | « Ответ #16 : 04-04-2011 09:18 »  |  | 
 
 Немного исправил код. Дело в том, что некоторые сообщения, вроде WM_NCCREATE, будут переданы в StaticWndProc еще до вызова SetWindowLongPtr, из CreateDialog.Видимо из-за этого в ATL используется более сложная схема для связывания хэндла окна и указателя на класс.
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #17 : 04-04-2011 09:28 »  |  | 
 
 Chaa, ага, то есть ограничения начались, не всё так радужно    Да и список объектов тоже не помониторишь особо |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	|  |