1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  *
4  * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include <winpr/crt.h>
24 #include <winpr/print.h>
25 #include <freerdp/log.h>
26 
27 #include "win_rdp.h"
28 
29 #include "win_wds.h"
30 
31 /**
32  * Windows Desktop Sharing API:
33  * http://blogs.msdn.com/b/rds/archive/2007/03/08/windows-desktop-sharing-api.aspx
34  *
35  * Windows Desktop Sharing Interfaces:
36  * http://msdn.microsoft.com/en-us/library/aa373871%28v=vs.85%29.aspx
37  *
38  * Offer Remote Assistance Sample C:
39  * http://msdn.microsoft.com/en-us/library/ms811079.aspx#remoteassistanceapi_topic2b
40  *
41  * Remote Assistance in XP: Programmatically establish an RDP session:
42  * http://www.codeproject.com/Articles/29939/Remote-Assistance-in-XP-Programmatically-establish
43  */
44 
45 #undef DEFINE_GUID
46 #define INITGUID
47 
48 #include <initguid.h>
49 
50 #include <freerdp/assistance.h>
51 
52 #define TAG SERVER_TAG("shadow.win")
53 
54 DEFINE_GUID(CLSID_RDPSession, 0x9B78F0E6, 0x3E05, 0x4A5B, 0xB2, 0xE8, 0xE7, 0x43, 0xA8, 0x95, 0x6B,
55             0x65);
56 DEFINE_GUID(DIID__IRDPSessionEvents, 0x98a97042, 0x6698, 0x40e9, 0x8e, 0xfd, 0xb3, 0x20, 0x09, 0x90,
57             0x00, 0x4b);
58 DEFINE_GUID(IID_IRDPSRAPISharingSession, 0xeeb20886, 0xe470, 0x4cf6, 0x84, 0x2b, 0x27, 0x39, 0xc0,
59             0xec, 0x5c, 0xfb);
60 DEFINE_GUID(IID_IRDPSRAPIAttendee, 0xec0671b3, 0x1b78, 0x4b80, 0xa4, 0x64, 0x91, 0x32, 0x24, 0x75,
61             0x43, 0xe3);
62 DEFINE_GUID(IID_IRDPSRAPIAttendeeManager, 0xba3a37e8, 0x33da, 0x4749, 0x8d, 0xa0, 0x07, 0xfa, 0x34,
63             0xda, 0x79, 0x44);
64 DEFINE_GUID(IID_IRDPSRAPISessionProperties, 0x339b24f2, 0x9bc0, 0x4f16, 0x9a, 0xac, 0xf1, 0x65,
65             0x43, 0x3d, 0x13, 0xd4);
66 DEFINE_GUID(CLSID_RDPSRAPIApplicationFilter, 0xe35ace89, 0xc7e8, 0x427e, 0xa4, 0xf9, 0xb9, 0xda,
67             0x07, 0x28, 0x26, 0xbd);
68 DEFINE_GUID(CLSID_RDPSRAPIInvitationManager, 0x53d9c9db, 0x75ab, 0x4271, 0x94, 0x8a, 0x4c, 0x4e,
69             0xb3, 0x6a, 0x8f, 0x2b);
70 
71 static ULONG Shadow_IRDPSessionEvents_RefCount = 0;
72 
GetRDPSessionEventString(DISPID id)73 const char* GetRDPSessionEventString(DISPID id)
74 {
75 	switch (id)
76 	{
77 		case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_CONNECTED:
78 			return "OnAttendeeConnected";
79 			break;
80 
81 		case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_DISCONNECTED:
82 			return "OnAttendeeDisconnected";
83 			break;
84 
85 		case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_UPDATE:
86 			return "OnAttendeeUpdate";
87 			break;
88 
89 		case DISPID_RDPSRAPI_EVENT_ON_ERROR:
90 			return "OnError";
91 			break;
92 
93 		case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTED:
94 			return "OnConnectionEstablished";
95 			break;
96 
97 		case DISPID_RDPSRAPI_EVENT_ON_VIEWER_DISCONNECTED:
98 			return "OnConnectionTerminated";
99 			break;
100 
101 		case DISPID_RDPSRAPI_EVENT_ON_VIEWER_AUTHENTICATED:
102 			return "OnConnectionAuthenticated";
103 			break;
104 
105 		case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTFAILED:
106 			return "OnConnectionFailed";
107 			break;
108 
109 		case DISPID_RDPSRAPI_EVENT_ON_CTRLLEVEL_CHANGE_REQUEST:
110 			return "OnControlLevelChangeRequest";
111 			break;
112 
113 		case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_PAUSED:
114 			return "OnGraphicsStreamPaused";
115 			break;
116 
117 		case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_RESUMED:
118 			return "OnGraphicsStreamResumed";
119 			break;
120 
121 		case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_JOIN:
122 			return "OnChannelJoin";
123 			break;
124 
125 		case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_LEAVE:
126 			return "OnChannelLeave";
127 			break;
128 
129 		case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_DATARECEIVED:
130 			return "OnChannelDataReceived";
131 			break;
132 
133 		case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_SENDCOMPLETED:
134 			return "OnChannelDataSent";
135 			break;
136 
137 		case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_OPEN:
138 			return "OnApplicationOpen";
139 			break;
140 
141 		case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_CLOSE:
142 			return "OnApplicationClose";
143 			break;
144 
145 		case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_UPDATE:
146 			return "OnApplicationUpdate";
147 			break;
148 
149 		case DISPID_RDPSRAPI_EVENT_ON_WINDOW_OPEN:
150 			return "OnWindowOpen";
151 			break;
152 
153 		case DISPID_RDPSRAPI_EVENT_ON_WINDOW_CLOSE:
154 			return "OnWindowClose";
155 			break;
156 
157 		case DISPID_RDPSRAPI_EVENT_ON_WINDOW_UPDATE:
158 			return "OnWindowUpdate";
159 			break;
160 
161 		case DISPID_RDPSRAPI_EVENT_ON_APPFILTER_UPDATE:
162 			return "OnAppFilterUpdate";
163 			break;
164 
165 		case DISPID_RDPSRAPI_EVENT_ON_SHARED_RECT_CHANGED:
166 			return "OnSharedRectChanged";
167 			break;
168 
169 		case DISPID_RDPSRAPI_EVENT_ON_FOCUSRELEASED:
170 			return "OnFocusReleased";
171 			break;
172 
173 		case DISPID_RDPSRAPI_EVENT_ON_SHARED_DESKTOP_SETTINGS_CHANGED:
174 			return "OnSharedDesktopSettingsChanged";
175 			break;
176 
177 		case DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED:
178 			return "OnViewingSizeChanged";
179 			break;
180 	}
181 
182 	return "OnUnknown";
183 }
184 
185 static HRESULT STDMETHODCALLTYPE
Shadow_IRDPSessionEvents_QueryInterface(__RPC__in _IRDPSessionEvents * This,__RPC__in REFIID riid,_COM_Outptr_ void ** ppvObject)186 Shadow_IRDPSessionEvents_QueryInterface(__RPC__in _IRDPSessionEvents* This,
187                                         /* [in] */ __RPC__in REFIID riid,
188                                         /* [annotation][iid_is][out] */
189                                         _COM_Outptr_ void** ppvObject)
190 {
191 	*ppvObject = NULL;
192 
193 	if (IsEqualIID(riid, &DIID__IRDPSessionEvents) || IsEqualIID(riid, &IID_IDispatch) ||
194 	    IsEqualIID(riid, &IID_IUnknown))
195 	{
196 		*ppvObject = This;
197 	}
198 
199 	if (!(*ppvObject))
200 		return E_NOINTERFACE;
201 
202 	This->lpVtbl->AddRef(This);
203 	return S_OK;
204 }
205 
Shadow_IRDPSessionEvents_AddRef(__RPC__in _IRDPSessionEvents * This)206 static ULONG STDMETHODCALLTYPE Shadow_IRDPSessionEvents_AddRef(__RPC__in _IRDPSessionEvents* This)
207 {
208 	Shadow_IRDPSessionEvents_RefCount++;
209 	return Shadow_IRDPSessionEvents_RefCount;
210 }
211 
Shadow_IRDPSessionEvents_Release(__RPC__in _IRDPSessionEvents * This)212 static ULONG STDMETHODCALLTYPE Shadow_IRDPSessionEvents_Release(__RPC__in _IRDPSessionEvents* This)
213 {
214 	if (!Shadow_IRDPSessionEvents_RefCount)
215 		return 0;
216 
217 	Shadow_IRDPSessionEvents_RefCount--;
218 	return Shadow_IRDPSessionEvents_RefCount;
219 }
220 
221 static HRESULT STDMETHODCALLTYPE
Shadow_IRDPSessionEvents_GetTypeInfoCount(__RPC__in _IRDPSessionEvents * This,__RPC__out UINT * pctinfo)222 Shadow_IRDPSessionEvents_GetTypeInfoCount(__RPC__in _IRDPSessionEvents* This,
223                                           /* [out] */ __RPC__out UINT* pctinfo)
224 {
225 	WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetTypeInfoCount");
226 	*pctinfo = 1;
227 	return S_OK;
228 }
229 
230 static HRESULT STDMETHODCALLTYPE
Shadow_IRDPSessionEvents_GetTypeInfo(__RPC__in _IRDPSessionEvents * This,UINT iTInfo,LCID lcid,__RPC__deref_out_opt ITypeInfo ** ppTInfo)231 Shadow_IRDPSessionEvents_GetTypeInfo(__RPC__in _IRDPSessionEvents* This,
232                                      /* [in] */ UINT iTInfo,
233                                      /* [in] */ LCID lcid,
234                                      /* [out] */ __RPC__deref_out_opt ITypeInfo** ppTInfo)
235 {
236 	WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetTypeInfo");
237 	return E_NOTIMPL;
238 }
239 
240 static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_GetIDsOfNames(
241     __RPC__in _IRDPSessionEvents* This,
242     /* [in] */ __RPC__in REFIID riid,
243     /* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR* rgszNames,
244     /* [range][in] */ __RPC__in_range(0, 16384) UINT cNames,
245     /* [in] */ LCID lcid,
246     /* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID* rgDispId)
247 {
248 	WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetIDsOfNames");
249 	return E_NOTIMPL;
250 }
251 
Shadow_IRDPSessionEvents_Invoke(_IRDPSessionEvents * This,_In_ DISPID dispIdMember,_In_ REFIID riid,_In_ LCID lcid,_In_ WORD wFlags,_In_ DISPPARAMS * pDispParams,_Out_opt_ VARIANT * pVarResult,_Out_opt_ EXCEPINFO * pExcepInfo,_Out_opt_ UINT * puArgErr)252 static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_Invoke(_IRDPSessionEvents* This,
253                                                                  /* [annotation][in] */
254                                                                  _In_ DISPID dispIdMember,
255                                                                  /* [annotation][in] */
256                                                                  _In_ REFIID riid,
257                                                                  /* [annotation][in] */
258                                                                  _In_ LCID lcid,
259                                                                  /* [annotation][in] */
260                                                                  _In_ WORD wFlags,
261                                                                  /* [annotation][out][in] */
262                                                                  _In_ DISPPARAMS* pDispParams,
263                                                                  /* [annotation][out] */
264                                                                  _Out_opt_ VARIANT* pVarResult,
265                                                                  /* [annotation][out] */
266                                                                  _Out_opt_ EXCEPINFO* pExcepInfo,
267                                                                  /* [annotation][out] */
268                                                                  _Out_opt_ UINT* puArgErr)
269 {
270 	HRESULT hr;
271 	VARIANT vr;
272 	UINT uArgErr;
273 	WLog_INFO(TAG, "%s (%ld)", GetRDPSessionEventString(dispIdMember), dispIdMember);
274 
275 	switch (dispIdMember)
276 	{
277 		case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_CONNECTED:
278 		{
279 			int level;
280 			IDispatch* pDispatch;
281 			IRDPSRAPIAttendee* pAttendee;
282 			vr.vt = VT_DISPATCH;
283 			vr.pdispVal = NULL;
284 			hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &vr, &uArgErr);
285 
286 			if (FAILED(hr))
287 			{
288 				WLog_ERR(TAG, "%s DispGetParam(0, VT_DISPATCH) failure: 0x%08lX",
289 				         GetRDPSessionEventString(dispIdMember), hr);
290 				return hr;
291 			}
292 
293 			pDispatch = vr.pdispVal;
294 			hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IRDPSRAPIAttendee,
295 			                                       (void**)&pAttendee);
296 
297 			if (FAILED(hr))
298 			{
299 				WLog_INFO(TAG, "%s IDispatch::QueryInterface(IRDPSRAPIAttendee) failure: 0x%08lX",
300 				          GetRDPSessionEventString(dispIdMember), hr);
301 				return hr;
302 			}
303 
304 			level = CTRL_LEVEL_VIEW;
305 			// level = CTRL_LEVEL_INTERACTIVE;
306 			hr = pAttendee->lpVtbl->put_ControlLevel(pAttendee, level);
307 
308 			if (FAILED(hr))
309 			{
310 				WLog_INFO(TAG, "%s IRDPSRAPIAttendee::put_ControlLevel() failure: 0x%08lX",
311 				          GetRDPSessionEventString(dispIdMember), hr);
312 				return hr;
313 			}
314 
315 			pAttendee->lpVtbl->Release(pAttendee);
316 		}
317 		break;
318 
319 		case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_DISCONNECTED:
320 			break;
321 
322 		case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_UPDATE:
323 			break;
324 
325 		case DISPID_RDPSRAPI_EVENT_ON_ERROR:
326 			break;
327 
328 		case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTED:
329 			break;
330 
331 		case DISPID_RDPSRAPI_EVENT_ON_VIEWER_DISCONNECTED:
332 			break;
333 
334 		case DISPID_RDPSRAPI_EVENT_ON_VIEWER_AUTHENTICATED:
335 			break;
336 
337 		case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTFAILED:
338 			break;
339 
340 		case DISPID_RDPSRAPI_EVENT_ON_CTRLLEVEL_CHANGE_REQUEST:
341 		{
342 			int level;
343 			IDispatch* pDispatch;
344 			IRDPSRAPIAttendee* pAttendee;
345 			vr.vt = VT_INT;
346 			vr.pdispVal = NULL;
347 			hr = DispGetParam(pDispParams, 1, VT_INT, &vr, &uArgErr);
348 
349 			if (FAILED(hr))
350 			{
351 				WLog_INFO(TAG, "%s DispGetParam(1, VT_INT) failure: 0x%08lX",
352 				          GetRDPSessionEventString(dispIdMember), hr);
353 				return hr;
354 			}
355 
356 			level = vr.intVal;
357 			vr.vt = VT_DISPATCH;
358 			vr.pdispVal = NULL;
359 			hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &vr, &uArgErr);
360 
361 			if (FAILED(hr))
362 			{
363 				WLog_ERR(TAG, "%s DispGetParam(0, VT_DISPATCH) failure: 0x%08lX",
364 				         GetRDPSessionEventString(dispIdMember), hr);
365 				return hr;
366 			}
367 
368 			pDispatch = vr.pdispVal;
369 			hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IRDPSRAPIAttendee,
370 			                                       (void**)&pAttendee);
371 
372 			if (FAILED(hr))
373 			{
374 				WLog_INFO(TAG, "%s IDispatch::QueryInterface(IRDPSRAPIAttendee) failure: 0x%08lX",
375 				          GetRDPSessionEventString(dispIdMember), hr);
376 				return hr;
377 			}
378 
379 			hr = pAttendee->lpVtbl->put_ControlLevel(pAttendee, level);
380 
381 			if (FAILED(hr))
382 			{
383 				WLog_INFO(TAG, "%s IRDPSRAPIAttendee::put_ControlLevel() failure: 0x%08lX",
384 				          GetRDPSessionEventString(dispIdMember), hr);
385 				return hr;
386 			}
387 
388 			pAttendee->lpVtbl->Release(pAttendee);
389 		}
390 		break;
391 
392 		case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_PAUSED:
393 			break;
394 
395 		case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_RESUMED:
396 			break;
397 
398 		case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_JOIN:
399 			break;
400 
401 		case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_LEAVE:
402 			break;
403 
404 		case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_DATARECEIVED:
405 			break;
406 
407 		case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_SENDCOMPLETED:
408 			break;
409 
410 		case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_OPEN:
411 			break;
412 
413 		case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_CLOSE:
414 			break;
415 
416 		case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_UPDATE:
417 			break;
418 
419 		case DISPID_RDPSRAPI_EVENT_ON_WINDOW_OPEN:
420 			break;
421 
422 		case DISPID_RDPSRAPI_EVENT_ON_WINDOW_CLOSE:
423 			break;
424 
425 		case DISPID_RDPSRAPI_EVENT_ON_WINDOW_UPDATE:
426 			break;
427 
428 		case DISPID_RDPSRAPI_EVENT_ON_APPFILTER_UPDATE:
429 			break;
430 
431 		case DISPID_RDPSRAPI_EVENT_ON_SHARED_RECT_CHANGED:
432 			break;
433 
434 		case DISPID_RDPSRAPI_EVENT_ON_FOCUSRELEASED:
435 			break;
436 
437 		case DISPID_RDPSRAPI_EVENT_ON_SHARED_DESKTOP_SETTINGS_CHANGED:
438 			break;
439 
440 		case DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED:
441 			break;
442 	}
443 
444 	return S_OK;
445 }
446 
447 static _IRDPSessionEventsVtbl Shadow_IRDPSessionEventsVtbl = {
448 	/* IUnknown */
449 	Shadow_IRDPSessionEvents_QueryInterface, Shadow_IRDPSessionEvents_AddRef,
450 	Shadow_IRDPSessionEvents_Release,
451 
452 	/* IDispatch */
453 	Shadow_IRDPSessionEvents_GetTypeInfoCount, Shadow_IRDPSessionEvents_GetTypeInfo,
454 	Shadow_IRDPSessionEvents_GetIDsOfNames, Shadow_IRDPSessionEvents_Invoke
455 };
456 
457 static _IRDPSessionEvents Shadow_IRDPSessionEvents = { &Shadow_IRDPSessionEventsVtbl };
458 
ShadowWndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)459 static LRESULT CALLBACK ShadowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
460 {
461 	switch (uMsg)
462 	{
463 		case WM_CLOSE:
464 			DestroyWindow(hwnd);
465 			break;
466 
467 		case WM_DESTROY:
468 			PostQuitMessage(0);
469 			break;
470 
471 		default:
472 			return DefWindowProc(hwnd, uMsg, wParam, lParam);
473 			break;
474 	}
475 
476 	return 0;
477 }
478 
win_shadow_wds_wnd_init(winShadowSubsystem * subsystem)479 int win_shadow_wds_wnd_init(winShadowSubsystem* subsystem)
480 {
481 	HMODULE hModule;
482 	HINSTANCE hInstance;
483 	WNDCLASSEX wndClassEx;
484 	hModule = GetModuleHandle(NULL);
485 	ZeroMemory(&wndClassEx, sizeof(WNDCLASSEX));
486 	wndClassEx.cbSize = sizeof(WNDCLASSEX);
487 	wndClassEx.style = 0;
488 	wndClassEx.lpfnWndProc = ShadowWndProc;
489 	wndClassEx.cbClsExtra = 0;
490 	wndClassEx.cbWndExtra = 0;
491 	wndClassEx.hInstance = hModule;
492 	wndClassEx.hIcon = NULL;
493 	wndClassEx.hCursor = NULL;
494 	wndClassEx.hbrBackground = NULL;
495 	wndClassEx.lpszMenuName = _T("ShadowWndMenu");
496 	wndClassEx.lpszClassName = _T("ShadowWndClass");
497 	wndClassEx.hIconSm = NULL;
498 
499 	if (!RegisterClassEx(&wndClassEx))
500 	{
501 		WLog_ERR(TAG, "RegisterClassEx failure");
502 		return -1;
503 	}
504 
505 	hInstance = wndClassEx.hInstance;
506 	subsystem->hWnd = CreateWindowEx(0, wndClassEx.lpszClassName, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0,
507 	                                 hInstance, NULL);
508 
509 	if (!subsystem->hWnd)
510 	{
511 		WLog_INFO(TAG, "CreateWindowEx failure");
512 		return -1;
513 	}
514 
515 	return 1;
516 }
517 
win_shadow_wds_init(winShadowSubsystem * subsystem)518 int win_shadow_wds_init(winShadowSubsystem* subsystem)
519 {
520 	int status;
521 	HRESULT hr;
522 	DWORD dwCookie;
523 	long left, top;
524 	long right, bottom;
525 	long width, height;
526 	IUnknown* pUnknown;
527 	rdpSettings* settings;
528 	BSTR bstrAuthString;
529 	BSTR bstrGroupName;
530 	BSTR bstrPassword;
531 	BSTR bstrPropertyName;
532 	VARIANT varPropertyValue;
533 	rdpAssistanceFile* file;
534 	IConnectionPoint* pCP;
535 	IConnectionPointContainer* pCPC;
536 	win_shadow_wds_wnd_init(subsystem);
537 	hr = OleInitialize(NULL);
538 
539 	if (FAILED(hr))
540 	{
541 		WLog_ERR(TAG, "OleInitialize() failure");
542 		return -1;
543 	}
544 
545 	hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
546 
547 	if (FAILED(hr))
548 	{
549 		WLog_ERR(TAG, "CoInitialize() failure");
550 		return -1;
551 	}
552 
553 	hr = CoCreateInstance(&CLSID_RDPSession, NULL, CLSCTX_ALL, &IID_IRDPSRAPISharingSession,
554 	                      (void**)&(subsystem->pSharingSession));
555 
556 	if (FAILED(hr))
557 	{
558 		WLog_ERR(TAG, "CoCreateInstance(IRDPSRAPISharingSession) failure: 0x%08lX", hr);
559 		return -1;
560 	}
561 
562 	pUnknown = (IUnknown*)subsystem->pSharingSession;
563 	hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IConnectionPointContainer, (void**)&pCPC);
564 
565 	if (FAILED(hr))
566 	{
567 		WLog_ERR(TAG, "QueryInterface(IID_IConnectionPointContainer) failure: 0x%08lX", hr);
568 		return -1;
569 	}
570 
571 	pCPC->lpVtbl->FindConnectionPoint(pCPC, &DIID__IRDPSessionEvents, &pCP);
572 
573 	if (FAILED(hr))
574 	{
575 		WLog_ERR(
576 		    TAG,
577 		    "IConnectionPointContainer::FindConnectionPoint(_IRDPSessionEvents) failure: 0x%08lX",
578 		    hr);
579 		return -1;
580 	}
581 
582 	dwCookie = 0;
583 	subsystem->pSessionEvents = &Shadow_IRDPSessionEvents;
584 	subsystem->pSessionEvents->lpVtbl->AddRef(subsystem->pSessionEvents);
585 	hr = pCP->lpVtbl->Advise(pCP, (IUnknown*)subsystem->pSessionEvents, &dwCookie);
586 
587 	if (FAILED(hr))
588 	{
589 		WLog_ERR(TAG, "IConnectionPoint::Advise(Shadow_IRDPSessionEvents) failure: 0x%08lX", hr);
590 		return -1;
591 	}
592 
593 	hr = subsystem->pSharingSession->lpVtbl->put_ColorDepth(subsystem->pSharingSession, 32);
594 
595 	if (FAILED(hr))
596 	{
597 		WLog_ERR(TAG, "IRDPSRAPISharingSession::put_ColorDepth() failure: 0x%08lX", hr);
598 		return -1;
599 	}
600 
601 	hr = subsystem->pSharingSession->lpVtbl->GetDesktopSharedRect(subsystem->pSharingSession, &left,
602 	                                                              &top, &right, &bottom);
603 
604 	if (FAILED(hr))
605 	{
606 		WLog_ERR(TAG, "IRDPSRAPISharingSession::GetDesktopSharedRect() failure: 0x%08lX", hr);
607 		return -1;
608 	}
609 
610 	width = right - left;
611 	height = bottom - top;
612 	WLog_INFO(
613 	    TAG,
614 	    "GetDesktopSharedRect(): left: %ld top: %ld right: %ld bottom: %ld width: %ld height: %ld",
615 	    left, top, right, bottom, width, height);
616 	hr = subsystem->pSharingSession->lpVtbl->get_VirtualChannelManager(
617 	    subsystem->pSharingSession, &(subsystem->pVirtualChannelMgr));
618 
619 	if (FAILED(hr))
620 	{
621 		WLog_ERR(TAG, "IRDPSRAPISharingSession::get_VirtualChannelManager() failure: 0x%08lX", hr);
622 		return -1;
623 	}
624 
625 	hr = subsystem->pSharingSession->lpVtbl->get_ApplicationFilter(
626 	    subsystem->pSharingSession, &(subsystem->pApplicationFilter));
627 
628 	if (FAILED(hr))
629 	{
630 		WLog_ERR(TAG, "IRDPSRAPISharingSession::get_ApplicationFilter() failure: 0x%08lX", hr);
631 		return -1;
632 	}
633 
634 	hr = subsystem->pSharingSession->lpVtbl->get_Attendees(subsystem->pSharingSession,
635 	                                                       &(subsystem->pAttendeeMgr));
636 
637 	if (FAILED(hr))
638 	{
639 		WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Attendees() failure: 0x%08lX", hr);
640 		return -1;
641 	}
642 
643 	hr = subsystem->pSharingSession->lpVtbl->get_Properties(subsystem->pSharingSession,
644 	                                                        &(subsystem->pSessionProperties));
645 
646 	if (FAILED(hr))
647 	{
648 		WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Properties() failure: 0x%08lX", hr);
649 		return -1;
650 	}
651 
652 	bstrPropertyName = SysAllocString(L"PortId");
653 	varPropertyValue.vt = VT_I4;
654 	varPropertyValue.intVal = 40000;
655 	hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties,
656 	                                                         bstrPropertyName, varPropertyValue);
657 	SysFreeString(bstrPropertyName);
658 
659 	if (FAILED(hr))
660 	{
661 		WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(PortId) failure: 0x%08lX", hr);
662 		return -1;
663 	}
664 
665 	bstrPropertyName = SysAllocString(L"DrvConAttach");
666 	varPropertyValue.vt = VT_BOOL;
667 	varPropertyValue.boolVal = VARIANT_TRUE;
668 	hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties,
669 	                                                         bstrPropertyName, varPropertyValue);
670 	SysFreeString(bstrPropertyName);
671 
672 	if (FAILED(hr))
673 	{
674 		WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(DrvConAttach) failure: 0x%08lX",
675 		         hr);
676 		return -1;
677 	}
678 
679 	bstrPropertyName = SysAllocString(L"PortProtocol");
680 	varPropertyValue.vt = VT_I4;
681 	// varPropertyValue.intVal = 0; // AF_UNSPEC
682 	varPropertyValue.intVal = 2; // AF_INET
683 	// varPropertyValue.intVal = 23; // AF_INET6
684 	hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties,
685 	                                                         bstrPropertyName, varPropertyValue);
686 	SysFreeString(bstrPropertyName);
687 
688 	if (FAILED(hr))
689 	{
690 		WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(PortProtocol) failure: 0x%08lX",
691 		         hr);
692 		return -1;
693 	}
694 
695 	hr = subsystem->pSharingSession->lpVtbl->Open(subsystem->pSharingSession);
696 
697 	if (FAILED(hr))
698 	{
699 		WLog_ERR(TAG, "IRDPSRAPISharingSession::Open() failure: 0x%08lX", hr);
700 		return -1;
701 	}
702 
703 	hr = subsystem->pSharingSession->lpVtbl->get_Invitations(subsystem->pSharingSession,
704 	                                                         &(subsystem->pInvitationMgr));
705 
706 	if (FAILED(hr))
707 	{
708 		WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Invitations() failure");
709 		return -1;
710 	}
711 
712 	bstrAuthString = SysAllocString(L"Shadow");
713 	bstrGroupName = SysAllocString(L"ShadowGroup");
714 	bstrPassword = SysAllocString(L"Shadow123!");
715 	hr = subsystem->pInvitationMgr->lpVtbl->CreateInvitation(
716 	    subsystem->pInvitationMgr, bstrAuthString, bstrGroupName, bstrPassword, 5,
717 	    &(subsystem->pInvitation));
718 	SysFreeString(bstrAuthString);
719 	SysFreeString(bstrGroupName);
720 	SysFreeString(bstrPassword);
721 
722 	if (FAILED(hr))
723 	{
724 		WLog_ERR(TAG, "IRDPSRAPIInvitationManager::CreateInvitation() failure: 0x%08lX", hr);
725 		return -1;
726 	}
727 
728 	file = subsystem->pAssistanceFile = freerdp_assistance_file_new();
729 
730 	if (!file)
731 	{
732 		WLog_ERR(TAG, "freerdp_assistance_file_new() failed");
733 		return -1;
734 	}
735 
736 	{
737 		int status1 = -1, status2 = -1;
738 		char* ConnectionString2;
739 		BSTR bstrConnectionString;
740 		hr = subsystem->pInvitation->lpVtbl->get_ConnectionString(subsystem->pInvitation,
741 		                                                          &bstrConnectionString);
742 
743 		if (FAILED(hr))
744 		{
745 			WLog_ERR(TAG, "IRDPSRAPIInvitation::get_ConnectionString() failure: 0x%08lX", hr);
746 			return -1;
747 		}
748 
749 		status1 = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)bstrConnectionString,
750 		                             ((UINT32*)bstrConnectionString)[-1], &(ConnectionString2), 0,
751 		                             NULL, NULL);
752 		SysFreeString(bstrConnectionString);
753 		status2 = freerdp_assistance_set_connection_string2(file, ConnectionString2, "Shadow123!");
754 		free(ConnectionString2);
755 
756 		if ((status1 < 1) || (status2 < 1))
757 		{
758 			WLog_ERR(TAG, "failed to convert connection string");
759 			return -1;
760 		}
761 	}
762 
763 	freerdp_assistance_print_file(file, WLog_Get(TAG), WLOG_INFO);
764 	status = win_shadow_rdp_init(subsystem);
765 
766 	if (status < 0)
767 	{
768 		WLog_ERR(TAG, "win_shadow_rdp_init() failure: %d", status);
769 		return status;
770 	}
771 
772 	settings = subsystem->shw->settings;
773 	status = freerdp_assistance_populate_settings_from_assistance_file(file, settings);
774 	freerdp_set_param_string(settings, FreeRDP_Domain, "RDP");
775 	freerdp_set_param_string(settings, FreeRDP_Username, "Shadow");
776 	freerdp_set_param_bool(settings, FreeRDP_AutoLogonEnabled, TRUE);
777 	freerdp_set_param_uint32(settings, FreeRDP_DesktopWidth, width);
778 	freerdp_set_param_uint32(settings, FreeRDP_DesktopHeight, height);
779 	status = win_shadow_rdp_start(subsystem);
780 
781 	if (status < 0)
782 	{
783 		WLog_ERR(TAG, "win_shadow_rdp_start() failure: %d", status);
784 		return status;
785 	}
786 
787 	return 1;
788 }
789 
win_shadow_wds_uninit(winShadowSubsystem * subsystem)790 int win_shadow_wds_uninit(winShadowSubsystem* subsystem)
791 {
792 	if (subsystem->pSharingSession)
793 	{
794 		subsystem->pSharingSession->lpVtbl->Close(subsystem->pSharingSession);
795 		subsystem->pSharingSession->lpVtbl->Release(subsystem->pSharingSession);
796 		subsystem->pSharingSession = NULL;
797 	}
798 
799 	if (subsystem->pVirtualChannelMgr)
800 	{
801 		subsystem->pVirtualChannelMgr->lpVtbl->Release(subsystem->pVirtualChannelMgr);
802 		subsystem->pVirtualChannelMgr = NULL;
803 	}
804 
805 	if (subsystem->pApplicationFilter)
806 	{
807 		subsystem->pApplicationFilter->lpVtbl->Release(subsystem->pApplicationFilter);
808 		subsystem->pApplicationFilter = NULL;
809 	}
810 
811 	if (subsystem->pAttendeeMgr)
812 	{
813 		subsystem->pAttendeeMgr->lpVtbl->Release(subsystem->pAttendeeMgr);
814 		subsystem->pAttendeeMgr = NULL;
815 	}
816 
817 	if (subsystem->pSessionProperties)
818 	{
819 		subsystem->pSessionProperties->lpVtbl->Release(subsystem->pSessionProperties);
820 		subsystem->pSessionProperties = NULL;
821 	}
822 
823 	if (subsystem->pInvitationMgr)
824 	{
825 		subsystem->pInvitationMgr->lpVtbl->Release(subsystem->pInvitationMgr);
826 		subsystem->pInvitationMgr = NULL;
827 	}
828 
829 	if (subsystem->pInvitation)
830 	{
831 		subsystem->pInvitation->lpVtbl->Release(subsystem->pInvitation);
832 		subsystem->pInvitation = NULL;
833 	}
834 
835 	if (subsystem->pAssistanceFile)
836 	{
837 		freerdp_assistance_file_free(subsystem->pAssistanceFile);
838 		subsystem->pAssistanceFile = NULL;
839 	}
840 
841 	if (subsystem->hWnd)
842 	{
843 		DestroyWindow(subsystem->hWnd);
844 		subsystem->hWnd = NULL;
845 	}
846 
847 	if (subsystem->shw)
848 	{
849 		win_shadow_rdp_uninit(subsystem);
850 		subsystem->shw = NULL;
851 	}
852 
853 	return 1;
854 }
855