Конференция "WinAPI" » Как принять сообщения в класс без окна?
 
  • dmk © (21.03.17 22:54) [0]
    У меня есть такой вариант, но он работает только вне класса:

    function ClientWindowProc(wnd: HWND; msg: cardinal; wparam, lparam: integer): integer; stdcall;
    var
     P: pointer;
     Style: dword;
     ExStyle: dword;

    begin
     P := Pointer(GetWindowLong(wnd, GWL_USERDATA));

     case msg of
     WM_NCCALCSIZE:
     begin
       Style := GetWindowLong(wnd, GWL_STYLE);
       ExStyle := GetWindowLong(wnd, GWL_EXSTYLE);

       //Убираем скроллы MDI-окна
       if (Style and (WS_HSCROLL or WS_VSCROLL)) <> 0 then
       begin
         Style := Style and not (WS_HSCROLL or WS_VSCROLL);
         SetWindowLong(wnd, GWL_STYLE, Style);
       end;

       //Убираем выступ в клиентской области MDI-окна
       if (ExStyle and (WS_EX_CLIENTEDGE)) <> 0 then
       begin
         ExStyle := (ExStyle and not WS_EX_CLIENTEDGE);
         SetWindowLong(wnd, GWL_EXSTYLE, ExStyle);
       end;

       Result := S_OK;
     end;//WM_NCCALCSIZE
     end;//case

     Result := CallWindowProc(P, Wnd, Msg, WParam, LParam);
    end;

    //................................................................................ ......................................

    procedure InitClientProc(ClientHandle: integer);
    begin
     if (ClientHandle <> 0) then
     begin
       //Данные пользователя могут быть заняты
       if GetWindowLongPtr(ClientHandle, GWL_USERDATA) = 0 then
       begin
         SetWindowLongPtr(ClientHandle, GWL_USERDATA,
           SetWindowLongPtr(ClientHandle, GWL_WNDPROC, NativeUInt(@ClientWindowProc)));
       end;
     end;
    end;

  • dmk © (21.03.17 23:17) [1]
    Мне нужно принимать сообщение от родительского окна в безоконный класс.
  • dmk © (21.03.17 23:18) [2]
    В гугле полно примеров, но все нерабочие.
  • dmk © (22.03.17 02:13) [3]
    Делаю так:

    type TCallWndProc = function(Wnd: HWND; Msg: cardinal; WParam, LParam: integer): integer of object; stdcall;

    //в классе
     FCallWndProc: TCallWndProc;

    function TWindow64.ClientWindowProc(wnd: HWND; msg: cardinal; wparam, lparam: integer): integer; stdcall;
    var
    P: pointer;
    Style: dword;
    ExStyle: dword;

    begin
    P := Pointer(GetWindowLong(wnd, GWL_USERDATA));

    case msg of
    WM_NCCALCSIZE:
    begin
      Style := GetWindowLong(wnd, GWL_STYLE);
      ExStyle := GetWindowLong(wnd, GWL_EXSTYLE);

      //Убираем скроллы MDI-окна
      if (Style and (WS_HSCROLL or WS_VSCROLL)) <> 0 then
      begin
        Style := Style and not (WS_HSCROLL or WS_VSCROLL);
        SetWindowLong(wnd, GWL_STYLE, Style);
      end;

      //Убираем выступ в клиентской области MDI-окна
      if (ExStyle and (WS_EX_CLIENTEDGE)) <> 0 then
      begin
        ExStyle := (ExStyle and not WS_EX_CLIENTEDGE);
        SetWindowLong(wnd, GWL_EXSTYLE, ExStyle);
      end;

      Result := S_OK;
    end;//WM_NCCALCSIZE
    end;//case

    Result := CallWindowProc(P, Wnd, Msg, WParam, LParam);
    end;

    procedure TWindow64.InitClientWndProc(AHandle: integer);
    var
     L: NativeInt;

    begin
     if (AHandle <> 0) then
     begin
       //Данные пользователя могут быть заняты
       if GetWindowLongPtr(AHandle, GWL_USERDATA) = 0 then
       begin
         FCallWndProc := ClientWndProc;
         L := SetWindowLongPtr(AHandle, GWL_WNDPROC, NativeUInt(@FCallWndProc));
         L := SetWindowLongPtr(AHandle, GWL_USERDATA, L);
       end;
     end;
    end;


    Проходит один цикл и виснет.
    Если не делать частью класса - все в порядке, но переменные класса не видны.
    Можно сделать вызов, если ClientWindowProc часть класса?
  • Leonid Troyanovsky © (22.03.17 08:47) [4]

    > dmk ©   (22.03.17 02:13) [3]

    В 32 битные времена этому служил MakeObjectInstance.

    --
    Regards, LVT.
  • Игорь Шевченко © (22.03.17 10:48) [5]
    Ты по человечески можешь сказать, что тебе надо ? Существует масса способов решения самых разнообразных задач
  • dmk © (22.03.17 13:15) [6]
    >Ты по человечески можешь сказать, что тебе надо ?
    У меня есть класс графических объектов, которые рисуются в буфере, а потом выводятся на экран. Мне надо им петлю сообщений вставить. Чтобы они WM_MOUSE..... получали. Вроде как компоненты, но окна они не имеют. Можно конечно из базового окна им передавать координаты, но есть недотаток, это можно сделать только между WM_PAINT, а отрисовка по WM_PAINT иногда сильно тормозит (когда их много) и мне надо прервать отрисовку и начать заново. Насколько я знаю сообщения передаются асинхронно и это то что мне надо.
  • dmk © (22.03.17 13:19) [7]
    >В 32 битные времена этому служил MakeObjectInstance.
    Это немного не то. Механизм вызова я подсмотрел, но уверенности нет. Вроде как правильный адрес он в стеке хранит.
    Там:
     pop ecx, а потом call farptr идет.

    Не хочется лезть в такие дебри без полного осознания,
    а информации нет по этому поводу.
  • NoUser © (22.03.17 14:05) [8]

    > Это немного не то.

    И на сколько немного там это не то? ))

     private
       FOldWndProc  : IntPtr;
       FOldUserData : IntPtr;
       procedure InitClientWndProc(AHandle: HWND); // AHandle: integer ?
    // function  ClientWindowProc(wnd: HWND; Msg: cardinal; wparam, lparam: integer): integer; stdcall;  // on x64??
       function  ClientWindowProc(Wnd: HWND; Msg: NativeInt ; wParam: NativeUInt; lParam: NativeInt): NativeInt; stdcall;
       class function DumMyWndProc(Wnd: HWND; Msg: NativeInt ; wParam: NativeUInt; lParam: NativeInt): NativeInt; static; stdcall;

    procedure TWindow64.InitClientWndProc(AHandle: HWND);
    begin
     //Данные пользователя могут быть заняты  // -> печалька
     //
     FOldWndProc := SetWindowLongPtr(AHandle, GWL_WNDPROC, IntPtr(@DummyWndProc));
     FOldUserData :=  SetWindowLongPtr(AHandle, GWL_USERDATA, IntPtr(Self));
    end;

    class function TWindow64.DumMyWndProc(Wnd: HWND; Msg: NativeInt; wParam: NativeUInt;lParam: NativeInt): NativeInt;
    var
    Tmp : Pointer;
    begin
    Tmp := Pointer(GetWindowLongPtr(Wnd, GWL_USERDATA));
    if (Tmp <> nil) then                                                          // а вдруг там мышь ?,!
     try                                                                          
      Result := TWindow64(Tmp).ClientWindowProc(Wnd, Msg ,wParam, lParam);
     except end
    else Result := DefWindowProc(Wnd, Msg ,wParam, lParam)                        // грустная печальная печалька
    end;

    function TWindow64.ClientWindowProc(Wnd: HWND; Msg: NativeInt; wParam: NativeUInt; lParam: NativeInt): NativeInt;
    begin
    // ...

    SetWindowLongPtr(Wnd, GWL_USERDATA, IntPtr(FOldUserData));                    // печалька ->

    Result := CallWindowProc(Pointer(FOldWndProc), Wnd, Msg, wParam, lParam);     // !

    if IntPtr(@DumMyWndProc) <> GetWindowLongPtr(Wnd, GWL_WNDPROC) then           // печальная печалька
      FOldWndProc := SetWindowLongPtr(Wnd, GWL_WNDPROC, IntPtr(@DumMyWndProc));   // ::

    FOldUserData := SetWindowLongPtr(Wnd, GWL_USERDATA, IntPtr(Self));            // печалька <-
    end;
  • dmk © (22.03.17 15:00) [9]
    NoUser ©   (22.03.17 14:05) [8]
    У меня нет окна. С окном все просто и без проблем.
    А без окна GetLastError выдает InvalideDC
  • dmk © (22.03.17 15:08) [10]
    Windows не дает определить WndProc без окна. Можно только невидимое окно сделать.
    Этот вопрос в соседней ветке.
    А TWindow64 у меня класс от TObject. Там почти ничего нет. Мне просто нужен цикл сообщений. Делал через TNotifyEvent — такой вариант не подходит.
  • rrrrr © (22.03.17 15:55) [11]
    аллокейташвнд
  • dmk © (22.03.17 16:32) [12]
    >аллокейташвнд
    Без окна не работает.
    HWND создает, но при инсталляции GWL_USERDATA - GetLastError - Invalid DC.
    Может на семерке работает, а на 10-ке точно не работает. Все примеры из гугла не рабочие :(
  • rrrrr © (22.03.17 16:36) [13]
    type
    TMyStupidClass = class(TObject)
     fWnd : HWND;
     constructor createIt();
     procedure onMessage(var Message: TMessage);
     property handle : HWND read fWnd;
    end;

    constructor TMyStupidClass.createIt;
    begin
    inherited create();
    fWnd := AllocateHWnd(onMessage);
    end;

    procedure TMyStupidClass.onMessage(var Message: TMessage);
    begin
    form1.Caption := IntToStr(Message.Msg);
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    var stc : TMyStupidClass;
    begin
    stc := TMyStupidClass.createIt();
    PostMessage(stc.handle,WM_USER + 1000, 0,0);
    end;
  • dmk © (22.03.17 17:44) [14]
    rrrrr ©   (22.03.17 16:36) [13]
    Мне от системы надо!!! :) WM_MOUSEMOVE
    Оно только с окном приходит.
    Не выходит каменный цветок.
  • rrrrr © (22.03.17 17:57) [15]
    Мне нужно принимать сообщение от родительского окна в безоконный класс.

    родительское окно - настоящее.
    безоконный класс принимать сообщения может.
    транслируй!
  • dmk © (22.03.17 18:00) [16]
    >транслируй!
    Уже
  • rrrrr © (22.03.17 18:01) [17]
    procedure TMyStupidClass.onMessage(var Message: TMessage);
    begin
    form1.Caption := Format('mouse coords: %d %d',[Message.WParam, Message.LParam]);
    end;

    procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    begin
    PostMessage(stc.handle, WM_MOUSEMOVE, Y,X);
    end;
  • rrrrr © (22.03.17 18:04) [18]
    только зачем все это, если можно прямо методы дергать
  • NoUser © (22.03.17 18:25) [19]
    > dmk ©   (22.03.17 15:00) [9]
    > У меня нет окна.

    Сочувствую, а как же :

    > dmk ©   (22.03.17 02:13) [3]
    > Если не делать частью класса - все в порядке, но переменные класса не видны.


    > rrrrr ©   (22.03.17 18:04) [18]
    !
  • dmk © (22.03.17 18:28) [20]
    >NoUser ©   (22.03.17 18:25) [19]

    Ну зачем извращать. Речь шла об оконной процедуре.
  • Игорь Шевченко © (22.03.17 19:16) [21]
    dmk ©   (22.03.17 13:15) [6]


    > Мне надо им петлю сообщений вставить. Чтобы они WM_MOUSE.
    > .... получали. Вроде как компоненты, но окна они не имеют.
    >


    OpenGL уже изобретен и даже с исходниками. И всякие там GLScene тоже с исходниками. Не понимаю, зачем при таком изобилии готовых решений изобретать велосипеды которые будут ехать медленно и неровно.
  • dmk © (22.03.17 19:50) [22]
    Игорь, патриотизм штука заразная. Хочу свое ;)
  • dmk © (22.03.17 19:53) [23]
    А на самом деле класс кроссплатформенный в будущем и привязка к системе и т.д. очень нежелательна. Посему куча ассамблера и соответствующие отступления.
  • Игорь Шевченко © (23.03.17 10:23) [24]
    dmk ©   (22.03.17 19:50) [22]

    Дело не в патриотизме, а в том, что в современном мире исходников столько, что решение почти любой проблемы несколькими способами можно найти в интернетах.
  • dmk © (23.03.17 12:14) [25]
    Можно и найти и купить - не спорю.
    Часто сталкивался с проблемой прекращения поддержки исходников или компонентов.
  • Игорь Шевченко © (23.03.17 12:21) [26]
    dmk ©   (23.03.17 12:14) [25]

    Я не про готовый вариант, а про реализацию идей, методы решения проблем и т.п. Это не надо покупать и опасаться прекращения поддержки.
  • D7 (28.03.17 21:59) [27]
    Я не понял. Сообщения может принимать только окно. Изображения выводить можно тоже только на окно. На невидимое окно выводить невозможно. У вас есть окно или нету? Или оно типа чужое?
    Делайте ваш кросплатформенный класс, добавляйте в поля TForm1 его экземпляр, вызывайте его методы в нужных событиях. И всё, нет?
  • D7 (28.03.17 22:39) [28]
    Поздно увидел другую вашу тему, вам там уже показали что-то подобное тому что я имел ввиду...

    Могу лишь посоветовать глянуть как работает AGG. Там кроссплатформенное ядро имеет лёгкие обёртки к разным ОС, в том числе делает окно на WinAPI и рисует на нём и получает управление клавиатуры/мыши.
  • dmk © (29.03.17 01:45) [29]
    >D7   (28.03.17 21:59) [27]

    Окна нет, но есть HWND созданный с помощью AllocateHWND.
    Класс от TObject. Рисуется в памяти. Не TCanvas.
  • D7 (29.03.17 02:46) [30]
    > Класс от TObject. Рисуется в памяти. Не TCanvas.

    Это я как раз сразу понял. Хорошая идея, одобряю, сам когда-то думал про подобное.

    > Окна нет, но есть HWND созданный с помощью AllocateHWND.

    А вот зачем такие свистопляски с окном - не понимаю.
    Я не сталкивался с подобной функцией прежде, прогуглил её - это походу какой-то метод из VCL. Который в итоге создаёт окно при помощи CreateWindowEx().
    Уверен что будет удачнее взять "минимальный WindowsAPI-проект" - и вперёд, допиливаем лёгонькую обёртку. Небольшую часть кода можно из TApplication взять.
  • dmk © (29.03.17 02:55) [31]
    >А вот зачем такие свистопляски с окном - не понимаю.
    Для того, чтобы классу без окна сообщения принимать.
  • D7 (29.03.17 16:56) [32]
    Что в вашем понимании есть "класс без окна"? Окнами в любом случае владеет только ОС.
    А вы говорите что вызываете метод "Forms.AllocateHWnd()" (он же "Classes.AllocateHWnd())"? Ну так вы этим как раз создали окно.
    Какого-то системного VCL-класса с какой-то системной VCL-WndProc по-умолчанию. Но я так понял вы вроде хотите как раз избавляться от VCL?

    Сделаю к выходным пример как бы предложил делать я, а там посмотрите и решите сами.
  • dmk © (29.03.17 18:35) [33]
    >Ну так вы этим как раз создали окно.
    Это все условности. По правилам Windows окном считается класс с оконной процедурой.
    У меня ее нет. Ибо не нужна. Это дочерний объект-неокно.
  • dmk © (29.03.17 20:02) [34]
    Вот пример дочерних объектов не окон с поведением окон ;)
    https://hostingkartinok.com/show-image.php?id=97725fa53a628a8e4b5f2c99ae984ed2

    Работают также как и системные. Почти никаких различий.
    Рисуются на любом контексте. Пока готово 3 компонета. Тут еще CheckBox не виден.
    Скролл бары за 3 дня сделал. Почти как FMX, но не FMX. ПРивязки к WIndows почти нет ;)
    Своя базовая бибилотека и никаких системных вызовов кроме BitBlt и сообщений о мышке.
    Переносится хоть под линукс, хоть под DOS с небольшой доработкой ввода-вывода.
  • dmk © (29.03.17 20:04) [35]
    У меня даже шрифты свои. Пока растровые, но все же ;)
  • dmk © (29.03.17 20:07) [36]
    И никаких оконных функций и прочей мутатени ;)
  • Игорь Шевченко © (29.03.17 21:34) [37]

    > По правилам Windows окном считается класс с оконной процедурой


    Без комментариев.


    > И никаких оконных функций и прочей мутатени ;)


    Таких фреймворков уже миллионы. Зачем нужен еще один с граблями - я не понимаю.
  • dmk © (29.03.17 22:02) [38]
    >Без комментариев.
    Ну тогда черный квадрат малевича тоже окно :)

    >Зачем нужен еще один с граблями - я не понимаю.
    Дык свое. У меня софтина на нем пишется. Большая :)
    Если намертво к windows привязаться потом тошно переделывать будет,
    а слово портирование забыть придется.
  • D7 (29.03.17 22:11) [39]
    > По правилам Windows окном считается класс с оконной процедурой.

    Это чего это, где же такое написано?
    В исходниках ОС может и класс, а со стороны прикладного программиста это - чёрный ящик, имеющий некий ID.

    На вашем скриншоте я вижу обычное окно с рамкой.
    Да, на его клиентской области выводится своё крутое кросплатфоменное, но через BitBlt() оно выводится на обычное окно. Можете взять Spy++ и проверить.
    Кстати можно заменить BitBlt() на StretchDIBits(), слышал мнение что оно чуток эффективнее, хотя сам не проверял не тестировал.

    В общем до понедельника сделаю тестовый мини-проект.
  • dmk © (29.03.17 22:17) [40]
    >На вашем скриншоте я вижу обычное окно с рамкой.
    Ну да, только все рисуется и крутится без системных вызовов ;)
    А BitBlt - ну тут извините. Windows не дает прямого доступа к видеопамяти.
    Короче написал я фигню. Каюсь, грешен был. О великий TForm!!!
  • D7 (29.03.17 22:24) [41]
    Нет, вы пишете перспективную штуку, но у вас есть окно какого-то класса и очередь сообщений, не может не быть. Под виндой не может.
    Поэтому нужна лёгкая прослойка между ОС/платформой и главным кодом. Для винды своя, для другого другая. А интерфейс главного не меняется.
  • dmk © (29.03.17 22:27) [42]
    >Поэтому нужна лёгкая прослойка между ОС/платформой и главным кодом.
    Абстракция от системы есть.
  • Игорь Шевченко © (29.03.17 22:59) [43]

    > Дык свое.


    Дык надо книжки читать, чтобы свое делать. А не плавать в базовых понятиях.


    > Если намертво к windows привязаться потом тошно переделывать
    > будет,
    > а слово портирование забыть придется.


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

    Иксы на юниксах например совсем по-другому работают, что на маке происходит - честно не знаю, но тоже не так, как на Windows. А на андроиде еще по третьему. Куда ты будешь свои WM_LBUTTONDOW переносить - я не представляю
  • dmk © (29.03.17 23:16) [44]
    >Игорь Шевченко ©   (29.03.17 22:59) [43]
    Вы меня уничтожили :) Просто растерли.
  • Eraser © (30.03.17 07:39) [45]

    > Почти как FMX, но не FMX. ПРивязки к WIndows почти нет

    так и в FMX привязки к windows нет.
    https://ru.wikipedia.org/wiki/%D0%98%D1%81%D1%82%D0%BE%D1%80%D0%B8%D1%8F_%D0%B2%D0%B5%D0%BB%D0%BE%D1%81%D0%B8%D0%BF%D0%B5%D0%B4%D0%B0
  • Игорь Шевченко © (30.03.17 10:19) [46]

    > Вы меня уничтожили :) Просто растерли.


    Не в этом дело. Такие задачи прекрасно решаются в рамках парадигмы Model-View-Controller, где контроллер как раз и занимается обработкой внешних событий. Таким образом решение абстрагируется от конкретных механизмов внешних событий, сосредотачивая всю конкретику в относительно небольших участках кода.
    Я ведь не зря начал с того, что примеров уже уйма, посмотреть, как сделано, можно совершенно бесплатно.
  • dmk © (30.03.17 13:10) [47]
    Так я так и делаю. У меня отдельный класс будет, который будет заниматься вводом-выводом. Просто не успеваю все сделать. Если бы я программистом был ;) А так сижу вечерами пишу, да и то не каждый день. Много изучил, но еще больше не знаю. Учимся пока. Для меня это кажется новшеством, а у других уже есть. Ну велосипед и что? Зато свой.
  • An a Student (30.03.17 20:01) [48]
    Просто вы, кажется, не понимаете что "окно" в Windows - это и не "форма" и не "класс". Да и вообще никакой класс не может "содержать окно", лишь побочно создавать и идентификатор хранить.
    Окно - это HWND (ну или псевдоним THandle из VCL), полученное через одну из WinAPI-функций (или даже из VCL-функций/методов).
    А связь своего потомка от TObject с неким HWND и с его оконной функцией - не делает ни окно "частью класса", ни наоборот.

    По идее же надо передавать указатель на экземпляр объекта своего класса через lParam, нет? А вы тут что-то странное делаете - зачем так странно сабклассить собственное окно?
  • dmk © (30.03.17 23:18) [49]
    HWND это просто индекс или ссылка или относительный адрес структуры которой рассылается сообщение. В остальном я делаю велосипед. Не обращайте внимания.
  • An a Student (31.03.17 00:31) [50]
    Вот именно. В классе который мы придумываем может быть только индекс/ссылка/смещение не важно что это - HWND. "Окна в классе" в принципе быть не может.

    гм... Этот "class function" никогда не видел, это чего такое, типа статического метода? Думал нету в Делфи статических. И у таких не будет первого скрытого параметра "self/this"? Ну дак в случае с WndProc тогда и нету смысла так делать.

    Классика - передавать указатель на объект в CreateWindowEx() в lParam и в WM_CREATE записывать его в GWL_USERDATA. Зачем извращаться-то? :)
  • DVM © (01.04.17 22:10) [51]

    > dmk ©

    не забудь еще что без цикла выборки сообщений, работать ничего не будет.


    > An a Student   (31.03.17 00:31) [50]


    > Этот "class function" никогда не видел, это чего такое,
    > типа статического метода? Думал нету в Делфи статических.
    >  И у таких не будет первого скрытого параметра "self/this"?
    >

    Этого недостаточно, все равно будут скрытые параметры. Нужно еще слово  static.
  • dmk © (01.04.17 22:15) [52]
    >не забудь еще что без цикла выборки сообщений, работать ничего не будет.
    Отдельного цикла нет. Просто трансляция из оконной процедуры. Все работает.
  • DVM © (01.04.17 22:20) [53]

    > dmk ©   (01.04.17 22:15) [52]


    > Отдельного цикла нет.

    Как это нет? У тебя же родительское окно есть. Есть. Значит и цикл есть.
  • DVM © (01.04.17 22:35) [54]
    По моему, тут вообще не нужно никаких окон и сообщений.
    Нужно ядро, и два контроллера, ввода и вывода. Общение между ними не нуждается в сообщениях. Все общение ядра с внешним миром определяется контроллерами. Контроллер ввода прекрасно может перехватывать сообщения формы и транслировать их в ядро.
  • dmk © (01.04.17 22:57) [55]
    Это типа узловой связи клиент-сервер?
  • D7 (03.04.17 03:38) [56]
    так... В общем что-то я совсем заморочился, наплодил нечто объёмное и сырое. Но общую суть как-то так:

    type
     MouseButton = (buttonLeft, buttonRight, buttonMiddle);

    function TWindow64WndProc(Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
    var Window64: TWindow64;
    begin
    Window64:=TWindow64(GetWindowLong(Wnd, GWL_USERDATA)); // получаем текущий объект!
    case Msg of
     WM_CREATE: // сообщение приходит одним из первых и однократно для каждого создаваемого HWND
       begin
       SetWindowLong(Wnd, GWL_USERDATA, Integer(PCreateStruct(lParam).lpCreateParams)); // сохраняем текущий объект так!
       Result:=0;
       end;
     WM_PAINT:
       begin
       Window64.OnMessagePaint(Wnd, wParam);
       Result:=0;
       end;
     WM_LBUTTONDOWN:
       begin
       Window64.OnMouseDown(Smallint(lParam And $FFFF), Smallint(lParam Shr 16), buttonLeft, ... );
       Result:=0;
       end;
     WM_LBUTTONUP:
       begin
       Window64.OnMouseUp(Smallint(lParam And $FFFF), Smallint(lParam Shr 16), buttonLeft, ... );
       Result:=0;
       end;
     WM_RBUTTONDOWN:
       begin
       Window64.OnMouseDown(Smallint(lParam And $FFFF), Smallint(lParam Shr 16), buttonRight, ... );
       Result:=0;
       end;
     WM_RBUTTONUP:
       begin
       Window64.OnMouseUp(Smallint(lParam And $FFFF), Smallint(lParam Shr 16), buttonRight, ... );
       Result:=0;
       end;
     else
       Result:=DefWindowProc(Wnd, Msg, wParam, lParam); // !!!
     end;
    end;

    procedure TWindow64.OnMessagePaint(Wnd: HWND; wParam: WPARAM);
    var DC: HDC; Rect: TRect; PS: TPaintStruct;
    begin
    if (wParam<>0) then
     DoPaint(HDC(wParam), nil)
    else
     if GetUpdateRect(Wnd, Rect, False) then
       begin
       DC:=BeginPaint(Wnd, PS);
       DoPaint(DC, @Rect);
       EndPaint(Wnd, PS);
       end
     else
       { nothing };
    end;

    procedure TWindow64.DoPaint(DC: HDC; Rect: PRect);
    begin
    // Делаем BitBlt или StrechDIBits на DC переданный через параметры
    end;

    procedure TWindow64.OnMouseDown(X: Integer; Y: Integer; Button: MouseButton, ... );
    begin
    //
    end;

    procedure TWindow64.OnMouseUp(X: Integer; Y: Integer; Button: MouseButton, ... );
    begin
    //
    end;

    constructor TWindow64.Create(AParent: THandle; ABitmap: TBitmap64; R: TRegion);
    var Rect: TRect;
    begin
    ...
     FWndClassEx.lpfnWndProc := @TWindow64WndProc; // и всё, больше ничего не надо мутить!
    ...
     FStyle:=WS_VISIBLE Or WS_OVERLAPPEDWINDOW;
     FStyleEx:=WS_EX_APPWINDOW;
     with Rect do
       begin
       Left:=FClientLeft;
       Top:=FClientTop;
       Right:=Left+FClientWidth;
       Bottom:=Top+FClientHeight;
       AdjustWindowRectEx(Rect, FStyle, False, FStyleEx);
       FHandle:=Windows.CreateWindowEx(
                                                          FStyleEx,
                                                          LPCWSTR(FWndClassEx.lpszClassName),
                                                          'TWindow64',
                                                          FStyle,
                                                          Left,
                                                          Top,
                                                          Right-Left,
                                                          Bottom-Top,
                                                          0, // !!!
                                                          0,
                                                          HInstance,
                                                          Pointer(Self) // и передаём ссылку на текущий объект сюда!
                                  );
       end;
    ...
    end;


    И не забывайте про всякие *DBLCLK. А зачем нужна какая-то самодельная "трансляция"?
    В каждый объект TWindow64 нажатие будет само приходить (если курсор был над ним), даже если оно будет дочернее.

    > DVM ©   (01.04.17 22:35) [54]

    эм... Я тоже не особо понял, если не сложно, расскажите пожалуйста всем поподробнее об этом? Спасибо!
  • dmk © (03.04.17 05:59) [57]
    У меня смысл такой, что приходится обходить ограничения Windows на доступ к видеопамяти, т.к. в проекте у меня все рисуется в буфере, то и контролы нужно рисовать в буфере. Поэтому и придумал такой вариант. Зато его можно и в буфер рисовать и на DC рисовать, хотя DC и есть буфер, только у системы.

    Проще покзать, чем объяснить. Тут 2 экзешника:
    https://cloud.mail.ru/public/bkmv/YUqSxabFZ

    TBitmap - там CheckBox в буфере рисуется, а в ic64 скроллы и линейки.
    Про смысл не спрашивайте.
  • D7 (03.04.17 10:38) [58]
    Под Win7 не стартится, видимо exe-шники только под 64. А старые демки (из соседних тем) уже не доступны, жаль, я бы с радостью посмотрел.

    Можно и на OpenGL всё рисовать. Видеопамять, пожалуйста. :)

    Непонятно тока что за "трансляция". Если у вас много окон (группа HWND) - то им сообщения сами придут.
    А если они не реальные окна - то им не надо создавать HWND и что-то слать, оперировать вручную, вызывать методы если требуется.

    Вы можете убрать из кода ваши секретные разработки (рисование на ассемблере и прочее, вообще их по логике в отдельных модулях надо хранить), оставить только базовые классы типа TWindow64, часть которых привязана к Windows, и скинуть куда-то сей урезанный проект?
  • D7 (03.04.17 10:46) [59]
    Под моей Win7 имелось ввиду. Попробую найти 64, но в идеале бы было бы чтоб работало и на 32 тоже. *

    Я же говорю - я очень хорошо понимаю задумку, но некоторые вещи что вы делаете (видно по кускам кода) не укладываются в подобную архитектуру.
    Что-то слегка не так, я хочу помочь это исправить.
  • dmk © (03.04.17 11:05) [60]
    >было бы чтоб работало и на 32 тоже
    Писать под win32 сей проект неудобно. Там ограничение 4 гб. Делать смешанную адресацию неудобно и получаются медленные процедуры. 32 уже потихоньку уходит в прошлое, хотя и не так быстро как 16 бит.
  • D7 (03.04.17 11:09) [61]
    И вы реально можете занять все 4ГБ? У меня вот ни одна программа, даже мощные CAD-системы и крутые игры - не достигают 4ГБ. %))
  • dmk © (03.04.17 11:12) [62]
    >Непонятно тока что за "трансляция".
    Windows не дает без окна доступ к очереди сообщений, поэтому приходится делать привязку к оконной процедуре. Типа врезки трубы в магистраль. Хотя можно изобрести что-то вроде своего контроллера. Если мышь в области, то запускать таймер и делать выборку позиции через winapi.GetCursorPos и клавиши через GetAsyncKeyState. Тогда вообще трансляция не нужна.

    А под 32 не переделаю. Смысла нет, да и наоборот я ее переделывал с 32 на 64.
  • dmk © (03.04.17 11:17) [63]
    >И вы реально можете занять все 4ГБ?
    У меня Photoshop64, 3ds max64, Illustrator64 и т.д все используют намного больше 4 гб.
    У меня 32 стоит. Фотошо например 20 Гб легко съедает.
  • D7 (03.04.17 12:02) [64]
    Не пользую фотошопы - рисовать не умею. Для элементарных обработок вполне хватает XnView/Gimp.
    Что ж вы с ними делаете такое?)) У меня модель летательного аппарата со всеми мельчайшими деталями и сложной кинематикой стока не жрёт))
    Хотя не тестил скока будет жрать если поставить x64 ОС и такую же версию CAD-системы... Может с этой же моделью сразу же в три раза больше памяти хапнет просто так?

    ох... Короче так.
    * Делаем класс DMKApplication, который: хранит список "окон" верхнего уровня программы, умеет запускать очередь сообщений, при закрытии всех окон выходит из программы (закрывает).
    * Делаем класс DMKWindow, который: является обёрткой над окнами верхнего уровня Windows, умеет создавать и уничтожать окна, получает управление от мыши и клавиатуры, отслеживает изменение своего состояния (позиция, размеры, итп), хранит и обрабатывает список "слоёв", выводит на себя итоговую буфер-картинку.
    * Делаем класс DMKLayer, который: является логической единицей выводящей что-либо на битмап, имеет классические методы и события. Возможно абстрактный, с какими-то потомками типа "кнопка", "текст", "чекбокс", etc.
    В простейшем случае имеем: один объект DMKApplication, один объект DMKWindow, некоторое количество объектов DMKLayer. Итого в программой будет создано один HWND и при перерисовке будет браться один HDC за раз и тут же освобождаться.
    Минимальная привязка к ОС, минимальное потребление системных как их там, максимальная скорость работы, переносимость программы на любую платформу через просто замену реализации нескольких методов DMKApplication и DMKWindow, и всё своё.
  • Игорь Шевченко © (03.04.17 12:13) [65]
    D7   (03.04.17 11:09) [61]


    > И вы реально можете занять все 4ГБ? У меня вот ни одна программа,
    >  даже мощные CAD-системы и крутые игры - не достигают 4ГБ.
    >  %))


    Это говорит о том, что с программами, занимающими больше 4-х Гб ты не знаком. Ну и что ? Займись фотографией, сразу познакомишься :)

    dmk ©   (03.04.17 11:05) [60]


    > 32 уже потихоньку уходит в прошлое


    Бред какой. Программ, которым реально нужен большой объем памяти, максимум 1 процент от всего.
  • dmk © (03.04.17 12:14) [66]
    >будет браться один HDC за раз и тут же освобождаться.
    DC - контекст - это просто битмап. Его не надо постоянно освобождать. Взял DC и пользуй его. Надоело - ReleaseDC. Это просто ссылка. Это нужно было в windows 3.11-95, а после win2000 уже не нужно.
    На самом деле все уже работает. Если запустите примеры, то увидите. Только win64 надо.
  • D7 (03.04.17 12:37) [67]
    Хех, "занимающими" или "жрущими"?)) Вся папка CAD-программы занимает на диске около 23ГБ.
    Фотографией? У вас есть фотка весящая 4ГБ в распакованном виде?)

    MSDN указывает делать BeginPaint/EndPaint. Я слушаюсь MSDN, во избежание, как говорится, это их система.
    HDC это не битмап, в него может быть выбран битмап, а может и не быть выбран. Как и остальные HGDI объекты.

    ну... Я предлагал помочь. Как хотите. Но покачто у вас что-то делается не совсем так. В плане WinAPI.
  • Игорь Шевченко © (03.04.17 14:06) [68]
    D7   (03.04.17 12:37) [67]


    > У вас есть фотка весящая 4ГБ в распакованном виде


    Конечно. И не одна. Кроме фоток еще есть базы данных. И не одна. Но это уже оффтопик. Я просто прошу поверить, что нужных 64-х разрядных программ достаточно.
  • dmk © (03.04.17 14:08) [69]
    >не совсем так. В плане WinAPI.
    У меня все в памяти делается, а не в винапи.
    Мне от WInApi только несколько сообщений надо.

    А за помощь спасибо! Все будет учтено.
  • dmk © (03.04.17 14:12) [70]
    >У вас есть фотка весящая 4ГБ в распакованном виде?)
    Вы просто не сталкивались видимо с такими задачами: БД, Видео, Фото, Полиграфия, Архивы и т.п. У меня архивы несколько сот гигабайт в упакованном виде. Работаю дизайнером. Есть файлы более 4-х Гб. Немного, но есть.
  • Eraser © (03.04.17 19:24) [71]

    > dmk ©  

    прочитал ветку, так и не понял - зачем?
    без окна в современной винде все равно отображать ничего не выйдет, для отображения в Windows нужно окно (Window), для него и нужно написать платформенно-зависимую прослойку, которая будет отображать и принимать ввод. к чему велосипеды - не понятно.
  • dmk © (03.04.17 23:41) [72]
    >без окна в современной винде все равно отображать ничего не выйдет
    Там в [57] уже все вышло :) Конечно же все отображается в окне.
  • Eraser © (04.04.17 10:41) [73]

    > dmk ©   (03.04.17 23:41) [72]

    все равно не понятно, зачем требовалось, что требовалось и что в итоге получилось.
    по-моему усложнение себе жизни.
 
Конференция "WinAPI" » Как принять сообщения в класс без окна?
Есть новые Нет новых   [118626   +13][b:0.001][p:0.003]