2017-02-10 2 views
0

Я искал создание пользовательского элемента управления с помощью WinApi для моего приложения, и я создал класс, который содержит функции CustomDialogProc и CreateWindowEx и RegisterClass().Do CustomDialogProc должен быть статичным. WinAPI

Я могу установить контрольную точку внутри CustomDialogProc, и она попадает, поэтому класс зарегистрирован правильно.

Однако, я должен объявить функцию CustomDialogProc как статические INT он заголовок моего класса

static LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam); 

Если я не ставлю его статичным, я получаю ошибку

Error C3867 'CustomControl::CustomDialogProc': non-standard syntax; use '&' to create a pointer to member 

И.С. это необходимо, это требует, чтобы все мои элементы управления, созданные в этом элементе управления, также были статическими. Что делать, если я хочу несколько экземпляров этого элемента управления? Как я могу обойти это? Основной MsgProc не является статической функцией. Также нет UpDownDialogProc в первой ссылке, приведенной ниже

Ниже приведен мой код для CustomControl.h, если кому-то это понадобится. Соединенный из кода находится по адресу: https://msdn.microsoft.com/en-us/library/windows/desktop/hh298353(v=vs.85).aspx https://www.codeproject.com/Articles/485767/True-Windows-control-subclassing

Спасибо,

#pragma once 
#include <windows.h> 

#include <commctrl.h> 

#pragma comment(lib, "comctl32.lib") 

class CustomControl 
{ 
public: 
    CustomControl(); 
    ~CustomControl(); 

    LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam) 
    { 
     switch (message) 
     { 
      case WM_CREATE: 
      //DO STUFF HERE 
      break; 
     } 
    } 

    bool CreateControl(HWND hwnd, HINSTANCE* m_hApp_instance) 
    { 
     g_hInst = m_hApp_instance; 

     RegisterSubClass(*g_hInst, WC_LISTBOX, TEXT("CustomControl"), CustomDialogProc); 

     HWND hwndCustom = CreateWindow(TEXT("CustomControl"), NULL, WS_CHILD | WS_VISIBLE, 
     0, 0, 0, 0, hwnd, (HMENU)100, *g_hInst, NULL); 

     return true; 
    } 

private: 

    HINSTANCE* g_hInst; 

    WNDPROC RegisterSubClass(HINSTANCE hInstance, LPCTSTR ParentClass, LPCTSTR ChildClassName, WNDPROC ChildProc) { 
     WNDCLASSEX twoWayStruct; 
     WNDPROC  parentWndProc; 

     if (GetClassInfoEx(NULL, ParentClass, &twoWayStruct)) { 
      parentWndProc = twoWayStruct.lpfnWndProc; // save the original message handler 

      twoWayStruct.cbSize = sizeof(WNDCLASSEX); // does not always get filled properly 
      twoWayStruct.hInstance = hInstance; 
      twoWayStruct.lpszClassName = ChildClassName; 
      twoWayStruct.lpfnWndProc = ChildProc; 

      /* Register the window class, and if it fails return 0 */ 
      if (RegisterClassEx(&twoWayStruct)) 
       return parentWndProc; // returns the parent class WndProc pointer; 
             // subclass MUST call it instead of DefWindowProc(); 
             // if you do not save it, this function is wasted 
     } 
     return 0; 
    } 
}; 
+0

DialogProcs (и аналогичные обратные вызовы) не могут быть нестационарными функциями-членами, поскольку их необходимо передать API-интерфейсам C, которые не понимают таких вещей. –

+1

Поскольку у вас установлена ​​Visual Studio, вы должны прочитать исходный код MFC. Это одна из немногих реализаций, которые получают это право (в принятом ответе нет). – IInspectable

+0

Честно говоря, написание хорошей оболочки Windows API - это работа на полный рабочий день. Это не то, что можно легко ударить. API достаточно сложный со всеми видами завихрений и поворотов, и если вы не знаете C++ достаточно (достаточно, чтобы быть хотя бы близко к продвинутому уровню), это само по себе является препятствием для поднятия. – PaulMcKenzie

ответ

2

Наиболее распространенным способом является использование SetWindowLongPtr хранить указатель на объект, связанный с оконной ручки.

HWND hWnd = CreateWindow(...); 
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) this); 

А затем в диалоговом прок, получить этот указатель и вызовите в своем классе:

// this static method is registered with your window class 
static LRESULT CALLBACK CustomDialogProcStatic(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam) 
{ 
    auto pThis = (CustomControl*) GetWindowLongPtr(hWnd, GWLP_USERDATA); 
    if (pThis != NULL) 
     return pThis->CustomDialogProcInstance(hWnd, uMsg, wParam, lParam); 
    return DefWindowProc(hWnd, uMsg, wParam, lParam); 
} 

// this instance method is called by the static method 
LRESULT CustomDialogProcInstance(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    ... 
} 

Убедитесь, что вы управлять окна и класс жизненного цикла надлежащим образом, чтобы предотвратить окно прок от вызова вырезанного объект. Во многих случаях это так же просто, как вызывать DestroyWindow, если ваш класс разрушен.

+0

Спасибо, я попытаюсь понять это, прежде чем отмечу его как ответ – Mich

+0

Я попробовал его и скомпилировал, но в строке: auto pThis = (CustomControl *) GetWindowLongPtr (hWnd, GWLP_USERDATA); pThis всегда NULL – Mich

+0

@ Kenneth - потому что вы не вызываете 'SetWindowLongPtr (hWnd, GWLP_USERDATA, (LONG_PTR) this);' – RbMm

0

Windows API - это C язык. Он ничего не знает о C++, не-статические функции, объекты и т.д.

Так что да, все ваши функции, которые будут взаимодействовать с Windows API, непосредственнодолжны бытьstatic функции-члены класса, или внеклассовой/global/"free".

Это не мешает вам написать обертку C++ для API C. Вот что делают библиотеки, такие как Microsoft MFC или старые библиотеки Borland OWL. Другие независимые группы также написали обертки для Windows API.

Обратите внимание, что эти разные библиотеки достигают цели подключения API на основе C к C++ по-разному. Один из них - использовать метод SetWindowLongPtr, упомянутый в ответе @MichaelGunter. Другим методом является использование карт для связывания оконных ручек и статических процедур Window.

Я бы предложил, прежде чем попробовать это самостоятельно (создав обертку), вы исследуете, как это уже сделали другие, и выберите наилучший подход, который подходит. Еще одно предположение заключается в том, что перед созданием обертки вы должны знать API, основанный на C, на гораздо большем, чем беглый уровень. Вам необходимо перейти к экспертным знаниям любого API C, который вы планируете создать обертку C++, если вы хотите, чтобы обертка работала относительно безупречно в разных сценариях.

Смежные вопросы