source: Daodan/MSVC/PortForwardEngine.cpp@ 787

Last change on this file since 787 was 589, checked in by gumby, 13 years ago

stuff

File size: 46.8 KB
RevLine 
[589]1// PortForwardEngine.cpp: implementation of the CPortForwardEngine class.
2//
3//////////////////////////////////////////////////////////////////////
4
5
6#include "PortForwardEngine.hpp"
7#include <atlbase.h>
8#include <atlconv.h>
9
10// forward declaration of global function which is included at the end of this file
11
12void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName);
13
14
15#ifdef _DEBUG
16#undef THIS_FILE
17static char THIS_FILE[]=__FILE__;
18#define new DEBUG_NEW
19#endif
20
21//////////////////////////////////////////////////////////////////////
22// Construction/Destruction
23//////////////////////////////////////////////////////////////////////
24
25CPortForwardEngine::CPortForwardEngine()
26{
27 InitializeMembersToNull();
28 ::InitializeCriticalSection( &m_cs );
29}
30
31CPortForwardEngine::~CPortForwardEngine()
32{
33 StopListeningForUpnpChanges( );
34
35 ::DeleteCriticalSection( &m_cs );
36}
37
38void CPortForwardEngine::InitializeMembersToNull()
39{
40 m_piNAT = NULL;
41 m_piEventManager = NULL;
42 m_piExternalIPAddressCallback= NULL;
43 m_piNumberOfEntriesCallback = NULL;
44
45 m_pChangeCallbackFunctions = NULL;
46
47 m_pPortMappingThread = NULL;
48 m_pDeviceInfoThread = NULL;
49 m_pAddMappingThread = NULL;
50 m_pEditMappingThread = NULL;
51 m_pDeleteMappingThread = NULL;
52
53 m_hWndForPortMappingThread = NULL;
54 m_hWndForDeviceInfoThread = NULL;
55 m_hWndForAddMappingThread = NULL;
56 m_hWndForEditMappingThread = NULL;
57 m_hWndForDeleteMappingThread = NULL;
58
59 m_bListeningForUpnpChanges = FALSE;
60}
61
62
63void CPortForwardEngine::DeinitializeCom()
64{
65
66 if ( m_piExternalIPAddressCallback != NULL )
67 {
68 m_piExternalIPAddressCallback->Release();
69 m_piExternalIPAddressCallback = NULL;
70 }
71
72
73 if ( m_piNumberOfEntriesCallback != NULL )
74 {
75 m_piNumberOfEntriesCallback->Release();
76 m_piNumberOfEntriesCallback = NULL;
77 }
78
79 if ( m_piEventManager != NULL )
80 {
81 m_piEventManager->Release();
82 m_piEventManager = NULL;
83 }
84
85 if ( m_piNAT != NULL )
86 {
87 m_piNAT->Release();
88 m_piNAT = NULL;
89 }
90
91 CoUninitialize(); // balancing call for CoInitialize
92}
93
94HRESULT CPortForwardEngine::ListenForUpnpChanges(CPortForwardChangeCallbacks *pCallbacks /* =NULL */ )
95{
96 // check if we are already listening
97
98 if ( m_bListeningForUpnpChanges == TRUE )
99 return E_FAIL;
100
101 m_bListeningForUpnpChanges = TRUE;
102
103
104 if ( pCallbacks==NULL )
105 {
106 SetChangeEventCallbackPointer( new CPortForwardChangeCallbacks );
107 }
108 else
109 {
110 SetChangeEventCallbackPointer( pCallbacks );
111 }
112
113 // initialize COM for this thread
114
115 HRESULT result = CoInitialize(NULL); // STA model
116 if ( !SUCCEEDED(result) )
117 {
118 return E_FAIL;
119 }
120
121 // create COM instance of IUPnPNAT
122
123 result = CoCreateInstance(__uuidof(UPnPNAT), NULL, CLSCTX_ALL, __uuidof(IUPnPNAT), (void **)&m_piNAT);
124 if ( !SUCCEEDED(result) || ( m_piNAT==NULL ) )
125 {
126 CoUninitialize();
127 return E_FAIL;
128 }
129
130
131 // Get the INATEventManager interface
132
133 result = m_piNAT->get_NATEventManager(&m_piEventManager);
134 if ( !SUCCEEDED(result) || (m_piEventManager==NULL ) )
135 {
136 m_piNAT->Release();
137 m_piNAT = NULL;
138 CoUninitialize();
139 return E_FAIL;
140 }
141
142 result = m_piEventManager->put_ExternalIPAddressCallback(
143 m_piExternalIPAddressCallback = new IDerivedNATExternalIPAddressCallback( m_pChangeCallbackFunctions ) );
144
145 if ( !SUCCEEDED(result) )
146 {
147 m_piEventManager->Release();
148 m_piEventManager = NULL;
149 m_piNAT->Release();
150 m_piNAT = NULL;
151 CoUninitialize();
152 return E_FAIL;
153 }
154
155 result = m_piEventManager->put_NumberOfEntriesCallback(
156 m_piNumberOfEntriesCallback = new IDerivedNATNumberOfEntriesCallback( m_pChangeCallbackFunctions ) );
157
158 if ( !SUCCEEDED(result) )
159 {
160 m_piEventManager->Release();
161 m_piEventManager = NULL;
162 m_piNAT->Release();
163 m_piNAT = NULL;
164 CoUninitialize();
165 return E_FAIL;
166 }
167
168 return S_OK;
169}
170
171
172
173HRESULT CPortForwardEngine::StopListeningForUpnpChanges( )
174{
175 // Stops listenting for UPnP change events on the router and deletes any
176 // CPortForwardChangeCallbacks-derived objects that are currently being held
177
178 // check if we are already listening
179
180 if ( m_bListeningForUpnpChanges == FALSE )
181 return E_FAIL;
182
183 m_bListeningForUpnpChanges = FALSE;
184
185
186 DeinitializeCom( );
187
188 if ( m_pChangeCallbackFunctions != NULL )
189 {
190 delete m_pChangeCallbackFunctions;
191 m_pChangeCallbackFunctions = NULL;
192 }
193
194 return S_OK;
195}
196
197
198
199HRESULT CPortForwardEngine::SetChangeEventCallbackPointer(CPortForwardChangeCallbacks *pCallbacks)
200{
201 ASSERT( pCallbacks!=NULL );
202
203 if ( m_pChangeCallbackFunctions != NULL )
204 {
205 delete m_pChangeCallbackFunctions;
206 m_pChangeCallbackFunctions = NULL;
207 }
208
209 m_pChangeCallbackFunctions = pCallbacks;
210
211 return S_OK;
212}
213
214
215
216BOOL CPortForwardEngine::IsAnyThreadRunning() const
217{
218 BOOL bRet = FALSE;
219 bRet |= ( m_pPortMappingThread != NULL );
220 bRet |= ( m_pDeviceInfoThread != NULL );
221 bRet |= ( m_pAddMappingThread != NULL );
222 bRet |= ( m_pEditMappingThread != NULL );
223 bRet |= ( m_pDeleteMappingThread != NULL );
224
225 return bRet;
226}
227
228
229
230
231std::vector<CPortForwardEngine::PortMappingContainer> CPortForwardEngine::GetPortMappingVector() const
232{
233 // returns a copy of the current mappings (note: thread-awareness is needed)
234
235 // cast away const-ness of the critical section (since this is a const function)
236 CPortForwardEngine* pThis = const_cast< CPortForwardEngine* >( this );
237
238 ::EnterCriticalSection( &(pThis->m_cs) );
239
240 std::vector<CPortForwardEngine::PortMappingContainer> retVector;
241 retVector = m_MappingContainer;
242
243 ::LeaveCriticalSection( &(pThis->m_cs) );
244
245 return retVector;
246}
247
248CPortForwardEngine::DeviceInformationContainer CPortForwardEngine::GetDeviceInformationContainer() const
249{
250 // returns a copy of the current device information (note: thread-awareness is needed)
251
252 // cast away const-ness of the critical section (since this is a const function)
253 CPortForwardEngine* pThis = const_cast< CPortForwardEngine* >( this );
254
255 ::EnterCriticalSection( &(pThis->m_cs) );
256
257 CPortForwardEngine::DeviceInformationContainer retDeviceInfo;
258 retDeviceInfo = m_DeviceInfo;
259
260 ::LeaveCriticalSection( &(pThis->m_cs) );
261
262 return retDeviceInfo;
263}
264
265
266///////////////////////////////////////////////
267//
268// Get Mappings and Device Information Using Threads
269//
270///////////////////////////////////////////////
271//
272// These comments explain the how to receive notifications from the threads that the
273// Port Forward Engine creates when running COM requests for device information or for
274// retreival/change of port mappings.
275//
276// There are five functions that create threads, and each function takes a HWND as a
277// parameter. During execution of the thread, each thread will post messages to this HWND,
278// so as to notify the HWMND of the thread's progress through the needed COM tasks. The
279// message is always the same: a UINT named UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION.
280// Encodings of the WPARAM and LPARAM within the message will enable the HWND to determine
281// what's going on inside the thread. The five functions are:
282//
283// GetMappingsUsingThread()
284// EditMappingUsingThread()
285// AddMappingUsingThread()
286// DeleteMappingUsingThread()
287// GetDeviceInformationUsingThread()
288//
289// The comments below explain each how to modify your class to receive the thread's notification
290// message, and also explain how to decode the WPARAM and LPARAM values
291
292
293
294// define the value of the registered Window message. An arbitrary GUID is included, to ensure uniqueness
295
296
297extern const UINT UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION = ::RegisterWindowMessage(
298 _T("UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION-{7C29C80A_5712_40e8_A124_A82E4B2795A7}") );
299
300
301
302///////////////////////////////////////////////
303//
304// GetMappingsUsingThread()
305//
306//////////////////////////////////////////////
307//
308// The GetMappingsUsingThread() function populates a std::vector of PortMappingContainer's with port
309// mappings that it finds using a thread. The reason for the thread is that COM retrieval of
310// port mappings is SLOW. Moreover, retrieval of the port mappings also BLOCKS the message
311// pump, so without a separate thread the application would otherwise appear to be hung/frozen.
312//
313// The thread frees the user interface of your program to do other things. The price you
314// pay for this convenience is that communication to your application is via Windows messages,
315// which the thread sends to your application and which your application must interpret and process.
316//
317// To use this function, your program must be able to receive (and process)
318// a registered window message posted from the thread when the thread is finished.
319// Thus, you must pass in a HWND of one of your windows that will receive the message. Typically,
320// you would choose your CMainFrame window (use the ::AfxGetMainWnd() function). However, you might
321// choose a different window, such as your CView-derived window for SDI applications
322//
323// The window that you choose must be able to process the message, which is a UINT named
324// UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION. For an MFC application, here are the changes
325// you must make to your CWnd class:
326//
327// 1. Declare a handler in your .h file using the following signature, in which
328// the name "OnMappingThreadNotificationMeesage" is arbitrary (ie, you can use
329// any name that you want, but you must be consistent):
330//
331// afx_msg LRESULT OnMappingThreadNotificationMeesage(WPARAM wParam, LPARAM lParam);
332//
333// 2. In your *.cpp file include the following "extern" statement somewhere at the beginning of
334// the file. This statement tells the linker that the value of the message is defined elsewhere:
335//
336// extern const UINT UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION; // defined in PortForwadEngine.cpp
337//
338// 3. In your .cpp implementation file, add an entry to the message map as follows:
339//
340// ON_REGISTERED_MESSAGE( UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, OnMappingThreadNotificationMeesage )
341//
342// 4. Again in your .cpp file, write the body of the OnMappingThreadNotificationMeesage() function.
343// Typically, you would check the WPARAM parameter to determine the nature of the notification.
344// WPARAM == CPortForwardEngine::EnumPortRetrieveInterval is sent at intervals, where
345// LPARAM goes from 0 to 10. You can use this to update a progress control (if you want)
346// WPARAM == CPortForwardEngine::EnumPortRetrieveDone is sent when the thread is done, where
347// LPARAM signifies if the thread was or was not successful (S_OK or E_FAIL). Call the
348// GetPortMappingVector() function to get a copy of the current contents of
349// std::vector< CPortForwardEngine::PortMappingContainer > m_MappingContainer
350
351BOOL CPortForwardEngine::GetMappingsUsingThread( HWND hWnd )
352{
353 // returns TRUE if thread was started successfully
354
355 if ( (m_pPortMappingThread!=NULL) || (hWnd==NULL) || (!IsWindow(hWnd)) )
356 return FALSE;
357
358 m_hWndForPortMappingThread = hWnd;
359
360
361 if ( m_pPortMappingThread != NULL )
362 {
363
364 return TRUE;
365 }
366 else
367 {
368 return FALSE;
369 }
370}
371
372
373///////////////////////////////////////////////
374//
375// EditMappingUsingThread()
376//
377//////////////////////////////////////////////
378//
379// The thread created by the EditMappingUsingThread() function uses the same architecture for
380// message notification as above (ie, it posts a UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION
381// message), but with the following WPARAM and LPARAM encodings:
382// WPARAM == CPortForwardEngine::EnumEditMappingInterval at intervals, where
383// LPARAM varies from 0 to 10. You can use this to update of a progress control (if you want).
384// WPARAM == CPortForwardEngine::EnumEditMappingDone when the thread is finished, where
385// LPARAM signifies if the thread was or was not successful (S_OK or E_FAIL).
386
387
388BOOL CPortForwardEngine::EditMappingUsingThread( CPortForwardEngine::PortMappingContainer& oldMapping,
389 CPortForwardEngine::PortMappingContainer& newMapping, HWND hWnd )
390{
391 // returns TRUE if thread was started successfully
392
393 if ( (m_pEditMappingThread!=NULL) || (hWnd==NULL) || (!IsWindow(hWnd)) )
394 return FALSE;
395
396 m_scratchpadOldMapping = oldMapping;
397 m_scratchpadNewMapping = newMapping;
398
399 m_hWndForEditMappingThread = hWnd;
400
401
402 if ( m_pEditMappingThread != NULL )
403 {
404
405 return TRUE;
406 }
407 else
408 {
409 return FALSE;
410 }
411
412}
413
414
415
416///////////////////////////////////////////////
417//
418// AddMappingUsingThread()
419//
420//////////////////////////////////////////////
421//
422// The thread created by the AddMappingUsingThread() function uses the same architecture for
423// message notification as above (ie, it posts a UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION
424// message), but with the following WPARAM and LPARAM encodings:
425// WPARAM == CPortForwardEngine::EnumAddMappingInterval at intervals, where
426// LPARAM varies from 0 to 10. You can use this to update of a progress control (if you want).
427// WPARAM == CPortForwardEngine::EnumAddMappingDone when the thread is finished, where
428// LPARAM signifies if the thread was or was not successful (S_OK or E_FAIL).
429
430BOOL CPortForwardEngine::AddMappingUsingThread( CPortForwardEngine::PortMappingContainer& newMapping, HWND hWnd )
431{
432 // returns TRUE if thread was started successfully
433
434 m_scratchpadAddedMapping = newMapping;
435
436 m_hWndForAddMappingThread = hWnd;
437
438 ThreadToAddMapping(0);
439 return 0;
440}
441
442
443
444///////////////////////////////////////////////
445//
446// DeleteMappingUsingThread()
447//
448//////////////////////////////////////////////
449//
450// The thread created by the DeleteMappingUsingThread() function uses the same architecture for
451// message notification as above (ie, it posts a UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION
452// message), but with the following WPARAM and LPARAM encodings:
453// WPARAM == CPortForwardEngine::EnumDeleteMappingInterval at intervals, where
454// LPARAM varies from 0 to 10. You can use this to update of a progress control (if you want).
455// WPARAM == CPortForwardEngine::EnumDeleteMappingDone when the thread is finished, where
456// LPARAM signifies if the thread was or was not successful (S_OK or E_FAIL).
457
458BOOL CPortForwardEngine::DeleteMappingUsingThread( CPortForwardEngine::PortMappingContainer& oldMapping, HWND hWnd )
459{
460 // returns TRUE if thread was started successfully
461
462 if ( (m_pDeleteMappingThread!=NULL) || (hWnd==NULL) || (!IsWindow(hWnd)) )
463 return FALSE;
464
465 m_scratchpadDeletedMapping = oldMapping;
466
467 m_hWndForDeleteMappingThread = hWnd;
468
469
470 if ( m_pDeleteMappingThread != NULL )
471 {
472
473 return TRUE;
474 }
475 else
476 {
477 return FALSE;
478 }
479
480}
481
482
483///////////////////////////////////////////////
484//
485// GetDeviceInformationUsingThread()
486//
487//////////////////////////////////////////////
488//
489// The thread created by the GetDeviceInformationUsingThread() function uses the same architecture for
490// message notification as above (ie, it posts a UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION
491// message), but with the following WPARAM and LPARAM encodings:
492// WPARAM == CPortForwardEngine::EnumDeviceInfoInterval at intervals, where
493// LPARAM varies from 0 to 10. You can use this to update of a progress control (if you want).
494// WPARAM == CPortForwardEngine::EnumDeviceInfoDone when thread is finished, where
495// LPARAM signifies if the thread was or was not successful (S_OK or E_FAIL). Call the
496// GetDeviceInformationContainer() function to retrieve a copy of the current contents of
497// CPortForwardEngine::DeviceInformationContainer m_DeviceInfo
498
499BOOL CPortForwardEngine::GetDeviceInformationUsingThread( HWND hWnd )
500{
501 // returns TRUE if thread was started successfully
502
503 if ( (m_pDeviceInfoThread!=NULL) || (hWnd==NULL) || (!IsWindow(hWnd)) )
504 return FALSE;
505
506 m_hWndForDeviceInfoThread = hWnd;
507
508
509 if ( m_pDeviceInfoThread != NULL )
510 {
511
512 return TRUE;
513 }
514 else
515 {
516 return FALSE;
517 }
518
519}
520
521
522
523
524/* static */
525UINT CPortForwardEngine::ThreadForPortRetrieval(LPVOID pVoid)
526{
527 ::SetThreadName( -1, "PortRtrv" ); // helps in debugging to see a thread's name
528
529 BOOL bContinue = TRUE;
530
531 CPortForwardEngine* pThis = (CPortForwardEngine*)pVoid;
532
533 // local copies of shared variables
534
535 HWND hWndForPosting = pThis->m_hWndForPortMappingThread;
536
537 WPARAM wp = EnumPortRetrieveInterval;
538 LPARAM lp = 0;
539
540 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
541
542 // initialize COM
543
544 if ( !SUCCEEDED( CoInitialize(NULL) ) ) // STA model
545 bContinue = FALSE;
546
547
548 // create COM instance of IUPnPNAT
549
550 IUPnPNAT* piNAT = NULL;
551 IStaticPortMappingCollection* piPortMappingCollection = NULL;
552
553 if ( !bContinue || !SUCCEEDED( CoCreateInstance(__uuidof(UPnPNAT), NULL, CLSCTX_ALL, __uuidof(IUPnPNAT), (void **)&piNAT) ) || ( piNAT==NULL ) )
554 bContinue = FALSE;
555
556 // Get the collection of forwarded ports
557
558 if ( !bContinue || !SUCCEEDED( piNAT->get_StaticPortMappingCollection(&piPortMappingCollection) ) || (piPortMappingCollection==NULL ) )
559 bContinue = FALSE;
560
561
562 lp = 1;
563 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
564
565 // Get mapping enumerator and reset the list of mappings
566
567 IUnknown* piUnk = NULL;
568 IEnumVARIANT* piEnumerator = NULL;
569
570 if ( !bContinue || !SUCCEEDED( piPortMappingCollection->get__NewEnum( &piUnk ) ) || piUnk==NULL )
571 bContinue = FALSE;
572
573 if ( !bContinue || !SUCCEEDED( piUnk->QueryInterface(IID_IEnumVARIANT, (void **)&piEnumerator) ) || piEnumerator==NULL )
574 bContinue = FALSE;
575
576 if ( !bContinue || !SUCCEEDED( piEnumerator->Reset() ) )
577 bContinue = FALSE;
578
579 lp = 2;
580 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
581
582
583 // get count of static mappings
584
585 long cMappings = 0;
586
587 if ( !bContinue || !SUCCEEDED( piPortMappingCollection->get_Count( &cMappings ) ) )
588 bContinue = FALSE;
589
590 if ( cMappings <= 0 ) cMappings = 4; // arbitrary non-zero value, so we can divide by non-zero value
591
592 lp = 3;
593 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
594
595
596 HRESULT result = S_OK;
597 int iii = 0;
598
599 // clear all current mappings (note: thread-awareness is needed)
600
601 ::EnterCriticalSection( &(pThis->m_cs) );
602 pThis->m_MappingContainer.clear();
603 ::LeaveCriticalSection( &(pThis->m_cs) );
604
605 CPortForwardEngine::PortMappingContainer mapCont;
606
607 while ( bContinue && SUCCEEDED(result) )
608 {
609 result = pThis->GetNextMapping( piEnumerator, mapCont );
610 if ( SUCCEEDED(result) )
611 {
612 ::EnterCriticalSection( &(pThis->m_cs) );
613 pThis->m_MappingContainer.push_back( mapCont );
614 ::LeaveCriticalSection( &(pThis->m_cs) );
615 }
616
617 lp = 3 + (10-3)*(++iii)/cMappings;
618 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
619 }
620
621 // release COM objects and de-initialize COM
622
623 if ( piEnumerator != NULL )
624 {
625 piEnumerator->Release();
626 piEnumerator = NULL;
627 }
628
629 if ( piPortMappingCollection != NULL )
630 {
631 piPortMappingCollection->Release();
632 piPortMappingCollection = NULL;
633 }
634
635 if ( piNAT != NULL )
636 {
637 piNAT->Release();
638 piNAT = NULL;
639 }
640
641
642 CoUninitialize();
643
644 // post completion message
645
646 lp = (bContinue ? S_OK : E_FAIL);
647 wp = EnumPortRetrieveDone;
648 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
649
650 pThis->m_pPortMappingThread = NULL;
651 pThis->m_hWndForPortMappingThread = NULL;
652
653
654 return 0;
655}
656
657
658/* static */
659UINT CPortForwardEngine::ThreadForDeviceInformationRetrieval( LPVOID pVoid )
660{
661 ::SetThreadName( -1, "DevInfo" ); // helps in debugging to see a thread's name
662
663 BOOL bContinue = TRUE;
664
665 CPortForwardEngine* pThis = (CPortForwardEngine*)pVoid;
666
667 // local copies of shared variables
668
669 HWND hWndForPosting = pThis->m_hWndForDeviceInfoThread;
670
671 WPARAM wp = EnumDeviceInfoInterval;
672 LPARAM lp = 0;
673
674 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
675
676
677 // initialize COM
678
679 if ( !SUCCEEDED( CoInitialize(NULL) ) ) // STA model
680 bContinue = FALSE;
681
682 // create COM instance of IUPnPDeviceFinder
683
684 IUPnPDeviceFinder* piDeviceFinder = NULL;
685
686 if ( !bContinue || !SUCCEEDED( CoCreateInstance( CLSID_UPnPDeviceFinder, NULL, CLSCTX_ALL,
687 IID_IUPnPDeviceFinder, (void**) &piDeviceFinder ) ) || ( piDeviceFinder==NULL ) )
688 bContinue = FALSE;
689
690 lp = 1;
691 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
692
693
694 // get devices of the desired type, using the PnP schema
695 // < deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1< /deviceType>
696
697 BSTR bStrDev = SysAllocString( L"urn:schemas-upnp-org:device:InternetGatewayDevice:1" );
698 IUPnPDevices* piFoundDevices = NULL;
699
700 if ( !bContinue || !SUCCEEDED( piDeviceFinder->FindByType( bStrDev, 0, &piFoundDevices ) )
701 || ( piFoundDevices==NULL ) )
702 bContinue = FALSE;
703
704 SysFreeString( bStrDev );
705
706
707 lp = 5;
708 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
709
710
711 // now traverse the collection of piFoundDevices
712
713 // the following code is based on code provided by MSDN in its Control Point API:
714 // "Device Collections Returned By Synchronous Searches" at
715 // http://msdn.microsoft.com/library/en-us/upnp/upnp/device_collections_returned_by_synchronous_searches.asp
716
717
718 HRESULT result = S_OK;
719 IUnknown * pUnk = NULL;
720 DeviceInformationContainer deviceInfo;
721
722 if ( bContinue && SUCCEEDED( piFoundDevices->get__NewEnum(&pUnk) ) && ( pUnk!=NULL ) )
723 {
724 IEnumVARIANT * pEnumVar = NULL;
725 result = pUnk->QueryInterface(IID_IEnumVARIANT, (void **) &pEnumVar);
726 if (SUCCEEDED(result))
727 {
728 VARIANT varCurDevice;
729 VariantInit(&varCurDevice);
730 pEnumVar->Reset();
731 // Loop through each device in the collection
732 while (S_OK == pEnumVar->Next(1, &varCurDevice, NULL))
733 {
734 IUPnPDevice * pDevice = NULL;
735 IDispatch * pdispDevice = V_DISPATCH(&varCurDevice);
736 if (SUCCEEDED(pdispDevice->QueryInterface(IID_IUPnPDevice, (void **) &pDevice)))
737 {
738 // finally, post interval notification message and get all the needed information
739
740 lp = 6;
741 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
742
743 result = pThis->PopulateDeviceInfoContainer( pDevice, deviceInfo, hWndForPosting );
744
745 }
746 VariantClear(&varCurDevice);
747 }
748 pEnumVar->Release();
749 }
750 pUnk->Release();
751 }
752
753
754 // release COM objects and de-initialize COM
755
756 if ( piDeviceFinder!=NULL )
757 {
758 piDeviceFinder->Release();
759 piDeviceFinder = NULL;
760 }
761
762 CoUninitialize();
763
764 bContinue = SUCCEEDED( result );
765
766
767 // store local devInfo into class member
768
769 pThis->m_DeviceInfo = deviceInfo;
770
771 // post completion message
772
773 lp = (bContinue ? S_OK : E_FAIL);
774 wp = EnumDeviceInfoDone;
775
776 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
777
778 pThis->m_pDeviceInfoThread = NULL;
779 pThis->m_hWndForDeviceInfoThread = NULL;
780
781 return 0;
782}
783
784
785/* static */
786UINT CPortForwardEngine::ThreadToEditMapping( LPVOID pVoid )
787{
788 ::SetThreadName( -1, "EditMap" ); // helps in debugging to see a thread's name
789
790 BOOL bContinue = TRUE;
791
792 CPortForwardEngine* pThis = (CPortForwardEngine*)pVoid;
793
794 // local copies of shared variables
795
796 PortMappingContainer oldMapping = pThis->m_scratchpadOldMapping;
797 PortMappingContainer newMapping = pThis->m_scratchpadNewMapping;
798 HWND hWndForPosting = pThis->m_hWndForEditMappingThread;
799
800 WPARAM wp = EnumEditMappingInterval;
801 LPARAM lp = 0;
802
803 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
804
805 // initialize COM
806
807 if ( !SUCCEEDED( CoInitialize(NULL) ) ) // STA model
808 bContinue = FALSE;
809
810
811 // create COM instance of IUPnPNAT
812
813 IUPnPNAT* piNAT = NULL;
814 IStaticPortMappingCollection* piPortMappingCollection = NULL;
815
816 if ( !bContinue || !SUCCEEDED( CoCreateInstance(__uuidof(UPnPNAT), NULL, CLSCTX_ALL, __uuidof(IUPnPNAT), (void **)&piNAT) ) || ( piNAT==NULL ) )
817 bContinue = FALSE;
818
819 // Get the collection of forwarded ports
820
821 if ( !bContinue || !SUCCEEDED( piNAT->get_StaticPortMappingCollection(&piPortMappingCollection) ) || (piPortMappingCollection==NULL ) )
822 bContinue = FALSE;
823
824
825 lp = 1;
826 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
827
828
829 // get the target old mapping from the collection of mappings
830
831 IStaticPortMapping* piStaticPortMapping = NULL;
832 USES_CONVERSION; // for conversion from CString's
833
834 if ( !bContinue || !SUCCEEDED( piPortMappingCollection->get_Item( _ttol(oldMapping.ExternalPort), T2OLE( oldMapping.Protocol.GetBuffer(0) ), &piStaticPortMapping ) ) || (piStaticPortMapping==NULL) )
835 bContinue = FALSE;
836
837 oldMapping.Protocol.ReleaseBuffer();
838
839
840 lp = 2;
841 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
842
843
844 // update the mapping
845
846 if ( bContinue )
847 {
848 HRESULT hr = S_OK;
849 VARIANT_BOOL vb = ( ( newMapping.Enabled == _T("Yes") ) ? VARIANT_TRUE : VARIANT_FALSE );
850
851 hr |= piStaticPortMapping->Enable( vb );
852 lp = 4;
853 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
854
855 hr |= piStaticPortMapping->EditDescription( T2OLE( newMapping.Description.GetBuffer(0) ) );
856 newMapping.Description.ReleaseBuffer();
857 lp = 6;
858 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
859
860 hr |= piStaticPortMapping->EditInternalPort( _ttol(newMapping.InternalPort) );
861 lp = 8;
862 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
863
864 hr |= piStaticPortMapping->EditInternalClient( T2OLE( newMapping.InternalClient.GetBuffer(0) ) );
865 newMapping.InternalClient.ReleaseBuffer();
866 lp = 10;
867 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
868
869 if ( !SUCCEEDED(hr) )
870 bContinue = FALSE;
871 }
872
873
874 // clean up and de-initialize COM
875
876 if ( piStaticPortMapping != NULL )
877 {
878 piStaticPortMapping->Release();
879 piStaticPortMapping = NULL;
880 }
881
882
883 if ( piPortMappingCollection != NULL )
884 {
885 piPortMappingCollection->Release();
886 piPortMappingCollection = NULL;
887 }
888
889 if ( piNAT != NULL )
890 {
891 piNAT->Release();
892 piNAT = NULL;
893 }
894
895
896 CoUninitialize();
897
898 // post completion message
899
900 lp = (bContinue ? S_OK : E_FAIL);
901 wp = EnumEditMappingDone;
902 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
903
904 pThis->m_pEditMappingThread = NULL;
905 pThis->m_hWndForEditMappingThread = NULL;
906
907 return 0;
908}
909
910/* static */
911UINT CPortForwardEngine::ThreadToDeleteMapping( LPVOID pVoid )
912{
913 ::SetThreadName( -1, "DelMap" ); // helps in debugging to see a thread's name
914
915 BOOL bContinue = TRUE;
916
917 CPortForwardEngine* pThis = (CPortForwardEngine*)pVoid;
918
919 // local copies of shared variables
920
921 PortMappingContainer oldMapping = pThis->m_scratchpadDeletedMapping;
922 HWND hWndForPosting = pThis->m_hWndForDeleteMappingThread;
923
924 WPARAM wp = EnumDeleteMappingInterval;
925 LPARAM lp = 0;
926
927 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
928
929 // initialize COM
930
931 if ( !SUCCEEDED( CoInitialize(NULL) ) ) // STA model
932 bContinue = FALSE;
933
934
935 // create COM instance of IUPnPNAT
936
937 IUPnPNAT* piNAT = NULL;
938 IStaticPortMappingCollection* piPortMappingCollection = NULL;
939
940 if ( !bContinue || !SUCCEEDED( CoCreateInstance(__uuidof(UPnPNAT), NULL, CLSCTX_ALL, __uuidof(IUPnPNAT), (void **)&piNAT) ) || ( piNAT==NULL ) )
941 bContinue = FALSE;
942
943 // Get the collection of forwarded ports
944
945 if ( !bContinue || !SUCCEEDED( piNAT->get_StaticPortMappingCollection(&piPortMappingCollection) ) || (piPortMappingCollection==NULL ) )
946 bContinue = FALSE;
947
948
949 lp = 1;
950 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
951
952
953 // get the target old mapping from the collection of mappings
954
955 USES_CONVERSION; // for conversion from CString's
956
957 if ( !bContinue ||
958 !SUCCEEDED( piPortMappingCollection->Remove( _ttol(oldMapping.ExternalPort), T2OLE( oldMapping.Protocol.GetBuffer(0) ) ) ) )
959 bContinue = FALSE;
960
961 oldMapping.Protocol.ReleaseBuffer();
962 lp = 2;
963 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
964
965
966
967 // clean up and de-initialize COM
968
969
970 if ( piPortMappingCollection != NULL )
971 {
972 piPortMappingCollection->Release();
973 piPortMappingCollection = NULL;
974 }
975
976 if ( piNAT != NULL )
977 {
978 piNAT->Release();
979 piNAT = NULL;
980 }
981
982
983 CoUninitialize();
984
985 // post completion message
986
987 lp = (bContinue ? S_OK : E_FAIL);
988 wp = EnumDeleteMappingDone;
989 ::PostMessage( hWndForPosting, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
990
991 pThis->m_pDeleteMappingThread = NULL;
992 pThis->m_hWndForDeleteMappingThread = NULL;
993
994 return 0;
995}
996
997
998/* static */
999UINT CPortForwardEngine::ThreadToAddMapping( LPVOID pVoid )
1000{
1001
1002 CPortForwardEngine* pThis = (CPortForwardEngine*)pVoid;
1003
1004 PortMappingContainer& newMapping = pThis->m_scratchpadAddedMapping;
1005
1006
1007 BOOL bContinue = TRUE;
1008 WPARAM wp = EnumAddMappingInterval;
1009 LPARAM lp = 0;
1010
1011
1012
1013 // initialize COM
1014
1015 if ( !SUCCEEDED( CoInitialize(NULL) ) ) // STA model
1016 bContinue = FALSE;
1017
1018
1019 // create COM instance of IUPnPNAT
1020
1021 IUPnPNAT* piNAT = NULL;
1022 IStaticPortMappingCollection* piPortMappingCollection = NULL;
1023
1024 if ( !bContinue || !SUCCEEDED( CoCreateInstance(__uuidof(UPnPNAT), NULL, CLSCTX_ALL, __uuidof(IUPnPNAT), (void **)&piNAT) ) || ( piNAT==NULL ) )
1025 bContinue = FALSE;
1026
1027 // Get the collection of forwarded ports
1028
1029 if ( !bContinue || !SUCCEEDED( piNAT->get_StaticPortMappingCollection(&piPortMappingCollection) ) || (piPortMappingCollection==NULL ) )
1030 bContinue = FALSE;
1031
1032
1033 lp = 1;
1034 ::PostMessage( pThis->m_hWndForAddMappingThread, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
1035
1036
1037 // add the new mapping
1038
1039 IStaticPortMapping* piStaticPortMapping = NULL;
1040 USES_CONVERSION; // for conversion from CString's
1041
1042 VARIANT_BOOL vb = ( ( newMapping.Enabled == _T("Yes") ) ? VARIANT_TRUE : VARIANT_FALSE );
1043
1044 if ( !bContinue ||
1045 !SUCCEEDED( piPortMappingCollection->Add( _ttol(newMapping.ExternalPort), T2OLE( newMapping.Protocol.GetBuffer(0) ),
1046 _ttol(newMapping.InternalPort), T2OLE( newMapping.InternalClient.GetBuffer(0) ), vb, T2OLE( newMapping.Description.GetBuffer(0) ),
1047 &piStaticPortMapping ) ) || (piStaticPortMapping==NULL) )
1048
1049 bContinue = FALSE;
1050
1051 newMapping.Protocol.ReleaseBuffer();
1052 newMapping.InternalClient.ReleaseBuffer();
1053 newMapping.Description.ReleaseBuffer();
1054
1055 lp = 2;
1056 ::PostMessage( pThis->m_hWndForAddMappingThread, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, lp );
1057
1058
1059
1060 // clean up and de-initialize COM
1061
1062 if ( piStaticPortMapping != NULL )
1063 {
1064 piStaticPortMapping->Release();
1065 piStaticPortMapping = NULL;
1066 }
1067
1068
1069 if ( piPortMappingCollection != NULL )
1070 {
1071 piPortMappingCollection->Release();
1072 piPortMappingCollection = NULL;
1073 }
1074
1075 if ( piNAT != NULL )
1076 {
1077 piNAT->Release();
1078 piNAT = NULL;
1079 }
1080
1081
1082 CoUninitialize();
1083
1084 // post completion message
1085
1086 lp = (bContinue ? S_OK : E_FAIL);
1087 wp = EnumAddMappingDone;
1088
1089 pThis->m_pAddMappingThread = NULL;
1090 pThis->m_hWndForAddMappingThread = NULL;
1091
1092 return 0;
1093}
1094
1095
1096
1097HRESULT CPortForwardEngine::GetNextMapping( IEnumVARIANT* piEnumerator, CPortForwardEngine::PortMappingContainer& mappingContainer )
1098{
1099 // uses the enumerator to get the next mapping and fill in a mapping container structure
1100
1101 USES_CONVERSION; // for conversion to CString's
1102 if ( piEnumerator == NULL )
1103 {
1104 return E_FAIL;
1105 }
1106
1107 VARIANT varCurMapping;
1108 VariantInit(&varCurMapping);
1109
1110 HRESULT result = piEnumerator->Next( 1, &varCurMapping, NULL);
1111 if( !SUCCEEDED(result) )
1112 {
1113 return E_FAIL;
1114 }
1115
1116 if ( varCurMapping.vt == VT_EMPTY )
1117 {
1118 return E_FAIL;
1119 }
1120
1121 IStaticPortMapping* piMapping = NULL;
1122 IDispatch* piDispMap = V_DISPATCH(&varCurMapping);
1123 result = piDispMap->QueryInterface(IID_IStaticPortMapping, (void **)&piMapping);
1124 if( !SUCCEEDED(result) )
1125 {
1126 return E_FAIL;
1127 }
1128
1129
1130 // get external address
1131
1132 BSTR bStr = NULL;
1133
1134 result = piMapping->get_ExternalIPAddress( &bStr );
1135 if( !SUCCEEDED(result) )
1136 {
1137 piMapping->Release();
1138 piMapping = NULL;
1139 return E_FAIL;
1140 }
1141
1142 if( bStr != NULL )
1143 mappingContainer.ExternalIPAddress = CString( OLE2T( bStr ) );
1144
1145 SysFreeString(bStr);
1146 bStr = NULL;
1147
1148
1149 // get external port
1150
1151 long lValue = 0;
1152
1153 result = piMapping->get_ExternalPort( &lValue );
1154 if( !SUCCEEDED(result) )
1155 {
1156 piMapping->Release();
1157 piMapping = NULL;
1158 return E_FAIL;
1159 }
1160
1161 mappingContainer.ExternalPort.Format( _T("%d"), lValue );
1162
1163
1164 // get internal port
1165
1166 result = piMapping->get_InternalPort( &lValue );
1167 if( !SUCCEEDED(result) )
1168 {
1169 piMapping->Release();
1170 piMapping = NULL;
1171 return E_FAIL;
1172 }
1173
1174 mappingContainer.InternalPort.Format( _T("%d"), lValue );
1175
1176
1177 // get protocol
1178
1179 result = piMapping->get_Protocol( &bStr );
1180 if( !SUCCEEDED(result) )
1181 {
1182 piMapping->Release();
1183 piMapping = NULL;
1184 return E_FAIL;
1185 }
1186
1187 if( bStr != NULL )
1188 mappingContainer.Protocol = CString( OLE2T( bStr ) );
1189
1190 SysFreeString(bStr);
1191 bStr = NULL;
1192
1193
1194 // get internal client
1195
1196 result = piMapping->get_InternalClient( &bStr );
1197 if( !SUCCEEDED(result) )
1198 {
1199 piMapping->Release();
1200 piMapping = NULL;
1201 return E_FAIL;
1202 }
1203
1204 if( bStr != NULL )
1205 mappingContainer.InternalClient = CString( OLE2T( bStr ) );
1206
1207 SysFreeString(bStr);
1208 bStr = NULL;
1209
1210
1211 // determine whether it's enabled
1212
1213 VARIANT_BOOL bValue = VARIANT_FALSE;
1214
1215 result = piMapping->get_Enabled( &bValue );
1216 if( !SUCCEEDED(result) )
1217 {
1218 piMapping->Release();
1219 piMapping = NULL;
1220 return E_FAIL;
1221 }
1222
1223 mappingContainer.Enabled = CString( ( (bValue==VARIANT_FALSE) ? _T("No") : _T("Yes") ) );
1224
1225
1226 // get description
1227
1228 result = piMapping->get_Description( &bStr );
1229 if( !SUCCEEDED(result) )
1230 {
1231 piMapping->Release();
1232 piMapping = NULL;
1233 return E_FAIL;
1234 }
1235
1236 if( bStr != NULL )
1237 mappingContainer.Description = CString( OLE2T( bStr ) );
1238
1239 SysFreeString(bStr);
1240 bStr = NULL;
1241
1242 // clean up
1243
1244 piMapping->Release();
1245 piMapping = NULL;
1246
1247
1248 VariantClear( &varCurMapping );
1249
1250 return S_OK;
1251
1252}
1253
1254
1255
1256HRESULT CPortForwardEngine::PopulateDeviceInfoContainer( IUPnPDevice* piDevice,
1257 CPortForwardEngine::DeviceInformationContainer& deviceInfo, HWND hWnd /* =NULL */ )
1258{
1259 USES_CONVERSION; // for conversion to CString's
1260
1261 HRESULT result=S_OK, hrReturn=S_OK;
1262 long lValue = 0;
1263 BSTR bStr = NULL;
1264 VARIANT_BOOL bValue = VARIANT_FALSE;
1265 IUPnPDevices* piDevices = NULL;
1266
1267 // parameters for interval notification messages
1268
1269 double lp = 6.0;
1270 double addend = (10.0 - 6.0)/19.0; // there are 19 parameters that are retrieved, and we already sent 6 notifications
1271 WPARAM wp = EnumDeviceInfoInterval;
1272
1273
1274 // get children: We will NOT enumerate through the devices that might be returned.
1275 // Rather, we will only indicate how many there are. So, in this sense, the information
1276 // is somewhat redundant to HasChildren
1277
1278 result = piDevice->get_Children( &piDevices );
1279 hrReturn |= result;
1280 if ( SUCCEEDED(result) && (piDevices!=NULL) )
1281 {
1282 piDevices->get_Count( &lValue );
1283 if ( lValue==0 )
1284 {
1285 deviceInfo.Children.Format( _T("No: Zero children") );
1286 }
1287 else if ( lValue==1 )
1288 {
1289 deviceInfo.Children.Format( _T("Yes: One child") );
1290 }
1291 else if ( lValue>=1 )
1292 {
1293 deviceInfo.Children.Format( _T("Yes: %d children"), lValue );
1294 }
1295 piDevices->Release();
1296 piDevices = NULL;
1297 lValue = 0;
1298 }
1299
1300 if ( hWnd!=NULL )
1301 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1302
1303
1304 // Get Description
1305
1306 result = piDevice->get_Description( &bStr );
1307 hrReturn |= result;
1308 if ( SUCCEEDED(result) )
1309 {
1310 deviceInfo.Description = CString( OLE2T( bStr ) );
1311 SysFreeString(bStr);
1312 bStr = NULL;
1313 }
1314
1315 if ( hWnd!=NULL )
1316 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1317
1318
1319 // Get FriendlyName
1320
1321 result = piDevice->get_FriendlyName( &bStr );
1322 hrReturn |= result;
1323 if ( SUCCEEDED(result) )
1324 {
1325 deviceInfo.FriendlyName = CString( OLE2T( bStr ) );
1326 SysFreeString(bStr);
1327 bStr = NULL;
1328 }
1329
1330 if ( hWnd!=NULL )
1331 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1332
1333
1334 // Get HasChildren
1335
1336 result = piDevice->get_HasChildren( &bValue );
1337 hrReturn |= result;
1338 if ( SUCCEEDED(result) )
1339 {
1340 deviceInfo.HasChildren = CString( ( (bValue==VARIANT_FALSE) ? _T("No") : _T("Yes") ) );
1341 bValue = VARIANT_FALSE;
1342 }
1343
1344 if ( hWnd!=NULL )
1345 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1346
1347
1348 // Get IconURL
1349
1350 BSTR bStrMime = SysAllocString(L"image/gif");
1351
1352 result = piDevice->IconURL( bStrMime, 32, 32, 8, &bStr );
1353 hrReturn |= result;
1354 if ( SUCCEEDED(result) )
1355 {
1356 deviceInfo.IconURL = CString( OLE2T( bStr ) );
1357 SysFreeString(bStr);
1358 bStr = NULL;
1359 }
1360
1361 SysFreeString(bStrMime);
1362 bStrMime = NULL;
1363
1364 if ( hWnd!=NULL )
1365 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1366
1367
1368 // Get IsRootDevice
1369
1370 result = piDevice->get_IsRootDevice( &bValue );
1371 hrReturn |= result;
1372 if ( SUCCEEDED(result) )
1373 {
1374 deviceInfo.IsRootDevice = CString( ( (bValue==VARIANT_FALSE) ? _T("No") : _T("Yes") ) );
1375 bValue = VARIANT_FALSE;
1376 }
1377
1378 if ( hWnd!=NULL )
1379 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1380
1381
1382 // Get ManufacturerName
1383
1384 result = piDevice->get_ManufacturerName( &bStr );
1385 hrReturn |= result;
1386 if ( SUCCEEDED(result) )
1387 {
1388 deviceInfo.ManufacturerName = CString( OLE2T( bStr ) );
1389 SysFreeString(bStr);
1390 bStr = NULL;
1391 }
1392
1393 if ( hWnd!=NULL )
1394 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1395
1396
1397 // Get ManufacturerURL
1398
1399 result = piDevice->get_ManufacturerURL( &bStr );
1400 hrReturn |= result;
1401 if ( SUCCEEDED(result) )
1402 {
1403 deviceInfo.ManufacturerURL = CString( OLE2T( bStr ) );
1404 SysFreeString(bStr);
1405 bStr = NULL;
1406 }
1407
1408 if ( hWnd!=NULL )
1409 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1410
1411
1412 // Get ModelName
1413
1414 result = piDevice->get_ModelName( &bStr );
1415 hrReturn |= result;
1416 if ( SUCCEEDED(result) )
1417 {
1418 deviceInfo.ModelName = CString( OLE2T( bStr ) );
1419 SysFreeString(bStr);
1420 bStr = NULL;
1421 }
1422
1423 if ( hWnd!=NULL )
1424 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1425
1426
1427 // Get ModelNumber
1428
1429 result = piDevice->get_ModelNumber( &bStr );
1430 hrReturn |= result;
1431 if ( SUCCEEDED(result) )
1432 {
1433 deviceInfo.ModelNumber = CString( OLE2T( bStr ) );
1434 SysFreeString(bStr);
1435 bStr = NULL;
1436 }
1437
1438 if ( hWnd!=NULL )
1439 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1440
1441
1442 // Get ModelURL
1443
1444 result = piDevice->get_ModelURL( &bStr );
1445 hrReturn |= result;
1446 if ( SUCCEEDED(result) )
1447 {
1448 deviceInfo.ModelURL = CString( OLE2T( bStr ) );
1449 SysFreeString(bStr);
1450 bStr = NULL;
1451 }
1452
1453 if ( hWnd!=NULL )
1454 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1455
1456
1457 // Get ParentDevice. Actually, we will only get the FriendlyName of the parent device,
1458 // if there is one
1459
1460 IUPnPDevice* piDev = NULL;
1461
1462 result = piDevice->get_ParentDevice( &piDev );
1463 hrReturn |= result;
1464 if ( SUCCEEDED(result) )
1465 {
1466 if ( piDev==NULL )
1467 {
1468 deviceInfo.ParentDevice.Format( _T("This is a topmost device") );
1469 }
1470 else
1471 {
1472 if ( SUCCEEDED( piDev->get_FriendlyName( &bStr ) ) )
1473 {
1474 deviceInfo.ParentDevice = CString( OLE2T( bStr ) );
1475 SysFreeString(bStr);
1476 bStr = NULL;
1477 }
1478 piDev->Release();
1479 piDev = NULL;
1480 }
1481 }
1482
1483 if ( hWnd!=NULL )
1484 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1485
1486
1487 // Get PresentationURL
1488
1489 result = piDevice->get_PresentationURL( &bStr );
1490 hrReturn |= result;
1491 if ( SUCCEEDED(result) )
1492 {
1493 deviceInfo.PresentationURL = CString( OLE2T( bStr ) );
1494 SysFreeString(bStr);
1495 bStr = NULL;
1496 }
1497
1498 if ( hWnd!=NULL )
1499 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1500
1501
1502 // Get RootDevice. Actually, we will only get the FriendlyName of the root device,
1503 // if there is one
1504
1505 result = piDevice->get_RootDevice( &piDev );
1506 hrReturn |= result;
1507 if ( SUCCEEDED(result) )
1508 {
1509 if ( piDev==NULL )
1510 {
1511 deviceInfo.RootDevice.Format( _T("This is a topmost device") );
1512 }
1513 else
1514 {
1515 if ( SUCCEEDED( piDev->get_FriendlyName( &bStr ) ) )
1516 {
1517 deviceInfo.RootDevice = CString( OLE2T( bStr ) );
1518 SysFreeString(bStr);
1519 bStr = NULL;
1520 }
1521 piDev->Release();
1522 piDev = NULL;
1523 }
1524 }
1525
1526 if ( hWnd!=NULL )
1527 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1528
1529
1530
1531 // Get SerialNumber
1532
1533 result = piDevice->get_SerialNumber( &bStr );
1534 hrReturn |= result;
1535 if ( SUCCEEDED(result) )
1536 {
1537 deviceInfo.SerialNumber = CString( OLE2T( bStr ) );
1538 SysFreeString(bStr);
1539 bStr = NULL;
1540 }
1541
1542 if ( hWnd!=NULL )
1543 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1544
1545
1546 // Get Services. Actually, we will NOT enumerate through all the services that are contained
1547 // in the IUPnPServices collection. Rather, we will only get a count of services
1548
1549 IUPnPServices* piServices = NULL;
1550
1551 result = piDevice->get_Services( &piServices );
1552 hrReturn |= result;
1553 if ( SUCCEEDED(result) && (piServices!=NULL) )
1554 {
1555 piServices->get_Count( &lValue );
1556 if ( lValue==0 )
1557 {
1558 deviceInfo.Services.Format( _T("No: Zero services") );
1559 }
1560 else if ( lValue==1 )
1561 {
1562 deviceInfo.Services.Format( _T("Yes: One service") );
1563 }
1564 else if ( lValue>=1 )
1565 {
1566 deviceInfo.Services.Format( _T("Yes: %d services"), lValue );
1567 }
1568 piServices->Release();
1569 piServices = NULL;
1570 lValue = 0;
1571 }
1572
1573 if ( hWnd!=NULL )
1574 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1575
1576
1577 // Get Type
1578
1579 result = piDevice->get_Type( &bStr );
1580 hrReturn |= result;
1581 if ( SUCCEEDED(result) )
1582 {
1583 deviceInfo.Type = CString( OLE2T( bStr ) );
1584 SysFreeString(bStr);
1585 bStr = NULL;
1586 }
1587
1588 if ( hWnd!=NULL )
1589 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1590
1591
1592 // Get UniqueDeviceName
1593
1594 result = piDevice->get_UniqueDeviceName( &bStr );
1595 hrReturn |= result;
1596 if ( SUCCEEDED(result) )
1597 {
1598 deviceInfo.UniqueDeviceName = CString( OLE2T( bStr ) );
1599 SysFreeString(bStr);
1600 bStr = NULL;
1601 }
1602
1603 if ( hWnd!=NULL )
1604 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1605
1606
1607 // Get UPC
1608
1609 result = piDevice->get_UPC( &bStr );
1610 hrReturn |= result;
1611 if ( SUCCEEDED(result) )
1612 {
1613 deviceInfo.UPC = CString( OLE2T( bStr ) );
1614 SysFreeString(bStr);
1615 bStr = NULL;
1616 }
1617
1618 if ( hWnd!=NULL )
1619 ::PostMessage( hWnd, UWM_PORT_FORWARD_ENGINE_THREAD_NOTIFICATION, wp, (LPARAM)(lp += addend) );
1620
1621 return hrReturn;
1622}
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632//////////////////////////////////////////////////////////////////////////////////////////////
1633//
1634// implementation of Port Forward Change Event Callbacks
1635//
1636/////////////////////////////////////////////////////////////////////////////////////////////
1637
1638
1639//////////////////////////////////////////////////////////////////////
1640// Construction/Destruction
1641//////////////////////////////////////////////////////////////////////
1642
1643CPortForwardChangeCallbacks::CPortForwardChangeCallbacks()
1644{
1645
1646}
1647
1648CPortForwardChangeCallbacks::~CPortForwardChangeCallbacks()
1649{
1650
1651}
1652
1653
1654/* virtual */
1655HRESULT /* STDMETHODCALLTYPE */ CPortForwardChangeCallbacks::OnNewNumberOfEntries( long lNewNumberOfEntries )
1656{
1657 CString tempStr;
1658 tempStr.Format( _T("UPnP has detected a change in the number of port mappings for your router \n")
1659 _T("New number of mappings = %d \n")
1660 _T("It is recommended to update your list of mappings"), lNewNumberOfEntries );
1661
1662 ::MessageBox( NULL, tempStr, _T("Change Detected in Number of Port Mappings"),
1663 MB_OK | MB_ICONEXCLAMATION );
1664
1665 return S_OK;
1666}
1667
1668
1669/* virtual */
1670HRESULT /* STDMETHODCALLTYPE */ CPortForwardChangeCallbacks::OnNewExternalIPAddress( BSTR bstrNewExternalIPAddress )
1671{
1672 USES_CONVERSION; // for ole to tstr conversion
1673
1674 CString tempStr;
1675 tempStr.Format( _T("UPnP has detected a change in your external IP address \n")
1676 _T("New IP address = %s \n")
1677 _T("It is recommended to update your list of mappings"), OLE2T( bstrNewExternalIPAddress ) );
1678
1679 ::MessageBox( NULL, tempStr, _T("Change Detected in External IP Address"),
1680 MB_OK | MB_ICONEXCLAMATION );
1681
1682 return S_OK;
1683}
1684
1685
1686
1687HRESULT STDMETHODCALLTYPE CPortForwardEngine::
1688IDerivedNATNumberOfEntriesCallback::QueryInterface(REFIID iid, void ** ppvObject)
1689{
1690 HRESULT hr = S_OK;
1691 *ppvObject = NULL;
1692
1693 if ( iid == IID_IUnknown || iid == IID_INATNumberOfEntriesCallback )
1694 {
1695 *ppvObject = this;
1696 AddRef();
1697 hr = NOERROR;
1698 }
1699 else
1700 {
1701 hr = E_NOINTERFACE;
1702 }
1703
1704 return hr;
1705}
1706
1707
1708HRESULT STDMETHODCALLTYPE CPortForwardEngine::
1709IDerivedNATExternalIPAddressCallback::QueryInterface(REFIID iid, void ** ppvObject)
1710{
1711 HRESULT hr = S_OK;
1712 *ppvObject = NULL;
1713
1714 if ( iid == IID_IUnknown || iid == IID_INATExternalIPAddressCallback )
1715 {
1716 *ppvObject = this;
1717 AddRef();
1718 hr = NOERROR;
1719 }
1720 else
1721 {
1722 hr = E_NOINTERFACE;
1723 }
1724
1725 return hr;
1726}
1727
1728/////////////////////////////////////////////////////////////////////
1729//
1730// SetThreadName -- a function to set the current thread's 8-character name
1731// so as to be able to distinguish between the threads during debug operations
1732//
1733// Usage: SetThreadName (-1, "MainThread");
1734// Must be called from the thread you're trying to name
1735// For example SetThreadName(-1, "1st Thread");
1736// Will truncate name to 8 characters
1737//
1738// code obtained from
1739// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
1740//
1741
1742
1743void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName)
1744{
1745
1746 struct THREADNAME_INFO
1747 {
1748 DWORD dwType; // must be 0x1000
1749 LPCSTR szName; // pointer to name (in user addr space)
1750 DWORD dwThreadID; // thread ID (-1=caller thread)
1751 DWORD dwFlags; // reserved for future use, must be zero
1752 } ;
1753
1754 THREADNAME_INFO info;
1755 info.dwType = 0x1000;
1756 info.szName = szThreadName;
1757 info.dwThreadID = dwThreadID;
1758 info.dwFlags = 0;
1759
1760 __try
1761 {
1762 RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
1763 }
1764 __except(EXCEPTION_CONTINUE_EXECUTION)
1765 {
1766 }
1767}
Note: See TracBrowser for help on using the repository browser.