Синхронизация перерисовки окна, вставленного через SetParent

Тема в разделе "WASM.WIN32", создана пользователем WishMaster, 31 июл 2008.

  1. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    На форме есть кнопка и панель. При нажатии на кнопку запускается Ворд и с помощью функции SetParent() запихивается в панельку. Код следующий (C++ Builder 6):

    Код (Text):
    1. #include <vcl.h>
    2. #pragma hdrstop
    3.  
    4. #include "Unit1.h"
    5. //---------------------------------------------------------------------------
    6. #pragma package(smart_init)
    7. #pragma resource "*.dfm"
    8.  
    9. TForm1 *Form1;
    10. Variant WordApp;
    11. int BorderSize, CaptionHeight;
    12. HWND PanelHandle, WordHandle;
    13.  
    14. //---------------------------------------------------------------------------
    15. __fastcall TForm1::TForm1(TComponent* Owner)
    16.         : TForm(Owner)
    17. {
    18.   PanelHandle = NULL;
    19.   WordHandle = NULL;
    20. }
    21. //---------------------------------------------------------------------------
    22.  
    23. void __fastcall TForm1::Button1Click(TObject *Sender)
    24. {
    25.   //Находим хендл окна панельки.
    26.   POINT p;
    27.   p.x = 5; p.y = 5;
    28.   PanelHandle = WindowFromPoint(Panel1->ClientToScreen(p));
    29.  
    30.   //Запускаем Ворд и определяем хендл его окна.
    31.   WordApp = ::CreateOleObject("Word.Application");
    32.   WideString WordCaption = WordApp.OlePropertyGet("Caption");
    33.   WordApp.OlePropertySet("Caption", "123");
    34.   WordHandle = FindWindow(NULL, "123");
    35.   WordApp.OlePropertySet("Caption", WordCaption);
    36.  
    37.   //Запихиваем Ворд в панельку. Сознательно игнорируем то, что
    38.   //"The new parent window and the child window must belong to the same application",
    39.   //т.к. другого выхода нет. Игнорируем также то, что для окна Ворда надо было бы поменять
    40.   //WS_POPUP на WS_CHILD, т.к. в таком случае пропадет меню и кнопочные панели, что не допустимо.
    41.   ::SetParent(WordHandle, PanelHandle);
    42.  
    43.   //Размещаем Ворд так, чтобы не было видно его шапки и границ.
    44.   WordApp.OlePropertySet("WindowState", 0);
    45.   BorderSize = (Width - ClientWidth)/2;
    46.   CaptionHeight = Height - ClientHeight - BorderSize;
    47.   FormResize(Sender);
    48.   WordApp.OlePropertySet("Visible", true);
    49.  
    50.   Button1->Caption = "Хватит!";
    51.   Button1->Enabled = false;
    52. }
    53. //---------------------------------------------------------------------------
    54.  
    55. void __fastcall TForm1::FormResize(TObject *Sender)
    56. {
    57.   //При изменении размеров формы изменяем размеры Ворда так, чтобы нигде не было видно шапки
    58.   //и границ.
    59.   if (WordHandle)
    60.     {
    61.       int NewX = - BorderSize;
    62.       int NewY = - CaptionHeight;
    63.       int NewWidth = Panel1->Width + 2*BorderSize;
    64.       int NewHeight = Panel1->Height + CaptionHeight + BorderSize;
    65.       SetWindowPos(WordHandle, NULL, NewX, NewY, NewWidth, NewHeight, SWP_ASYNCWINDOWPOS | SWP_NOZORDER);
    66.     }  
    67. }
    68. //---------------------------------------------------------------------------
    При изменении размеров формы Ворд автоматически подстраивается так, чтобы не было видно его границ и шапки. Используется функция SetWindowPos(), в которую передаем флаг
    SWP_ASYNCWINDOWPOS. Вот его описание в MSDN:

    Если этот флаг не установить, то при попытке изменить размеры формы у нас происходит один вызов функции FormResize(), соответсветнно один вызов функции SetWindowPos(), размеры изменяются один раз и все – дальше движения мышки игнорируются и форма блокируется с такими размерами, пока не отпустишь и снова не потянешь за край формы. Если этот флаг стоит, то все норм, размеры Ворда синхронно изменяются, в том числе и с открытым документом. Но все это до поры, до времени :)

    Проблема возникает, если создать документ и, на пример, изменить масштаб его отображения (там где 25-50-100% и т.п.). После этого, несмотря на установленный флажок SWP_ASYNCWINDOWPOS в вызове функции SetWindowPos() все равно наблюдается описанная выше ситуация – изменения размеров происходит один раз и блокируется. Я пробовал ставить еще флажок SWP_DEFERERASE (Prevents generation of the WM_SYNCPAINT message), но это не исправляет ситуацию. Так же была мысль, что надо посылать всем дочерним окнам в моем окне ворда также сообщения с флажком SWP_ASYNCWINDOWPOS. Попробовал это с помощью функции EnumChildWindows():

    Код (Text):
    1. EnumChildWindows(WordHandle, (WNDENUMPROC)EnumChildProc, (LPARAM)0);
    2.  
    3. BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
    4.   {
    5.     SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_ASYNCWINDOWPOS | SWP_DEFERERASE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
    6.     return TRUE;
    7.   }
    Но на ситуацию это не повлияло. Как думаете – в чем проблема? Почему пока не измениш, например, масштаб отображения документа (но не только это, та же ситуация при нажатии на некоторые кнопки Ворда, хотя и не все) все работает нормально. А когда измениш – начинает стопорится?

    Буду благодарен за любые размышления :)

    ПС. Прикрепил исходник на C++ Builder (там есть и екзешник – для работы нужен только установленный Ворд) - если у кого возникнет желание посмотреть, о чем это я :)
     
  2. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    Проблема решается заменой функции SetWindowPos на MoveWindow:

    Код (Text):
    1. MoveWindow(WordHandle, NewX, NewY, NewWidth, NewHeight, TRUE);