[DEVMGR]
[reactos.git] / reactos / dll / win32 / devmgr / devmgmt / MainWindow.cpp
index f96145b..50dc3a9 100644 (file)
@@ -1,13 +1,13 @@
 /*
  * PROJECT:     ReactOS Device Manager
  * LICENSE:     GPL - See COPYING in the top level directory
- * FILE:        dll/win32/devmgr/devmgr/MainWindow.cpp
+ * FILE:        dll/win32/devmgr/devmgmt/MainWindow.cpp
  * PURPOSE:     Implements the main container window for the device view
  * COPYRIGHT:   Copyright 2014 - 2015 Ged Murphy <gedmurphy@reactos.org>
  */
 
 
-#include "stdafx.h"
+#include "precomp.h"
 #include "devmgmt.h"
 #include "MainWindow.h"
 
 #define BTN_UPDATE_DRV      4
 #define BTN_UNINSTALL_DRV   5
 
+#define REFRESH_TIMER       1
+
+HINSTANCE g_hThisInstance = NULL;
+HINSTANCE g_hParentInstance = NULL;
 
 // menu hints
 static const MENU_HINT MainMenuHintTable[] =
@@ -58,42 +62,80 @@ static const MENU_HINT SystemMenuHintTable[] =
     {SC_SIZE,       IDS_HINT_SYS_SIZE},
     {SC_MINIMIZE,   IDS_HINT_SYS_MINIMIZE},
     {SC_MAXIMIZE,   IDS_HINT_SYS_MAXIMIZE},
