Russian Qt Forum
Ноябрь 25, 2024, 09:04 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Перепиcать MFC на ActiveQt  (Прочитано 3949 раз)
grdima
Гость
« : Август 10, 2017, 18:56 »

Жизнь сложилать таким образом что мне необходимо переписать некоторое простое приложение с использованием MFC, ATL, COM+ и всего веселого, на ActiveQt.
Прошу помощи в этом деле, т.к. перерыл все что только можно, так и не понял.

Это приложение использует API основанное та технологии COM, есть две машины расположенных в локальной сети и в одной рабочей группе. На одной устанавливается и регистрируется COM server, на второй (на которой должен работать мой клиент) он также регистрируется и указавается адрес соседней машины.

Вот выдержка из документации по API (Изображения во вложении):

Цитировать
    Component Model Diagram
  • 1. The Communication Server serves as concentrator for communication with the access control hardware located at customers locations.
  • 2. The Accw.dll acts as a remote DCOM server that communicates with the client and the WIN-PAK SE/PE communication server. The Accw.dll contains the buisness component, IMTSCBServer is an interface that contains the various API calls WINPAK SE/PE Communication Server functionalities. The client is informed about the events and alarms using COM/DMOC callbacks mechanism and tag based protocol.
  • 3. The Communication Server API Client is a Windows client application that monitors the events/alarms of the hardware devices at the costomer locations.

И вторая цитата:

Цитировать
Protocol Process
The client application initiates the connection to the WIN-PAK SE/PE by passing a reference using the InitServer(IDispatch* Caller, ...) method. The server responds to the call using the GotMessage(sMassage) method to notify the client of any events. In addition, the server notifiers the client abouterrors in the server using the method ServerErrors(sErrorMessage).

The procedural steps for communication between the ActiveX enabled client application and server are as follows:
  • 1. The client derives the IWPAVCallBack interface and implements; the GotMessage() and ServerError() methods. The client calls the ACCW.MTSCBServer::InitServer method and passes the reference of the class that implemnents the IWPAVCallBack interface.
  • 2. The Communication server wrapper ACCW.dll contains the compiled WIN-PAK SE/PE communication server APIs. These APIs act as interface between the client and the communication server. The Communication server collects the information about the events generated in the hardware panels.
  • 3. The ACCW.dll sends information about any events as a parameter in the GotMessage() method.

В оригинальном приложении существует класс
[/list]
Код:
class CClientClass : 
public IDispatchImpl<IClientClass, &IID_IClientClass, &LIBID_VCClient>,
public ISupportErrorInfo,
public CComObjectRoot,
public CComCoClass<CClientClass,&CLSID_ClientClass>,
//public IDispatchImpl<IWPAVCallBack, &IID_IWPAVCallBack, &LIBID_Accw>
public IDispEventImpl<1, CClientClass,
&IID_IWPAVCallBack, &LIBID_Accw, 1, 0> //Implement the IWPAVCallBack interface to support events from Winpak CommServer API
{
public:
CStringList m_szListInput;  // List of messages from Winpak CommServer API

public:
CClientClass() {}
~CClientClass() { m_szListInput.RemoveAll();}

BEGIN_COM_MAP(CClientClass)
//DEL COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IClientClass)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY2(IDispatch, IClientClass)
// COM_INTERFACE_ENTRY(IWPAVCallBack)
COM_INTERFACE_ENTRY_IID(IID_IWPAVCallBack, IDispatch)
END_COM_MAP()
//DECLARE_NOT_AGGREGATABLE(CClientClass)
// Remove the comment from the line above if you don't want your object to
// support aggregation.


// Add to Event Sink Map : Declaring the handler function of Winpak CommServer API
BEGIN_SINK_MAP(CClientClass)
      SINK_ENTRY_EX(1, IID_IWPAVCallBack, 1, GotMessage)
 SINK_ENTRY_EX(1, IID_IWPAVCallBack, 2, ServerError)
END_SINK_MAP()


DECLARE_REGISTRY_RESOURCEID(IDR_ClientClass)
// ISupportsErrorInfo
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
// IClientClass

CString GetFieldFromInput(CString szInput,CString szField)
{

int iStartPos = szInput.Find("<" + szField,0);
if(iStartPos >= 0)
{
int iSize = szField.GetLength();
int iLastPos = szInput.Find("</" + szField,iStartPos+1);

iSize = iStartPos + 2 + iSize;
iLastPos = iLastPos -  iSize;
return(szInput.Mid(iSize,iLastPos));
}
else
return("");

}
// IWPAVCallBack - Implementation
STDMETHOD(GotMessage)(BSTR bstrTranInfo)
{
    AFX_MANAGE_STATE(AfxGetAppModuleState())

/* CString sInput;
CString sAcctName="Account1";

sInput = CString(bstrTranInfo);

CString sRes = GetFieldFromInput(sInput,"Account");

if(sRes == sAcctName || sRes.IsEmpty())
{

m_szListInput.AddHead(CString(bstrTranInfo));
}*/

m_szListInput.AddHead(CString(bstrTranInfo));

return E_NOTIMPL;
}

STDMETHOD(ServerError)(BSTR bstrErrorInfo)
{
AfxMessageBox(CString(bstrErrorInfo));
return E_NOTIMPL;
}


};

