1 / 1 / 2
Регистрация: 13.02.2015
Сообщений: 19
1

COM & C++ & MDI

13.02.2015, 22:22. Показов 2051. Ответов 7
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет.

Совсем недавно стал постигать азы технологии COM на своем "рабочем" языке С++. Благодаря MSDN научился создавать простенькие com серверы и использовать их в приложениях. Но недавно столкнулся с задачей, которую уже долгое время не могу решить. Надеюсь на вашу помощь.

Задача следующая. Имеется MDI приложение, в котором есть возможность добавления нового функционала с помощью сторонних модулей. Предположительно, написано на delphi. Исходного кода нет. Необходимо написать COM модуль на С++, который создавал бы дочернее окно в рабочей области приложения и выполнял бы некоторый функционал.

Проблема как раз в создании дочернего окна в MDI через COM модуль. С помощью каких средств это можно реализовать?

Если необходимо, могу предоставить код com модуля, который пока только создает диалоговое окно. Предполагается, что дочернее окно должно создаваться после закрытия диалога.

Заранее спасибо за ответ.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.02.2015, 22:22
Ответы с готовыми решениями:

ActiveDirectory & C++
Всем здравствуйте!!! В общем возникла такая задача написать функции для работы с АД 1 функция...

C++ & OpenOffice SDK
Всем привет. Недавно появилась задача из приложения, написанного на языке С++, выгрузки данных в...

IShellLink & IPersistFile - создание ярлыка
Приветствую всех. Написал следующий код : IShellLink* ISH; IPersistFile* IPF;...

Вывод типа, универсальные ссылки, cannot bind lvalue to && и другие
Доброго дня, товарищи. Вот код: Вот отчет компиля: Объясните мне, пожалуйста, где я не прав....

7
Модератор
3398 / 2170 / 352
Регистрация: 13.01.2012
Сообщений: 8,400
17.02.2015, 09:26 2
если описанный функционал создания левых окон внутри приложения не заложен в программе не ясно как вы все это собираетесь сделать по-человечески
1
1 / 1 / 2
Регистрация: 13.02.2015
Сообщений: 19
19.02.2015, 21:12  [ТС] 3
Цитата Сообщение от vxg Посмотреть сообщение
если описанный функционал создания левых окон внутри приложения не заложен в программе не ясно как вы все это собираетесь сделать по-человечески
То есть, я так понимаю, что сторонними средствами ( типа ActiveX ) какими-то это реализовать невозможно? Чисто теоретически, остается же вариант написания COM модуля на "родном" для приложения языке, или все равно не получится?

А так, конечно, буду выяснить у разработчиков, реализован у них такой функционал или нет.
0
Модератор
3398 / 2170 / 352
Регистрация: 13.01.2012
Сообщений: 8,400
20.02.2015, 09:11 4
Цитата Сообщение от Pele-Saratov Посмотреть сообщение
реализован у них такой функционал или нет
COM-это не волшебство - это ммм... некий способ заставить некую сущность проделать некие действия. если эта сущность не реализована, то о чем речь? из общих способов программно заставить другое приложение проделать некие действия приходит на ум разве что DDE - сам никогда не пользовался, по слухам это такая штука которая "прикидывается" действиями обычного пользователя: типа кликнул на кнопочку, ввел текст, поставил галочку
1
1 / 1 / 2
Регистрация: 13.02.2015
Сообщений: 19
13.02.2017, 19:22  [ТС] 5
Всем привет. Поднимаю тему спустя 2 года. Но задачу уже можно "пощупать".

Задача все та же: есть MDI приложение, написанное на MFC+QT, - такой вот гибрид. Система умеет работать с COM. Нужно с помощью отдельных COM-модулей дорабатывать систему. В частности, создавать свой интерфейс на любом языке программирования, поддерживающий COM, и размещать его на клиенте в рабочей области главного окна.