-    {SC_CLOSE,      IDS_HINT_SYS_CLOSE},
+    {SC_CLOSE,      IDS_HINT_SYS_CLOSE}
 };
 
 static TBBUTTON TbButtons[] =
 {
-    { BTN_PROPERTIES, IDC_PROPERTIES, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
-    { BTN_SCAN_HARDWARE, IDC_SCAN_HARDWARE, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
-    { 2, IDC_STATIC, TBSTATE_ENABLED, BTNS_SEP, 0, 0 },
-    { BTN_ENABLE_DRV, IDC_ENABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
-    { BTN_DISABLE_DRV, IDC_DISABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
-    { BTN_UPDATE_DRV, IDC_UPDATE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
-    { BTN_UNINSTALL_DRV, IDC_UNINSTALL_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 }
+    { BTN_PROPERTIES, IDC_PROPERTIES, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+    { BTN_SCAN_HARDWARE, IDC_SCAN_HARDWARE, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+    { 2, IDC_STATIC, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0 },
+    { BTN_ENABLE_DRV, IDC_ENABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+    { BTN_DISABLE_DRV, IDC_DISABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+    { BTN_UPDATE_DRV, IDC_UPDATE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 },
+    { BTN_UNINSTALL_DRV, IDC_UNINSTALL_DRV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }
 };
 
 
 /* PUBLIC METHODS **********************************************/
 
-CMainWindow::CMainWindow(void) :
-    m_ToolbarhImageList(NULL),
+CDeviceManager::CDeviceManager(void) :
     m_hMainWnd(NULL),
     m_hStatusBar(NULL),
     m_hToolBar(NULL),
-    m_CmdShow(0)
+    m_CmdShow(0),
+    m_RefreshPending(false)
 {
     m_szMainWndClass = L"DevMgmtWndClass";
 }
 
-CMainWindow::~CMainWindow(void)
+CDeviceManager::~CDeviceManager(void)
+{
+}
+
+bool
+CDeviceManager::Create(_In_ HWND /*hWndParent*/,
+                       _In_ HINSTANCE hInst,
+                       _In_opt_z_ LPCWSTR /*lpMachineName*/,
+                       _In_ int nCmdShow)
 {
-    // Destroy any previous list
-    if (m_ToolbarhImageList) ImageList_Destroy(m_ToolbarhImageList);
+    CDeviceManager MainWindow;
+    INITCOMMONCONTROLSEX icex;
+    CAtlStringW szAppName;
+    int Ret = 1;
+
+    // Store the instances
+    g_hParentInstance = hInst;
+    g_hThisInstance = GetModuleHandleW(L"devmgr.dll");
+
+    // Initialize common controls
+    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+    icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES;
+    InitCommonControlsEx(&icex);
+
+    // Load the application name
+    if (szAppName.LoadStringW(g_hThisInstance, IDS_APPNAME))
+    {
+        // Initialize the main window
+        if (MainWindow.Initialize(szAppName, nCmdShow))
+        {
+            // Run the application
+            Ret = MainWindow.Run();
+
+            // Uninitialize the main window
+            MainWindow.Uninitialize();
+        }
+    }
+
+    return (Ret == 0);
 }
 
+
+/* PRIVATE METHODS **********************************************/
+
 bool
-CMainWindow::Initialize(LPCTSTR lpCaption,
-                        int nCmdShow)
+CDeviceManager::Initialize(_In_z_ LPCTSTR lpCaption,
+                           _In_ int nCmdShow)
 {
     CAtlStringW szCaption;
     WNDCLASSEXW wc = {0};
@@ -104,13 +146,13 @@ CMainWindow::Initialize(LPCTSTR lpCaption,
     // Setup the window class struct
     wc.cbSize = sizeof(WNDCLASSEXW);
     wc.lpfnWndProc = MainWndProc;
-    wc.hInstance = g_hInstance;
-    wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCEW(IDI_MAIN_ICON));
+    wc.hInstance = g_hThisInstance;
+    wc.hIcon = LoadIcon(g_hThisInstance, MAKEINTRESOURCEW(IDI_MAIN_ICON));
     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
     wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
     wc.lpszMenuName = MAKEINTRESOURCEW(IDR_MAINMENU);
     wc.lpszClassName = m_szMainWndClass;
-    wc.hIconSm = (HICON)LoadImage(g_hInstance,
+    wc.hIconSm = (HICON)LoadImage(g_hThisInstance,
                                   MAKEINTRESOURCE(IDI_MAIN_ICON),
                                   IMAGE_ICON,
                                   16,
@@ -131,7 +173,7 @@ CMainWindow::Initialize(LPCTSTR lpCaption,
                                      500,
                                      NULL,
                                      NULL,
-                                     g_hInstance,
+                                     g_hThisInstance,
                                      this);
     }
 
@@ -140,14 +182,14 @@ CMainWindow::Initialize(LPCTSTR lpCaption,
 }
 
 void
-CMainWindow::Uninitialize()
+CDeviceManager::Uninitialize(void)
 {
     // Unregister the window class 
-    UnregisterClassW(m_szMainWndClass, g_hInstance);
+    UnregisterClassW(m_szMainWndClass, g_hThisInstance);
 }
 
 int
-CMainWindow::Run()
+CDeviceManager::Run(void)
 {
     MSG Msg;
 
@@ -161,14 +203,11 @@ CMainWindow::Run()
     return 0;
 }
 
-
-/* PRIVATE METHODS **********************************************/
-
 bool
-CMainWindow::MainWndMenuHint(WORD CmdId,
-                             const MENU_HINT *HintArray,
-                             DWORD HintsCount,
-                             UINT DefHintId)
+CDeviceManager::MainWndMenuHint(_In_ WORD CmdId,
+                                _In_ const MENU_HINT *HintArray,
+                                _In_ DWORD HintsCount,
+                                _In_ UINT DefHintId)
 {
     bool Found = false;
     const MENU_HINT *LastHint;
@@ -188,16 +227,14 @@ CMainWindow::MainWndMenuHint(WORD CmdId,
 
     StatusBarLoadString(m_hStatusBar,
                         SB_SIMPLEID,
-                        g_hInstance,
+                        g_hThisInstance,
                         HintId);
 
     return Found;
 }
 
 void
-CMainWindow::UpdateStatusBar(
-    _In_ bool InMenuLoop
-    )
+CDeviceManager::UpdateStatusBar(_In_ bool InMenuLoop)
 {
     SendMessageW(m_hStatusBar,
                  SB_SIMPLE,
@@ -206,50 +243,52 @@ CMainWindow::UpdateStatusBar(
 }
 
 bool
-CMainWindow::RefreshView(ViewType Type)
+CDeviceManager::RefreshView(_In_ ViewType Type,
+                            _In_ bool ScanForChanges)
 {
-    UINT CheckId;
-    BOOL bSuccess;
+    UINT CheckId = 0;
 
     // Refreshed the cached view
-    m_DeviceView->Refresh(Type, FALSE, TRUE, NULL);
+    m_DeviceView->Refresh(Type, ScanForChanges, true);
 
     // Get the menu item id
     switch (Type)
     {
-        case DevicesByType: CheckId = IDC_DEVBYTYPE; break;
-        case DevicesByConnection: CheckId = IDC_DEVBYCONN; break;
-        case ResourcesByType: CheckId = IDC_RESBYTYPE; break;
-        case ResourcesByConnection: CheckId = IDC_RESBYCONN; break;
-        default: ATLASSERT(FALSE); break;
+        case DevicesByType:
+            CheckId = IDC_DEVBYTYPE;
+            break;
+
+        case DevicesByConnection:
+            CheckId = IDC_DEVBYCONN;
+            break;
+
+        case ResourcesByType:
+            CheckId = IDC_RESBYTYPE;
+            break;
+
+        case ResourcesByConnection:
+            CheckId = IDC_RESBYCONN;
+            break;
+
+        default:
+            ATLASSERT(FALSE);
+            break;
     }
 
     // Set the new check item
-    bSuccess = CheckMenuRadioItem(m_hMenu,
-                                  IDC_DEVBYTYPE,
-                                  IDC_RESBYCONN,
-                                  CheckId,
-                                  MF_BYCOMMAND);
-
-    return TRUE;
-}
+    CheckMenuRadioItem(m_hMenu,
+                       IDC_DEVBYTYPE,
+                       IDC_RESBYCONN,
+                       CheckId,
+                       MF_BYCOMMAND);
 
-bool
-CMainWindow::ScanForHardwareChanges()
-{
-    // Refresh the cache and and display
-    m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
-                          true,
-                          true,
-                          NULL);
     return true;
 }
 
 bool
-CMainWindow::CreateToolBar()
+CDeviceManager::CreateToolBar(void)
 {
     TBADDBITMAP TbAddBitmap;
-    INT Index;
 
     DWORD dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
@@ -262,9 +301,10 @@ CMainWindow::CreateToolBar()
                                  0, 0, 0, 0,
                                  m_hMainWnd,
                                  (HMENU)IDC_TOOLBAR,
-                                 g_hInstance,
+                                 g_hThisInstance,
                                  NULL);
-    if (m_hToolBar == NULL) return FALSE;
+    if (m_hToolBar == NULL)
+        return FALSE;
 
     // Don't show clipped buttons
     SendMessageW(m_hToolBar,
@@ -280,9 +320,9 @@ CMainWindow::CreateToolBar()
                  sizeof(TBBUTTON),
                  0);
 
-    TbAddBitmap.hInst = g_hInstance;
+    TbAddBitmap.hInst = g_hThisInstance;
     TbAddBitmap.nID = IDB_TOOLBAR;
-    Index = SendMessageW(m_hToolBar, TB_ADDBITMAP, _countof(TbButtons), (LPARAM)&TbAddBitmap);
+    SendMessageW(m_hToolBar, TB_ADDBITMAP, _countof(TbButtons), (LPARAM)&TbAddBitmap);
 
     SendMessageW(m_hToolBar, TB_ADDBUTTONSW, _countof(TbButtons), (LPARAM)TbButtons);
     SendMessageW(m_hToolBar, TB_AUTOSIZE, 0, 0);
@@ -296,7 +336,7 @@ CMainWindow::CreateToolBar()
 }
 
 bool
-CMainWindow::CreateStatusBar()
+CDeviceManager::CreateStatusBar(void)
 {
     int StatWidths[] = {110, -1}; // widths of status bar
     bool bRet = FALSE;
@@ -309,7 +349,7 @@ CMainWindow::CreateStatusBar()
                                    0, 0, 0, 0,
                                    m_hMainWnd,
                                    (HMENU)IDC_STATUSBAR,
-                                   g_hInstance,
+                                   g_hThisInstance,
                                    NULL);
     if (m_hStatusBar)
     {
@@ -323,12 +363,14 @@ CMainWindow::CreateStatusBar()
     return bRet;
 }
 
-void CMainWindow::UpdateUiContext(_In_ LPTV_ITEMW TvItem)
+void CDeviceManager::UpdateToolbar()
 {
     WORD State;
 
+    CNode *Node = m_DeviceView->GetSelectedNode();
+
     // properties button
-    if (m_DeviceView->HasProperties(TvItem))
+    if (Node->HasProperties())
     {
         State = TBSTATE_ENABLED;
     }
@@ -341,7 +383,8 @@ void CMainWindow::UpdateUiContext(_In_ LPTV_ITEMW TvItem)
     SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UNINSTALL_DRV, MAKELPARAM(State, 0)); // hack
 
     // enable driver button
-    if (m_DeviceView->IsDisabled(TvItem))
+    if (Node->GetNodeType() == DeviceNode &&
+        dynamic_cast<CDeviceNode *>(Node)->IsDisabled())
     {
         State = TBSTATE_ENABLED;
     }
@@ -352,7 +395,9 @@ void CMainWindow::UpdateUiContext(_In_ LPTV_ITEMW TvItem)
     SendMessageW(m_hToolBar, TB_SETSTATE, IDC_ENABLE_DRV, MAKELPARAM(State, 0));
 
     // disable driver button
-    if (m_DeviceView->CanDisable(TvItem) && !m_DeviceView->IsDisabled(TvItem))
+    if (Node->GetNodeType() == DeviceNode &&
+        dynamic_cast<CDeviceNode *>(Node)->CanDisable() &&
+        !dynamic_cast<CDeviceNode *>(Node)->IsDisabled())
     {
         State = TBSTATE_ENABLED;
     }
@@ -361,20 +406,13 @@ void CMainWindow::UpdateUiContext(_In_ LPTV_ITEMW TvItem)
         State = TBSTATE_HIDDEN;
     }
     SendMessageW(m_hToolBar, TB_SETSTATE, IDC_DISABLE_DRV, MAKELPARAM(State, 0));
-
-
-
-    
-
 }
 
-
-
 bool
-CMainWindow::StatusBarLoadString(IN HWND hStatusBar,
-                                 IN INT PartId,
-                                 IN HINSTANCE hInstance,
-                                 IN UINT uID)
+CDeviceManager::StatusBarLoadString(_In_ HWND hStatusBar,
+                                    _In_ INT PartId,
+                                    _In_ HINSTANCE hInstance,
+                                    _In_ UINT uID)
 {
     CAtlStringW szMessage;
     bool bRet = false;
@@ -393,7 +431,7 @@ CMainWindow::StatusBarLoadString(IN HWND hStatusBar,
 }
 
 LRESULT
-CMainWindow::OnCreate(HWND hwnd)
+CDeviceManager::OnCreate(_In_ HWND hwnd)
 {
     LRESULT RetCode;
 
@@ -411,7 +449,7 @@ CMainWindow::OnCreate(HWND hwnd)
         if (m_DeviceView->Initialize())
         {
             // Do the initial scan
-            ScanForHardwareChanges();
+            RefreshView(m_DeviceView->GetCurrentView(), true);
 
             // Display the window according to the user request
             ShowWindow(hwnd, m_CmdShow);
@@ -423,7 +461,7 @@ CMainWindow::OnCreate(HWND hwnd)
 }
 
 LRESULT
-CMainWindow::OnSize()
+CDeviceManager::OnSize(void)
 {
     RECT rcClient, rcTool, rcStatus;
     INT lvHeight, iToolHeight, iStatusHeight;
@@ -458,23 +496,21 @@ CMainWindow::OnSize()
 }
 
 LRESULT
-CMainWindow::OnNotify(LPARAM lParam)
+CDeviceManager::OnNotify(_In_ LPARAM lParam)
 {
     LPNMHDR NmHdr = (LPNMHDR)lParam;
-    LRESULT Ret;
+    LRESULT Ret = 0;
 
     switch (NmHdr->code)
     {
         case TVN_SELCHANGED:
         {
-            LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
-            UpdateUiContext(&NmTreeView->itemNew);
+            UpdateToolbar();
             break;
         }
 
         case NM_DBLCLK:
         {
-            LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
             m_DeviceView->DisplayPropertySheet();
             break;
         }
@@ -494,6 +530,7 @@ CMainWindow::OnNotify(LPARAM lParam)
         case TTN_GETDISPINFO:
         {
              LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam;
+             lpttt->hinst = g_hThisInstance;
 
             UINT_PTR idButton = lpttt->hdr.idFrom;
             switch (idButton)
@@ -505,34 +542,34 @@ CMainWindow::OnNotify(LPARAM lParam)
                     lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SCAN);
                     break;
                 case IDC_ENABLE_DRV:
-                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ENABLE);
+                    lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_ENABLE);
                     break;
                 case IDC_DISABLE_DRV:
-                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_DISABLE);
+                    lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_DISABLE);
                     break;
                 case IDC_UPDATE_DRV:
-                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UPDATE);
+                    lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE);
                     break;
                 case IDC_UNINSTALL_DRV:
-                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UNINSTALL);
+                    lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL);
                     break;
             }
             break;
         }
     }
 
-    return 0;
+    return Ret;
 }
 
 LRESULT
-CMainWindow::OnContext(LPARAM lParam)
+CDeviceManager::OnContext(_In_ LPARAM lParam)
 {
     return m_DeviceView->OnContextMenu(lParam);
 }
 
 LRESULT
-CMainWindow::OnCommand(WPARAM wParam,
-                       LPARAM lParam)
+CDeviceManager::OnCommand(_In_ WPARAM wParam,
+                          _In_ LPARAM /*lParam*/)
 {
     LRESULT RetCode = 0;
     WORD Msg;
@@ -543,50 +580,14 @@ CMainWindow::OnCommand(WPARAM wParam,
     switch (Msg)
     {
         case IDC_PROPERTIES:
-        {
-            m_DeviceView->DisplayPropertySheet();
-            break;
-        }
-
         case IDC_SCAN_HARDWARE:
-        {
-            ScanForHardwareChanges();
-            break;
-        }
-
         case IDC_ENABLE_DRV:
-        {
-            bool NeedsReboot;
-            if (m_DeviceView->EnableSelectedDevice(true, NeedsReboot) &&
-                NeedsReboot)
-            {
-                MessageBox(m_hMainWnd, L"Rebooting", L"Enable", MB_OK);
-            }
-            break;
-        }
-
         case IDC_DISABLE_DRV:
-        {
-            bool NeedsReboot;
-            m_DeviceView->EnableSelectedDevice(false, NeedsReboot);
-            break;
-        }
-
         case IDC_UPDATE_DRV:
-        {
-            MessageBox(m_hMainWnd, L"Not yet implemented", L"Update Driver", MB_OK);
-            break;
-        }
-
         case IDC_UNINSTALL_DRV:
-        {
-            MessageBox(m_hMainWnd, L"Not yet implemented", L"Uninstall Driver", MB_OK);
-            break;
-        }
-
         case IDC_ADD_HARDWARE:
         {
-            MessageBox(m_hMainWnd, L"Not yet implemented", L"Add Hardware", MB_OK);
+            m_DeviceView->OnAction(Msg);
             break;
         }
 
@@ -596,9 +597,9 @@ CMainWindow::OnCommand(WPARAM wParam,
             HMENU hMenu = CreatePopupMenu();
             m_DeviceView->CreateActionMenu(hMenu, true);
 
+            // Calculate where to put the menu
             RECT rc;
             GetMenuItemRect(m_hMainWnd, m_hMenu, 1, &rc);
-
             LONG Height = rc.bottom - rc.top;
 
             // Display the menu
@@ -615,13 +616,13 @@ CMainWindow::OnCommand(WPARAM wParam,
 
         case IDC_DEVBYTYPE:
         {
-            RefreshView(DevicesByType);
+            RefreshView(DevicesByType, false);
             break;
         }
 
         case IDC_DEVBYCONN:
         {
-            RefreshView(DevicesByConnection);
+            RefreshView(DevicesByConnection, false);
             break;
         }
 
@@ -640,10 +641,7 @@ CMainWindow::OnCommand(WPARAM wParam,
                 CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_CHECKED);
             }
             // Refresh the device view
-            m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
-                                  false,
-                                  true,
-                                  NULL);
+            RefreshView(m_DeviceView->GetCurrentView(), false);
             break;
         }
 
@@ -679,8 +677,14 @@ CMainWindow::OnCommand(WPARAM wParam,
     return RetCode;
 }
 
+void
+CDeviceManager::OnActivate(void)
+{
+    m_DeviceView->SetFocus();
+}
+
 LRESULT
-CMainWindow::OnDestroy()
+CDeviceManager::OnDestroy(void)
 {
     // Uninitialize the device view
     m_DeviceView->Uninitialize();
@@ -699,16 +703,16 @@ CMainWindow::OnDestroy()
 }
 
 LRESULT CALLBACK
-CMainWindow::MainWndProc(HWND hwnd,
-                         UINT msg,
-                         WPARAM wParam,
-                         LPARAM lParam)
+CDeviceManager::MainWndProc(_In_ HWND hwnd,
+                            _In_ UINT msg,
+                            _In_ WPARAM wParam,
+                            _In_ LPARAM lParam)
 {
-    CMainWindow *This;
+    CDeviceManager *This;
     LRESULT RetCode = 0;
 
     // Get the object pointer from window context
-    This = (CMainWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+    This = (CDeviceManager *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
     if (This == NULL)
     {
         // Check that this isn't a create message
@@ -724,7 +728,7 @@ CMainWindow::MainWndProc(HWND hwnd,
         case WM_CREATE:
         {
             // Get the object pointer from the create param
-            This = (CMainWindow *)((LPCREATESTRUCT)lParam)->lpCreateParams;
+            This = (CDeviceManager *)((LPCREATESTRUCT)lParam)->lpCreateParams;
 
             // Store the pointer in the window's global user data
             SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)This);
@@ -783,6 +787,40 @@ CMainWindow::MainWndProc(HWND hwnd,
             break;
         }
 
+        case WM_DEVICECHANGE:
+        {
+            if (wParam == DBT_DEVNODES_CHANGED)
+            {
+                //
+                // The OS can send multiple change messages in quick succession. To avoid
+                // refreshing multiple times (and to avoid waiting in the message thread)
+                // we set a timer to run in 500ms, which should leave enough time for all
+                // the messages to come through. Wrap so we don't set multiple timers
+                //
+                if (InterlockedCompareExchange((LONG *)&This->m_RefreshPending, TRUE, FALSE) == FALSE)
+                {
+                    SetTimer(hwnd, REFRESH_TIMER, 500, NULL);
+                }
+            }
+            break;
+        }
+
+        case WM_TIMER:
+        {
+            if (wParam == REFRESH_TIMER)
+            {
+                // Schedule a refresh (this just creates a thread and returns)
+                This->RefreshView(This->m_DeviceView->GetCurrentView(), true);
+
+                // Cleanup the timer
+                KillTimer(hwnd, REFRESH_TIMER);
+
+                // Allow more change notifications
+                InterlockedExchange((LONG *)&This->m_RefreshPending, FALSE);
+            }
+            break;
+        }
+
         case WM_ENTERMENULOOP:
         {
             This->UpdateStatusBar(true);
@@ -801,7 +839,13 @@ CMainWindow::MainWndProc(HWND hwnd,
             DestroyWindow(hwnd);
             break;
         }
-        
+
+        case WM_ACTIVATE:
+        {
+            if (LOWORD(hwnd))
+                This->OnActivate();
+            break;
+        }
 
         case WM_DESTROY:
         {
@@ -820,47 +864,3 @@ HandleDefaultMessage:
 
     return RetCode;
 }
-
-
-//////// MOVE ME ////////////////
-
-HINSTANCE g_hInstance = NULL;
-HANDLE ProcessHeap = NULL;
-
-BOOL
-WINAPI
-DeviceManager_ExecuteW(HWND hWndParent,
-                       HINSTANCE hInst,
-                       LPCWSTR lpMachineName,
-                       int nCmdShow)
-{
-    CMainWindow MainWindow;
-    INITCOMMONCONTROLSEX icex;
-    CAtlStringW szAppName;
-    int Ret = 1;
-
-    // Store the global values
-    g_hInstance = hInst;
-    ProcessHeap = GetProcessHeap();
-
-    // Initialize common controls
-    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
-    icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES;
-    InitCommonControlsEx(&icex);
-
-    // Load the application name
-    if (szAppName.LoadStringW(g_hInstance, IDS_APPNAME))
-    {
-        // Initialize the main window
-        if (MainWindow.Initialize(szAppName, nCmdShow))
-        {
-            // Run the application
-            Ret = MainWindow.Run();
-
-            // Uninitialize the main window
-            MainWindow.Uninitialize();
-        }
-    }
-
-    return Ret;
-}