Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Синхронизация окон при использовании SetParent


Автор: NightWishMaster 31.7.2008, 14:34
На форме есть кнопка и панель. При нажатии на кнопку запускается Ворд и с помощью функции SetParent() запихивается в панельку. Код следующий (C++ Builder 6):

Код

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

TForm1 *Form1;
Variant WordApp;
int BorderSize, CaptionHeight;
HWND PanelHandle, WordHandle;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
  PanelHandle = NULL;
  WordHandle = NULL;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  //Находим хендл окна панельки.
  POINT p;
  p.x = 5; p.y = 5;
  PanelHandle = WindowFromPoint(Panel1->ClientToScreen(p));

  //Запускаем Ворд и определяем хендл его окна.
  WordApp = ::CreateOleObject("Word.Application");
  WideString WordCaption = WordApp.OlePropertyGet("Caption");
  WordApp.OlePropertySet("Caption", "123");
  WordHandle = FindWindow(NULL, "123");
  WordApp.OlePropertySet("Caption", WordCaption);

  //Запихиваем Ворд в панельку. Сознательно игнорируем то, что
  //"The new parent window and the child window must belong to the same application",
  //т.к. другого выхода нет. Игнорируем также то, что для окна Ворда надо было бы поменять
  //WS_POPUP на WS_CHILD, т.к. в таком случае пропадет меню и кнопочные панели, что не допустимо.
  ::SetParent(WordHandle, PanelHandle);

  //Размещаем Ворд так, чтобы не было видно его шапки и границ.
  WordApp.OlePropertySet("WindowState", 0);
  BorderSize = (Width - ClientWidth)/2;
  CaptionHeight = Height - ClientHeight - BorderSize;
  FormResize(Sender);
  WordApp.OlePropertySet("Visible", true);

  Button1->Caption = "Хватит!";
  Button1->Enabled = false;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormResize(TObject *Sender)
{
  //При изменении размеров формы изменяем размеры Ворда так, чтобы нигде не было видно шапки
  //и границ.
  if (WordHandle)
    {
      int NewX = - BorderSize;
      int NewY = - CaptionHeight;
      int NewWidth = Panel1->Width + 2*BorderSize;
      int NewHeight = Panel1->Height + CaptionHeight + BorderSize;
      SetWindowPos(WordHandle, NULL, NewX, NewY, NewWidth, NewHeight, SWP_ASYNCWINDOWPOS | SWP_NOZORDER);
    }  
}
//---------------------------------------------------------------------------


При изменении размеров формы Ворд автоматически подстраивается так, чтобы не было видно его границ и шапки. Используется функция SetWindowPos(), в которую передаем флаг 
SWP_ASYNCWINDOWPOS. Вот его описание в MSDN:

Цитата

SWP_ASYNCWINDOWPOS 
If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request.


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

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

Код

EnumChildWindows(WordHandle, (WNDENUMPROC)EnumChildProc, (LPARAM)0);

BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
  {
    SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_ASYNCWINDOWPOS | SWP_DEFERERASE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
    return TRUE;
  }


Но на ситуацию это не повлияло. Как думаете – в чем проблема? Почему пока не измениш, например, масштаб отображения документа (но не только это, та же ситуация при нажатии на некоторые кнопки Ворда, хотя и не все) все работает нормально. А когда измениш – начинает стопорится?

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

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

Автор: GremlinProg 31.7.2008, 23:24
попробуй добавить ворду стиль WS_CHILD

Автор: NightWishMaster 31.7.2008, 23:34
Цитата(GremlinProg @  31.7.2008,  23:24 Найти цитируемый пост)
попробуй добавить ворду стиль WS_CHILD 

Я писал в коментах кода, что мне это не приемлемо, т.к. в таком случае пропадает меню и панельки Ворда (дочернее окно "не имеет права" иметь меню, насколько я понял из МСДН). Я сознательно не менял стиль окна Ворда.

Проблема решается заменой функции SetWindowPos на MoveWindow:

Код

MoveWindow(WordHandle, NewX, NewY, NewWidth, NewHeight, TRUE);

Автор: rubic 3.9.2008, 04:34
Цитата(NightWishMaster @  31.7.2008,  14:34 Найти цитируемый пост)
 //Запихиваем Ворд в панельку. Сознательно игнорируем то, что
  //"The new parent window and the child window must belong to the same application",
  //т.к. другого выхода нет.

Не нашел такого в MSDN...
http://msdn.microsoft.com/en-us/library/ms633541(VS.85).aspx
или искал не там?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)