Конференция "WinAPI" » Окно на WinApi внутри Dll [D7, WinXP]
 
  • DagOT-R © (13.04.10 11:31) [0]
    Я пишу проект на WinAPI и GDI, и допустим, хочу написать Dll, из которой экспортирую функцию, которая вызывает контекстное меню. Однако, само меню я решил также написать как окно на WinAPI, т.к. для этого меню у меня есть собственный дизайн, с нарисованным фоном и кнопками. Внутри функции в Dll'ке я создаю и регистрирую класс окна, создаю собственно окно меню, там же находится процедура-обработчик сообщений окна. Однако, если после создания окна прописать цикл обработки сообщений TranslateMessage-DispatchMessage, то само собой, сама процедура создания контекстного меню "повесит" все приложение, пока меню не будет уничтожено. Собственно, вопрос в том, как в одном приложении использовать и обрабатывать несколько окон на WinAPI?
  • Дмитрий С © (13.04.10 12:26) [1]
    У тебя этот цикл в основной программе уже есть, он один для всех окон потока. Отдельный цикл нужно создавать для отдельного потока. Для каждого окна создавать отдельный цикл не нужно.

    P.S. если не сложно скинь пример менюшки на winapi мне на почту reg argi ru.
  • Сергей М. © (13.04.10 13:00) [2]

    > если после создания окна прописать цикл обработки сообщений
    > TranslateMessage-DispatchMessage, то само собой, сама процедура
    > создания контекстного меню "повесит" все приложение, пока
    > меню не будет уничтожено


    Это с какого же перепугу "повесит" ?
  • DagOT-R © (13.04.10 13:26) [3]
    Собственно проблема в том, что при вызове меню ничего не происходит: функция вызывается корректно, но никаких следов появления меню, даже малейшей задержки в работе программы при загрузке изображений не происходит. Само меню пока очень сырое, и написано до момента, когда его можно подключить к проекту и тестировать. В нем не до конца прописано уничтожение окна и не прописана реакция на кнопки. Собственно, задумка такова:
    Из Dll экспортируется ф-я ,которой передается хендл окна его вызывающего, передается адрес процедуры обратного вызова, которая будет обрабатывать события на кнопках из основного кода проекта, также передаются координаты курсора. Код оочень сырой, но выложу тут чтобы узнать, где именно кроется загвоздка.

    library Menu;

    uses
     Windows,
     SysUtils,
     Classes,
     messages;

    type
      TRe_Action = (A_Exit, A_Hide, A_Show, A_SoundOn, A_SoundOff);
      TRe_Menu_proc = procedure (Action: TRe_Action; Param: Integer);
      PRe_Menu_proc = ^TRe_Menu_proc;

      Var
        Message: TMsg;

    {$R Pics.res}
    {$R *.res}

    function ScreenWidth: integer;
    begin
    result:=GetSystemMetrics(SM_CXVIRTUALSCREEN);
    end;

    function ScreenHeight: integer;
    begin
    result:=GetSystemMetrics(SM_CYVIRTUALSCREEN);
    end;

    function Create_Menu(Handle: HWND; Menu_proc: PRe_Menu_proc; X, Y: integer): HWND; stdcall;
    var
     wc : TWndClassEx;  //Переменная шаблона класса окна
     xPos,yPos,nWidth,nHeight : Integer;
     TRgn, FoneRgn: HRGN;
     Dc,hMemDc: Hdc;

     PIC_Exit1, PIC_Exit2, PIC_Exit3, PIC_Fone, PIC_Hide1, PIC_Hide2, PIC_Hide3,
     PIC_Show1, PIC_Show2, PIC_Show3, PIC_Soff1, PIC_Soff2, PIC_Soff3, PIC_Son1,
     PIC_Son2, PIC_Son3: HBitmap;

    function BitmapToRgn(PosX, PosY, width, height: integer; Image: HBitmap): HRGN;
    var
    TmpRgn: HRGN;
    x, y: Byte;
    ConsecutivePixels: integer;
    CurrentPixel: COLORREF;
    CurrentColor: COLORREF;
     TmpDC: HDC;
    begin
    Result := CreateRectRgn(0, 0, PosX+width-1, PosY+height-1);
     TmpDC:= CreateCompatibleDC(Dc);
     SelectObject(TmpDC,Image);
    for y := 0 to height-1 - 1 do
     begin
      CurrentColor := GetPixel(TmpDC,0,y);
      ConsecutivePixels := 1;
      for x := 0 to width-1 - 1 do
       begin
        CurrentPixel := GetPixel(TmpDC,x,y);
        if CurrentColor = CurrentPixel then
         inc(ConsecutivePixels)
        else
         begin // Входим в новую зону
          if (CurrentColor = $ff00ff) or (CurrentColor = $00C8C4C8) then
           begin
            TmpRgn := CreateRectRgn(PosX+x-ConsecutivePixels, PosY+y, PosX+x, PosY+y+1);
            CombineRgn(Result, Result, TmpRgn, RGN_DIFF);
            DeleteObject(TmpRgn);
           end;
          CurrentColor := CurrentPixel;
          ConsecutivePixels := 1;
         end;
       end;
      if ((CurrentColor = $ff00ff) or (CurrentColor = $00C8C4C8)) and (ConsecutivePixels > 0) then
       begin
        TmpRgn := CreateRectRgn(PosX+x-ConsecutivePixels, PosY+y, PosX+x, PosY+y+1);
        CombineRgn(Result, Result, TmpRgn, RGN_DIFF);
        DeleteObject(TmpRgn);
       end;
     end;
       DeleteDC(TmpDC);
    end;

    function WindowProc(wnd:HWND; Msg : Integer; Wparam:Wparam; Lparam:Lparam):Lresult; stdcall;
    Begin
     {Далее происходит цикл обработки сообщений}
     case msg of
     wm_create :
       Begin
       DC := GetWindowDC(wnd);
        PIC_Exit1 := LoadBitmap(hInstance, 'RE_M_EXIT1');
        PIC_Exit2 := LoadBitmap(hInstance, 'RE_M_EXIT2');
        PIC_Exit3 := LoadBitmap(hInstance, 'RE_M_EXIT3');
        PIC_Fone  := LoadBitmap(hInstance, 'RE_M_FONE');
        PIC_Hide1 := LoadBitmap(hInstance, 'RE_M_HIDE1');
        PIC_Hide2 := LoadBitmap(hInstance, 'RE_M_HIDE2');
        PIC_Hide3 := LoadBitmap(hInstance, 'RE_M_HIDE3');
        PIC_Show1 := LoadBitmap(hInstance, 'RE_M_SHOW1');
        PIC_Show2 := LoadBitmap(hInstance, 'RE_M_SHOW2');
        PIC_Show3 := LoadBitmap(hInstance, 'RE_M_SHOW3');
        PIC_Soff1 := LoadBitmap(hInstance, 'RE_M_SOFF1');
        PIC_Soff2 := LoadBitmap(hInstance, 'RE_M_SOFF2');
        PIC_Soff3 := LoadBitmap(hInstance, 'RE_M_SOFF3');
        PIC_Son1  := LoadBitmap(hInstance, 'RE_M_SON1');
        PIC_Son2  := LoadBitmap(hInstance, 'RE_M_SON2');
        PIC_Son3  := LoadBitmap(hInstance, 'RE_M_SON3');
        FoneRgn := BitmapToRgn(0, 0, 129, 97, PIC_Fone);
        TRgn:= CreateRectRgn(0,0,1,1);
         CombineRgn(TRgn,FoneRgn,Trgn,RGN_COPY);
         SetWindowRgn(Wnd,Trgn,True);
        WindowProc:= DefWindowProc (wnd, Msg, WParam, LParam);
       End;
     wm_paint :
       Begin
        hMemDc := CreateCompatibleDC(dc);
        SelectObject(hMemDC,PIC_Fone);
        BitBlt(dc, 0, 0, 129, 97, hMemDC, 0, 0, SRCCOPY);
        DeleteDC(hMemDC);

        WindowProc:= DefWindowProc (wnd, Msg, WParam, LParam);
       End;
     wm_destroy :  //Сообщение посылаемое при уничтожении окна
       Begin
       ReleaseDC(Wnd, Dc);

        Result:=0;
             postquitmessage(0); exit;
        WindowProc:= DefWindowProc (wnd, Msg, WParam, LParam);
       End
      else Result:=DefWindowProc(wnd,msg,wparam,lparam);
     end;
    End;
    begin
    result:=0;

    wc.cbSize:=sizeof(wc);
    wc.style:=cs_hredraw or cs_vredraw;
    wc.lpfnWndProc:=@WindowProc;
    wc.cbClsExtra:=0;

    wc.cbWndExtra:=0;
    wc.hInstance:=HInstance;
    wc.hIcon:=LoadIcon(0,idi_application);
    wc.hCursor:=LoadCursor(0,idc_arrow);
    wc.hbrBackground:=COLOR_BTNFACE+1;
    wc.lpszMenuName:=nil;
    wc.lpszClassName:='TRE_Menu';
    RegisterClassEx(wc); //Регистрация нового класса в системе

    {'заполнение переменных xPos,yPos,nWidth,nHeight}
    nWidth:=129;
    nHeight:=97;

    if ScreenWidth-X>=nWidth then
    xPos:=x else xPos:=x-nWidth;
    if ScreenHeight-Y>=nHeight then
    yPos:=y else yPos:=y-nHeight;

    { Создание главного окна}
    result:=CreateWindowEx (
    0,                    //флаги расширенных стилей
    '
    TRE_Menu',    //имя класса окна, данное при заполнении структуры wc
    '
    RE_Menu',          //заголовок окна
    ws_overlappedwindow+WS_VISIBLE, //флаги стилей окна
    {подробнdее о стилях см. после текста программы}
    xPos,               //горизонтальная позиция окна
    yPos,               //вертикальная позиция окна

    nWidth,             //ширина окна
    nHeight,            //высота окна
    Handle,                  //описатель родительского окна (parent) или окна-владельца (owner)
    0,                  //описатель меню окна (меню нет, нет и описателя)
    Hinstance,          //описатель приложения
    nil                 //address of window-creation data
    );
    ShowWindow(result, SW_SHOW); //Отображаем окно
    UpdateWindow (Result);
    end;

    exports
    Create_Menu index 1 name '
    Create_Menu';

    begin

    end.

  • han_malign (13.04.10 13:43) [4]
    круто... WindowProc - локальная функция ссылающаяся на локальные переменные внешней функции...
    1. Delphi7 не поддерживает замыканий...
    2. Прежде чем сношать мозги(и себе, и занятым людям) с DLL - убедись что работает "линейный" код в монолитном проекте...
  • DagOT-R © (13.04.10 17:03) [5]
    Все переменные, необходимые для создания и работы окна прописаны внутри функции. Естественно, не описывать же мне все переменные как глобальные!
  • DagOT-R © (13.04.10 17:05) [6]
    Где ты увидел замыкания в коде? Выразись пояснее, а то из твоих абстрактно-непонятных, но якобы очевидных обьяснений ничего непонятно.
  • Игорь Шевченко © (13.04.10 17:47) [7]
    DagOT-R ©   (13.04.10 17:03) [5]

    Тебе явно указали, что оконная процедура не может быть вложенной.
    Что ты препираешься ?
  • DagOT-R © (14.04.10 00:41) [8]
    Ок, ясно, спасибо, попробую исправить.
  • DagOT-R © (14.04.10 01:42) [9]
    И правда, все работает и рисуется отлично. Еще раз спасибо за помощь.
  • Дмитрий С © (14.04.10 04:45) [10]
    А разве такое компилируется для локальной WindowProc:
    wc.lpfnWndProc:=@WindowProc;
    ?
  • DagOT-R © (14.04.10 14:14) [11]
    Вот выложу готовый проект, в котором используется это меню, загружаемое через dll.
    Оконная сиделка Мэй [3.04 Мб]:
    http://ani-grafick.ucoz.ru/oursoft/May2.rar
    Исходники и текстуры библиотеки [242 Кб]:
    http://ani-grafick.ucoz.ru/oursoft/Menu.rar
 
Конференция "WinAPI" » Окно на WinApi внутри Dll [D7, WinXP]
Есть новые Нет новых   [134431   +15][b:0][p:0.004]