Как работает клиент: при выборе заданного пункта меню, он вызывает наперед известный ему метод интерфейса. Структура интерфейса очень простая:
C++
1
2
3
4
interface ITask : IUnknown {
    HRESULT Run([in]HWND hWndParent,[out]HWND*created_wnd,[out]long*error_code);
 
};
В общем, все понятно: реализовываем данный метод внутри своего модуля, создаем в нем нужный функционал, дочернему окну назначаем родителя и, по идее, все должно работать. Казалось бы, но...

Смоделировал работу клиента и сервера на простеньком примере:

1. COM модуль, который реализует необходимый метод. Метод создает пустое дочернее окно в рабочей области;
2. простое MDI приложение, написанное на MFC, содержит только пункты меню и рабочую область. При выборе пункта меню, вызывается COM модуль.

Клиент:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class CMDIMainFrame : public CMDIFrameWndEx {
    DECLARE_DYNAMIC(CMDIMainFrame)
    public:
        CMDIMainFrame(CWnd *pWnd = 0);
        virtual ~CMDIMainFrame();
 
    protected:
        afx_msg void OnFileNew(); // при данном сообщение вызывается com-модуль
 
        DECLARE_MESSAGE_MAP();
 
};
 
IMPLEMENT_DYNAMIC(CMDIMainFrame, CMDIFrameWndEx)
 
BEGIN_MESSAGE_MAP(CMDIMainFrame, CMDIFrameWndEx)
    ON_COMMAND(ID_FILE_NEW, OnFileNew)
END_MESSAGE_MAP()
 
CMDIMainFrame::CMDIMainFrame(CWnd *pWnd) {}
CMDIMainFrame::~CMDIMainFrame() { }
 
void CMDIMainFrame::OnFileNew() {   
    IClassFactory *factory = 0;
    ITask *iTest = 0;
    HWND hWnd = this->GetSafeHwnd(); // главное окно для передачи модулю
 
    HRESULT h = CoGetClassObject(
        CLSID_TaskClass,
        CLSCTX_INPROC_SERVER,
        NULL,
        IID_IClassFactory,
        reinterpret_cast<void **>(&factory));
 
        HWND created_wnd = 0;
        long error_code = 0;        
 
    h = factory->CreateInstance(NULL, IID_ITask, (void **)&iTest);
    h = iTest->Run(hWnd, &created_wnd, &error_code);
 
    iTest->Release();
    factory->Release();
 
}
Метод в модуле COM
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class CChildWnd : public CMDIChildWnd {
    public:
        CChildWnd(){ };
        ~CChildWnd(){ };
};
 
STDMETHODIMP TaskClass::Run( HWND hWndParent, HWND *create_wnd, long *error_code ) { 
    CMDIFrameWnd *pFrameWnd = (CMDIFrameWnd *)CWnd::FromHandle(hWndParent);
    CChildWnd *pChildWnd = new CChildWnd;
    pChildWnd->Create(NULL, _T("Hello"), WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 
CFrameWnd::rectDefault, pFrameWnd );
 
        created_wnd = pChildWnd->GetSafeHwnd();
 
    return S_OK; 
}
 
+ фабрика классов, экспортируемые функции и т.д.  - все стандартно.
При вызове пункта меню дочернее окно, созданное в COM-модуле, в самом деле появляется внутри клиента. НО! При закрытии самого клиента возникает ошибка: ACCESS VIOLATION и отладчик указывает на строчку
C++
1
lResult = pWnd->WindowProc(nMsg, wParam, lParam);
файла wincore.cpp.

Запускаю WinDbg. Получаю такую же ошибку в mfc110u!AfxCallWndProc+0x93.
Последнее в стеке вызовов: win32u!NtUserMessageCall+0xc.

Если же перенести код из COM-объекта непосредственно в клиент, то такая ошибка не наблюдается.
Понятно, что ошибка возникает в обработчике событий на клиенте. Но почему? Что нужно сделать на стороне модуля, чтобы корректно "встроиться" в обработчик событий на клиенте? И возможно ли это?