И вот обраотчик нажатия на кнопку логина:
Код:
void CWPCommLoginDlg::OnLogin() 
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);

CString sDomainName;

int iSel = m_CmbDomain.GetCurSel();
if(m_CmbDomain.GetCount() > 0 && iSel<0)
return;
m_CmbDomain.GetLBText(iSel, sDomainName);

VARIANT_BOOL pbResult;
HRESULT hRes;

hRes = CComObject<CClientClass>::CreateInstance(&(m_pParent->m_pCallback));
hRes = m_pParent->m_pServer.CreateInstance("accw.MTSCBServer");

BSTR bstrUser = m_strUname.AllocSysString();
BSTR bstrPswd = m_strPassword.AllocSysString();
BSTR bstrDomain = sDomainName.AllocSysString();


hRes = m_pParent->m_pServer->InitServer2(m_pParent->m_pCallback,3,bstrUser,bstrPswd, bstrDomain, 1, &pbResult);

if(FAILED(hRes))
{
AfxMessageBox(_T("Login Fail Due to Unknown COM Failure"));
m_pParent->m_pServer->Release();
m_bLogin = FALSE;
}
else if(VARIANT_FALSE == pbResult)
{
AfxMessageBox(_T("Login Fail Due Invalid Credentials or\n WP DB Server Unavailable"));
m_pParent->m_pServer->Release();
m_bLogin = FALSE;
}
else
m_bLogin = TRUE;

::SysFreeString(bstrUser);
::SysFreeString(bstrPswd);

CDialog::OnOK();
}


Все то же самое мне нужно сделать с помощью ActiveQt. При ригистрации API на клиентской машине инсталлятор также ложит в папку с MFC клиентом файл accw.tlb, который я использую для генерации accw.h+accw.cpp
c помощью dumpcpp в *.pro файле

Код:
TYPELIBS = $$system(dumpcpp -getfile {F8EFDA04-97DF-11D3-9438-00902730004E})

Все делает мой класс Client
Код
C++ (Qt)
#include "accw.h"
#include <QAxObject>
#include <windows.h>
#include <QAxAggregated>
#include <QUuid>
 
using namespace Accw;
class Client : public IWPAVCallBack
{
 
public:
struct AccwCredentials {
wpviewTYPE type;
QString login;
QString password;
int userid;
};
 
explicit Client(IDispatch* subobject = 0, QAxObject *parent = 0);
bool Connect(AccwCredentials credentials);
bool Connect(wpviewTYPE type, const QString &login, const QString &password, int userid);
 
 
};
 

Вот его реализация:
Код
C++ (Qt)
#include "client.h"
#include <QDebug>
#include <QUuid>
#include <windows.h>
#include <OleAuto.h>
 
Client::Client(IDispatch* subobject, QAxObject* parent) :
IWPAVCallBack(subobject, parent)
{
}
 
bool Client::Connect(wpviewTYPE type, const QString& login, const QString& password, int userid)
{
MTSCBServer* accw = new MTSCBServer;
 
IDispatch* disp = nullptr;
 
queryInterface(IID_IDispatch, (void**)disp);
 
bool result = accw->InitServer(disp, type, login, password, userid);
 
if (!result){
accw->clear();
}
return result;
}
 
bool Client::Connect(Client::AccwCredentials credentials)
{
return Connect(credentials.type, credentials.login, credentials.password, credentials.userid);
}
 

После вызова  
Код
C++ (Qt)
MTSCBServer* accw = new MTSCBServer;
на удаленной машине инстанциируется COM server (это видно в dcomcnfg консоли)

Но вот как мне для выполнения вызова
Код
C++ (Qt)
bool result = accw->InitServer(disp, type, login, password, userid);

вытащить IDispatch* из класса Client? Что нужно сделать для реализации IWPAVCallBack интерфейса?

я пытаюсь сделать это с помощью
Код
C++ (Qt)
IDispatch* disp = nullptr;
queryInterface(IID_IDispatch, (void**)disp);

но в результате
Код:
disp == nullptr

Подскажите как реализовать IWPAVCallBack с помощью ActiveQt, подобно MFС  примеру?
« Последнее редактирование: Август 10, 2017, 21:57 от grdima » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.133 секунд. Запросов: 20.