0

I want to create a COM control in Win32 by clsid: {3523C2FB-4031-44E4-9A3B-F1E94986EE7F} and then use the api QueryInterface to send commands to it. In MFC project this would be very simple in 4 lines of code:

m_wndMsTsc.CreateControl(L"{3523C2FB-4031-44E4-9A3B-F1E94986EE7F}", NULL, WS_VISIBLE, CRect(10, 10, 470, 280), this,0))
LPUNKNOWN lpUnk = m_wndMsTsc.GetControlUnknown();
lpUnk->QueryInterface(IID_IMsRdpClient5, (void**)&m_pMsTsc);
lpUnk->QueryInterface(IID_IMsRdpClientNonScriptable5, (void**)&pns);

In Win32 what i tried so far:

container = ::CreateWindow(L"EDIT",L"", WS_CHILD | WS_VISIBLE, 0, 0, rect.right, rect.bottom, mainWindow, 0, hInstance, 0);
IMsRdpClient5 *rdpClient = NULL;
// Then initialize com control
CoInitialize(0);
CoCreateInstance(CLSID_MsRdpClient5, 0, CLSCTX_ALL, IID_IMsRdpClient5, (void**)&rdpClient);
// Attach
AtlAxAttachControl(rdpClient, container, 0);
IUnknown *pUnk = NULL;
AtlAxGetControl(container, &pUnk);
pUnk->QueryInterface(IID_IMsRdpClient5, (void**)&rdpClient);

A very basic example how to create a control by clsid and attach it to IUnknown would be very helpful!

Clarke
  • 63
  • 9
  • Parent window is mainWindow hwnd. I also tried to CreateWindow by resource using: CONTROL "{3523C2FB-4031-44E4-9A3B-F1E94986EE7F}", 802L, "AX", WS_CHILD | WS_VISIBLE, 0, 0, 500, 400. – Clarke Nov 24 '16 at 07:10
  • You don't need an HWND to work with ActiveX controls. All COM interfaces derive from `IUnknown`. `CoCreateInstance()` is already giving you `IMsRdpClient5`, simply query it as-is for `IID_IMsRdpClientNonScriptable5`. – Remy Lebeau Nov 24 '16 at 07:29
  • MFC provides you with a ready-to-use solution of ActiveX Control host. You initialize it with a CLSID and you are good to go: MFC does the magic of UI embedding. You just don't have with plain Win32. You have to implement the host from the ground up. `AtlAxAttachControl` is not Win32, it's ATL which is basically a layer close (roughly) to MFC. It does have its own host (\atlmfc\include\atlhost.h might be a good starting point to look from). – Roman R. Nov 24 '16 at 09:40
  • I tried Remy Lebeau advice but still no success. CoCreateInstance(CLSID_MsRdpClient5, 0, CLSCTX_INPROC_SERVER, IID_IMsRdpClient5, (void**)&lpUnk); lpUnk->QueryInterface(IID_IMsRdpClientNonScriptable5, (void**)&rdpClientNonScriptable); when i call rdpClient->Connect(); the com control doesnt appear – Clarke Nov 24 '16 at 10:37
  • *"A very basic example how to create a control by clsid and attach it to IUnknown would be very helpful!"* - You already have that. Visual Studio ships the entire source code for MFC (and ATL). What are you really looking for? Are you asking how to use COM (or ActiveX controls) without understanding COM? – IInspectable Nov 24 '16 at 12:30
  • I did look through mfc source and I tried Trial and Error method dozen ways but still can't get the rdp window to connect, all i get is empty form without any activex control. I only need to create the rdp window and query the interface.. the rest i know how to implement – Clarke Nov 24 '16 at 13:06
  • Trial and error isn't very effective, if you ignore to check for errors (like in your call to `CoInitialize`). – IInspectable Nov 24 '16 at 18:52
  • I'm sure just using CoInitialize() won't create the control. I was trying to CreateWindow("{3523c2fb-4031... (CLSID of MsTscAx)" then pick up IUnknown pointer using AtlAxGetControl(). I've seen this method work for browser but i'm confused why it doesn't work for rdp client ? – Clarke Nov 24 '16 at 21:58
  • @Clarke: like IInspectable said, you have the source code for MFC, so just look at how `CreateControl()` is implemented and copy the logic to your own code. – Remy Lebeau Nov 24 '16 at 23:08

1 Answers1

2
    HRESULT hr = AtlAxWinInit();
    HWND hWnd = CreateWindow(_T("AtlAxWin"), _T("{3523C2FB-4031-44E4-9A3B-F1E94986EE7F}"), WS_CHILD | WS_VISIBLE, 10, 10, 400, 300, hwnd, (HMENU)102, NULL, NULL);
    IUnknown *unkn;          
    hr = AtlAxGetControl(hWnd, &unkn);
    unkn->QueryInterface(IID_IMsRdpClient5, (void**)&rdpClient);
    unkn->QueryInterface(IID_IMsRdpClientNonScriptable5, (void**)&rdpClientNonScriptable);\

This method works perfectly in Win32. Thanks everyone for ideas

Clarke
  • 63
  • 9