Надеюсь на Вашу помощь, спасибо.
0
Модератор
3398 / 2170 / 352
Регистрация: 13.01.2012
Сообщений: 8,400
14.02.2017, 07:02 6
Pele-Saratov, не сильно вчитываясь - при уничтожении COM-объекта убейте окно которое он сделал или поменяйте оконную процедуру с сидящей внутри объекта на стандартную вне его
0
1 / 1 / 2
Регистрация: 13.02.2015
Сообщений: 19
14.02.2017, 19:29  [ТС] 7
Цитата Сообщение от vxg Посмотреть сообщение
...при уничтожении COM-объекта убейте окно которое он сделал...
Я правильно понимаю, что это на стороне клиента? И в какой момент происходит уничтожение com-объекта? Во время закрытия дочернего окна?
Дополнительно внутри модуля не нужно явно присоединять дочернее окно к обработчику сообщений рабочей области?

Цитата Сообщение от vxg Посмотреть сообщение
...или поменяйте оконную процедуру с сидящей внутри объекта на стандартную вне его
То есть, оконная процедура - на клиенте, а окно - на сервере? А как в этой ситуации окно присоединить к обработчику? Передавать обработчик в модуль через параметр?
0
Модератор
3398 / 2170 / 352
Регистрация: 13.01.2012
Сообщений: 8,400
15.02.2017, 11:11 8
Pele-Saratov, очень сумбурный поток...
мысли:
-в пункте меню вы создали фабрику и создали при помощи ее объект
-после этого вы освободили фабрику и объект - по идее они должны были уничтожится - ведь ссылок на них больше нет - как они у вас продолжают работать непонятно, возможно секрет в
Цитата Сообщение от Pele-Saratov Посмотреть сообщение
и т.д.
-в объекте вы создаете объект окна (нигде не сохраняя ссылку - непонятно кто его потом удалит)
-после чего объект окна создает собственно окно
-наверное (я не знаком с CChildWnd) оконная процедура лежит где-то в объекте окна
-когда окно в приложении закрывается оно начинает прибивать свои дочерние окна - если вдруг окажется что дочернее окно не знает о своем родителе или родитель не знает о своем дочернем окне (я не знаю устанавливает ли вызов pChildWnd->Create связь между окнами одинаково доступную как со стороны родительского так и со стороны дочернего окна), то какое-то из них может быть убито раньше времени или не убито вообще и обратиться к тому которое убито, <еще 1001 вариант плохого развития событий>
-что бы сделал я:
----получил ссылку на фабрику при запуске приложения (возможно вам вообще не нужна эта ссылка - почему вы не создаете объекты обычным способом при котором все манипуляции с фабрикой происходят неявно и пользователь получает уже готовую ссылку на объект?)
----при нажатии на пункт меню получил ссылку на объект
----вызвал метод Run
----перед закрытием окна освободил ссылки на объекты
----при создании объекта хранил бы в нем ссылку на объект окна
----при удалении объекта удалял бы окно предусмотренным для CChildWnd методом после чего удалял бы сам объект окна (возможно удаление объекта окна автоматически приводит к удалению окна)
----при закрытии приложения освободил ссылку на фабрику
0
15.02.2017, 11:11
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
15.02.2017, 11:11
Помогаю со студенческими работами здесь

Expression: c <= -1 && c >= 255
Пишу мини курсовую. На ввод принимаются только цифры. И нужна поставить проверку на ввод, то есть...

std::filesystem && std::asio и пр
Пытался найти хоть какие-то сроки включения всего этого в стандарт (так же ожидается lexical_cast,...

Auto&& and decltype(auto)
Приведите пример различия поведения заполнителей auto&amp;&amp; и decltype(auto).

Значение (i&(1<<j)
Вообщем писал такой вот код #include&lt;iostream&gt; #include&lt;math.h&gt; #define n 6 using namespace...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru