Я пытаюсь использовать MsRdpClient для подключения к серверу rdp и получения некоторых основных уведомлений.Теперь у меня та же проблема, что и у людей около 8 лет, я не нашел ответа, поэтому я снова поднимаю эту тему.У меня есть такой код, собранный из различных примеров того, как использовать rdp с winapi:
#include <Windows.h>
#include <CommCtrl.h>
#include <tchar.h>
#include "resource.h"
#include <atlbase.h>
#include <exdisp.h>
#include "mstscax.tlh"
#include "mstscax.tli"
using namespace MSTSCLib;
class CTscEventSink : public IMsTscAxEvents
{
public:
CTscEventSink()
{
_ulRefs = 1;
m_dwEvtCookie = 0;
}
~CTscEventSink()
{
}
BOOL Attach(IMsTscAx* pTscAx)
{
CComPtr<IConnectionPointContainer> cpCPCont;
HRESULT hr;
hr = pTscAx->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&cpCPCont);
if (FAILED(hr))
return FALSE;
hr = cpCPCont->FindConnectionPoint(__uuidof(IMsTscAxEvents), &m_cpConnect);
if (FAILED(hr))
{
return FALSE;
}
hr = m_cpConnect->Advise(this, &m_dwEvtCookie);
if (FAILED(hr))
{
m_dwEvtCookie = 0;
return FALSE;
}
return TRUE;
}
void Detach()
{
if ((m_dwEvtCookie) && (m_cpConnect))
m_cpConnect->Unadvise(m_dwEvtCookie);
if (m_cpConnect)
m_cpConnect = NULL;
}
//IUnknown Methods
STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppv)
{
if (riid == __uuidof(IMsTscAxEvents))
{
*ppv = (IMsTscAxEvents *)this;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHOD_(ULONG, AddRef) (void)
{
InterlockedIncrement((LONG*)&_ulRefs);
return _ulRefs;
}
STDMETHOD_(ULONG, Release) (void)
{
ULONG ulRefs = _ulRefs;
if (InterlockedDecrement((LONG*)&_ulRefs) == 0)
{
delete this;
return 0;
}
return _ulRefs;
}
HRESULT OnConnecting()
{
DebugBreak();
::MessageBoxA(NULL, "Connecting", "", 0);
}
HRESULT OnConnected()
{
DebugBreak();
::MessageBoxA(NULL, "Connected", "", 0);
}
HRESULT OnFatalError()
{
DebugBreak();
::MessageBoxA(NULL, "Fatal Error", "", 0);
}
HRESULT OnLoginComplete()
{
DebugBreak();
::MessageBoxA(NULL, "Login complete", "", 0);
}
HRESULT OnLogonError(
long lError)
{
DebugBreak();
::MessageBoxA(NULL, "OnLogonError", "", 0);
}
HRESULT OnDisconnected(
long discReason)
{
DebugBreak();
::MessageBoxA(NULL, "OnDisconnected", "", 0);
}
//IDispatch Methods
STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo)
{
return E_NOTIMPL;
}
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
{
return E_NOTIMPL;
}
STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, UINT cNames,
LCID lcid, DISPID FAR* rgdispid)
{
return E_NOTIMPL;
}
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr)
{
return S_OK;
}
protected:
ULONG _ulRefs;
DWORD m_dwEvtCookie;
CComPtr<IConnectionPoint> m_cpConnect;
};
CTscEventSink * pCTscEventSink;
MSTSCLib::IMsRdpClient2* pInterface = NULL;
LRESULT CALLBACK WindowProc(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
switch (messg)
{
case WM_SIZE:
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam));
}
return 0;
}
int CALLBACK wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wndclass;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = &WindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = reinterpret_cast <HBRUSH> (COLOR_BTNFACE + 1);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = L"RdpTest1";
::RegisterClass(&wndclass);
HWND mainWindow = ::CreateWindow(
L"RdpTest1",
L"Rdp!",
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
800,
NULL,
NULL,
hInstance,
0);
::ShowWindow(mainWindow, nCmdShow);
::UpdateWindow(mainWindow);
//ocx
typedef HRESULT(WINAPI *PFonc)(IUnknown*, HWND, IUnknown**);
HINSTANCE hDLL2 = ::LoadLibrary(TEXT("atl.dll"));
if (!hDLL2)
return 1;
PFonc AtlAxAttachControl = (PFonc) ::GetProcAddress(hDLL2, "AtlAxAttachControl");
HRESULT hr = ::CoInitialize(0);
HRESULT hrInit = CoInitialize(NULL);
if (FAILED(hrInit)) return 0;
CLSID clsid = __uuidof(MSTSCLib::MsRdpClient2);
IID iid = __uuidof(MSTSCLib::IMsRdpClient2);
HRESULT hrInterface = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void**)&pInterface);
if (SUCCEEDED(hrInterface))
{
pCTscEventSink = new CTscEventSink();
BOOL b = pCTscEventSink->Attach(pInterface);
pInterface->PutServer(L"non_existing_server.lol");
pInterface->PutFullScreen(VARIANT_TRUE);
pInterface->PutDesktopWidth(GetSystemMetrics(SM_CXSCREEN));
pInterface->PutDesktopHeight(GetSystemMetrics(SM_CYSCREEN));
pInterface->PutUserName(L"some_incorrect_user");
pInterface->AdvancedSettings2->PutClearTextPassword(L"some_incorrect_pass");
pInterface->AdvancedSettings2->PutRDPPort(3389);
IMsRdpExtendedSettings *pExtendedSetting = NULL;
IID interface_MsRdpClient8NotSafeForScripting = __uuidof(MSTSCLib::MsRdpClient2NotSafeForScripting);
HRESULT hr = pInterface->QueryInterface(interface_MsRdpClient8NotSafeForScripting, (void**)&pExtendedSetting);
if (hr == S_OK)
{
VARIANT index;
VariantInit(&index);
V_VT(&index) = VT_BOOL;
index.boolVal = VARIANT_TRUE;
pExtendedSetting->put_Property((BSTR)L"DisableCredentialsDelegation", &index);
}
hr = AtlAxAttachControl(pInterface, mainWindow, 0);
if (FAILED(hr)) {
MessageBox(0, L"FAILED(AtlAxAttachControl(pitd, container, NULL))", L"Error", MB_ICONERROR | MB_OK);
}
HRESULT hrConnect = pInterface->Connect();
if (FAILED(hrConnect))
{
MessageBoxW(NULL, L"pInterface->Connect()", L"Error", 0);
}
else MessageBoxW(NULL, L"pInterface->Connect() Success!!!", L"Success", 0);
}
else
{
wchar_t buf[16] = { 0 };
_ltow(hrInterface, buf, 16);
MessageBoxW(NULL, buf, L"CoCreateInstance failed", 0);
}
::MSG message;
while (::GetMessageA(&message, 0, 0, 0)) {
switch (message.message) {
case WM_QUIT:
break;
default:
::TranslateMessage(&message);
::DispatchMessage(&message);
break;
}
}
CoUninitialize();
FreeLibrary(hDLL2);
return 0;
}
Хорошо, так что я делаю в этом коде.Я создаю окно, создаю объект MSTSCLib::IMsRdpClient2* pInterface
, присоединяю класс приемника событий, чтобы перехватывать события, к этому объекту и передаю ему недопустимые данные.Но никакие события не запускаются, OnFatalError, OnConnecting и т. Д. Никогда не вызывались, и HRESULT hrConnect = pInterface->Connect();
всегда возвращает S_OK
, независимо от того, какой сервер / пользователь / пароль.Из того, что я понял, это поведение связано с реализацией Invoke
в CTscEventSink
Мне нужно сделать что-то внутри:
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr)
{
return S_OK;
}
Вместо того, чтобы просто возвращать S_OK
, мне нужно что-то сделать, чтобына самом деле передать команду подключения дальше.Может кто-нибудь помочь, что мне здесь делать ??Как то, что позвонить из Invoke ??Это загадка, и я не знаю примеров, и ни одна страница MSDN не говорит об этом.