+ "-x c" added to gcc (type changed to C)
[public/netxms.git] / src / console / win32 / nxcon.cpp
CommitLineData
3bf7e95e
VK
1// nxcon.cpp : Defines the class behaviors for the application.
2//
3
4#include "stdafx.h"
5#include "nxcon.h"
6
7#include "MainFrm.h"
8#include "LoginDialog.h"
9
10#ifdef _DEBUG
11#define new DEBUG_NEW
12#undef THIS_FILE
13static char THIS_FILE[] = __FILE__;
14#endif
15
16
17//
18// Wrapper for client library event handler
19//
20
21static void ClientEventHandler(DWORD dwEvent, DWORD dwCode, void *pArg)
22{
23 theApp.EventHandler(dwEvent, dwCode, pArg);
24}
25
26
8e748b3e
VK
27//
28// Wrapper for client library debug callback
29//
30
31static void ClientDebugCallback(char *pszMsg)
32{
33 theApp.DebugCallback(pszMsg);
34}
35
36
3bf7e95e
VK
37//
38// CConsoleApp
39//
40
41BEGIN_MESSAGE_MAP(CConsoleApp, CWinApp)
42 //{{AFX_MSG_MAP(CConsoleApp)
43 ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
44 ON_COMMAND(ID_VIEW_CONTROLPANEL, OnViewControlpanel)
45 ON_COMMAND(ID_VIEW_EVENTS, OnViewEvents)
46 ON_COMMAND(ID_VIEW_MAP, OnViewMap)
47 ON_COMMAND(ID_CONNECT_TO_SERVER, OnConnectToServer)
48 ON_COMMAND(ID_VIEW_OBJECTBROWSER, OnViewObjectbrowser)
a5f8f9b0 49 ON_COMMAND(ID_CONTROLPANEL_EVENTS, OnControlpanelEvents)
8e748b3e 50 ON_COMMAND(ID_VIEW_DEBUG, OnViewDebug)
417924d6 51 ON_COMMAND(ID_CONTROLPANEL_USERS, OnControlpanelUsers)
3bf7e95e
VK
52 //}}AFX_MSG_MAP
53END_MESSAGE_MAP()
54
55
56//
57// CConsoleApp construction
58//
59
60CConsoleApp::CConsoleApp()
61{
62 m_bCtrlPanelActive = FALSE;
63 m_bEventBrowserActive = FALSE;
a5f8f9b0 64 m_bEventEditorActive = FALSE;
417924d6 65 m_bUserEditorActive = FALSE;
3bf7e95e 66 m_bObjectBrowserActive = FALSE;
8e748b3e 67 m_bDebugWindowActive = FALSE;
3bf7e95e
VK
68 m_dwClientState = STATE_DISCONNECTED;
69}
70
999bd324
VK
71
72//
73// CConsoleApp destruction
74//
75
76CConsoleApp::~CConsoleApp()
77{
999bd324
VK
78}
79
80
3bf7e95e
VK
81//
82// The one and only CConsoleApp object
83//
84
85CConsoleApp theApp;
86
87
88//
89// CConsoleApp initialization
90//
91
92BOOL CConsoleApp::InitInstance()
93{
94 BOOL bSetWindowPos;
95 DWORD dwBytes;
96 BYTE *pData;
8e748b3e 97 HMENU hMenu;
3bf7e95e
VK
98
99 if (!AfxSocketInit())
100 {
101 AfxMessageBox(IDP_SOCKETS_INIT_FAILED, MB_OK | MB_ICONSTOP);
102 return FALSE;
103 }
104
105 if (!NXCInitialize())
106 {
107 AfxMessageBox(IDS_NXC_INIT_FAILED, MB_OK | MB_ICONSTOP);
108 return FALSE;
109 }
110 NXCSetEventHandler(ClientEventHandler);
111
112 AfxEnableControlContainer();
113
114 // Standard initialization
115 // If you are not using these features and wish to reduce the size
116 // of your final executable, you should remove from the following
117 // the specific initialization routines you do not need.
118
119#ifdef _AFXDLL
120 Enable3dControls(); // Call this when using MFC in a shared DLL
121#else
122 Enable3dControlsStatic(); // Call this when linking to MFC statically
123#endif
124
125 // Change the registry key under which our settings are stored.
126 SetRegistryKey(_T("NetXMS"));
127
128 // To create the main window, this code creates a new frame window
129 // object and then sets it as the application's main window object.
130
131 CMDIFrameWnd* pFrame = new CMainFrame;
132 m_pMainWnd = pFrame;
133
134 // create main MDI frame window
135 if (!pFrame->LoadFrame(IDR_MAINFRAME))
136 return FALSE;
137
8e748b3e
VK
138 // Load shared MDI menus and accelerator table
139 HINSTANCE hInstance = AfxGetResourceHandle();
140
141 hMenu = ::LoadMenu(hInstance, MAKEINTRESOURCE(IDM_VIEW_SPECIFIC));
142
143 m_hMDIMenu = ::LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));
144 InsertMenu(m_hMDIMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(hMenu, 0), "&Window");
145
146 m_hEventBrowserMenu = ::LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));
147 InsertMenu(m_hEventBrowserMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(hMenu, 0), "&Window");
148 InsertMenu(m_hEventBrowserMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(hMenu, 1), "&Event");
149
2060ba91
VK
150 m_hObjectBrowserMenu = ::LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));
151 InsertMenu(m_hObjectBrowserMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(hMenu, 0), "&Window");
152 InsertMenu(m_hObjectBrowserMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(hMenu, 2), "&Object");
153
cad81e33
VK
154 m_hUserEditorMenu = ::LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));
155 InsertMenu(m_hUserEditorMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(hMenu, 0), "&Window");
156 InsertMenu(m_hUserEditorMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(hMenu, 3), "&User");
157
8e748b3e
VK
158 m_hMDIAccel = ::LoadAccelerators(hInstance, MAKEINTRESOURCE(IDA_MDI_DEFAULT));
159 m_hEventBrowserAccel = ::LoadAccelerators(hInstance, MAKEINTRESOURCE(IDA_MDI_DEFAULT));
2060ba91 160 m_hObjectBrowserAccel = ::LoadAccelerators(hInstance, MAKEINTRESOURCE(IDA_OBJECT_BROWSER));
cad81e33 161 m_hUserEditorAccel = ::LoadAccelerators(hInstance, MAKEINTRESOURCE(IDA_MDI_DEFAULT));
3bf7e95e
VK
162
163 // Load configuration from registry
164 dwBytes = sizeof(WINDOWPLACEMENT);
165 bSetWindowPos = GetProfileBinary(_T("General"), _T("WindowPlacement"),
166 &pData, (UINT *)&dwBytes);
167 strcpy(g_szServer, (LPCTSTR)GetProfileString(_T("Connection"), _T("Server"), _T("localhost")));
168 strcpy(g_szLogin, (LPCTSTR)GetProfileString(_T("Connection"), _T("Login"), NULL));
169
170 // The main window has been initialized, so show and update it.
171 if (bSetWindowPos)
172 {
173 pFrame->SetWindowPlacement((WINDOWPLACEMENT *)pData);
174 if (pFrame->IsIconic())
175 pFrame->ShowWindow(SW_RESTORE);
176 }
177 else
178 {
179 pFrame->ShowWindow(m_nCmdShow);
180 }
181 pFrame->UpdateWindow();
182 pFrame->PostMessage(WM_COMMAND, ID_CONNECT_TO_SERVER, 0);
183
184 return TRUE;
185}
186
187/////////////////////////////////////////////////////////////////////////////
188// CConsoleApp message handlers
189
190int CConsoleApp::ExitInstance()
191{
8e748b3e
VK
192 NXCSetDebugCallback(NULL);
193 NXCDisconnect();
194
3bf7e95e 195 // Free resources
8e748b3e
VK
196 SafeFreeResource(m_hMDIMenu);
197 SafeFreeResource(m_hMDIAccel);
198 SafeFreeResource(m_hEventBrowserMenu);
199 SafeFreeResource(m_hEventBrowserAccel);
3bf7e95e
VK
200
201 return CWinApp::ExitInstance();
202}
203
204
205/////////////////////////////////////////////////////////////////////////////
206// CAboutDlg dialog used for App About
207
208class CAboutDlg : public CDialog
209{
210public:
211 CAboutDlg();
212
213// Dialog Data
214 //{{AFX_DATA(CAboutDlg)
215 enum { IDD = IDD_ABOUTBOX };
216 //}}AFX_DATA
217
218 // ClassWizard generated virtual function overrides
219 //{{AFX_VIRTUAL(CAboutDlg)
220 protected:
221 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
222 //}}AFX_VIRTUAL
223
224// Implementation
225protected:
226 //{{AFX_MSG(CAboutDlg)
227 // No message handlers
228 //}}AFX_MSG
229 DECLARE_MESSAGE_MAP()
230};
231
232CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
233{
234 //{{AFX_DATA_INIT(CAboutDlg)
235 //}}AFX_DATA_INIT
236}
237
238void CAboutDlg::DoDataExchange(CDataExchange* pDX)
239{
240 CDialog::DoDataExchange(pDX);
241 //{{AFX_DATA_MAP(CAboutDlg)
242 //}}AFX_DATA_MAP
243}
244
245BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
246 //{{AFX_MSG_MAP(CAboutDlg)
247 // No message handlers
248 //}}AFX_MSG_MAP
249END_MESSAGE_MAP()
250
251// App command to run the dialog
252void CConsoleApp::OnAppAbout()
253{
254 CAboutDlg aboutDlg;
255 aboutDlg.DoModal();
256}
257
258/////////////////////////////////////////////////////////////////////////////
259// CConsoleApp message handlers
260
261
262void CConsoleApp::OnViewControlpanel()
263{
264 CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, m_pMainWnd);
265
266 // create a new MDI child window or open existing
267 if (m_bCtrlPanelActive)
268 m_pwndCtrlPanel->BringWindowToTop();
269 else
270 pFrame->CreateNewChild(
8e748b3e 271 RUNTIME_CLASS(CControlPanel), IDR_CTRLPANEL, m_hMDIMenu, m_hMDIAccel);
3bf7e95e
VK
272}
273
274
275//
276// This method called when new view is created
277//
278
279void CConsoleApp::OnViewCreate(DWORD dwView, CWnd *pWnd)
280{
281 switch(dwView)
282 {
283 case IDR_CTRLPANEL:
284 m_bCtrlPanelActive = TRUE;
285 m_pwndCtrlPanel = pWnd;
286 break;
287 case IDR_EVENTS:
288 m_bEventBrowserActive = TRUE;
289 m_pwndEventBrowser = (CEventBrowser *)pWnd;
290 break;
291 case IDR_OBJECTS:
292 m_bObjectBrowserActive = TRUE;
293 m_pwndObjectBrowser = pWnd;
294 break;
a5f8f9b0
VK
295 case IDR_EVENT_EDITOR:
296 m_bEventEditorActive = TRUE;
297 m_pwndEventEditor = (CEventEditor *)pWnd;
298 break;
417924d6
VK
299 case IDR_USER_EDITOR:
300 m_bUserEditorActive = TRUE;
301 m_pwndUserEditor = (CUserEditor *)pWnd;
302 break;
8e748b3e
VK
303 case IDR_DEBUG_WINDOW:
304 m_bDebugWindowActive = TRUE;
305 m_pwndDebugWindow = (CDebugFrame *)pWnd;
306 NXCSetDebugCallback(ClientDebugCallback);
307 break;
3bf7e95e
VK
308 default:
309 break;
310 }
311}
312
313
314//
315// This method called when view is destroyed
316//
317
318void CConsoleApp::OnViewDestroy(DWORD dwView, CWnd *pWnd)
319{
320 switch(dwView)
321 {
322 case IDR_CTRLPANEL:
323 m_bCtrlPanelActive = FALSE;
324 break;
325 case IDR_EVENTS:
326 m_bEventBrowserActive = FALSE;
327 break;
328 case IDR_OBJECTS:
329 m_bObjectBrowserActive = FALSE;
330 break;
a5f8f9b0
VK
331 case IDR_EVENT_EDITOR:
332 m_bEventEditorActive = FALSE;
333 break;
417924d6
VK
334 case IDR_USER_EDITOR:
335 m_bUserEditorActive = FALSE;
336 break;
8e748b3e
VK
337 case IDR_DEBUG_WINDOW:
338 m_bDebugWindowActive = FALSE;
339 NXCSetDebugCallback(NULL);
340 break;
3bf7e95e
VK
341 default:
342 break;
343 }
344}
345
346void CConsoleApp::OnViewEvents()
347{
348 CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, m_pMainWnd);
349
350 // create a new MDI child window or open existing
351 if (m_bEventBrowserActive)
352 m_pwndEventBrowser->BringWindowToTop();
353 else
354 pFrame->CreateNewChild(
8e748b3e 355 RUNTIME_CLASS(CEventBrowser), IDR_EVENTS, m_hEventBrowserMenu, m_hEventBrowserAccel);
3bf7e95e
VK
356}
357
358void CConsoleApp::OnViewMap()
359{
360 CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, m_pMainWnd);
361
362 // create a new MDI child window
f7a7f8e4 363 pFrame->CreateNewChild(RUNTIME_CLASS(CMapFrame), IDR_MAPFRAME, m_hMDIMenu, m_hMDIAccel);
3bf7e95e
VK
364}
365
366void CConsoleApp::OnConnectToServer()
367{
368 CLoginDialog dlgLogin;
f7a7f8e4 369 DWORD dwResult;
3bf7e95e
VK
370
371 dlgLogin.m_szServer = g_szServer;
372 dlgLogin.m_szLogin = g_szLogin;
f7a7f8e4 373 do
3bf7e95e
VK
374 {
375 if (dlgLogin.DoModal() != IDOK)
376 {
377 PostQuitMessage(1);
378 break;
379 }
380 strcpy(g_szServer, (LPCTSTR)dlgLogin.m_szServer);
381 strcpy(g_szLogin, (LPCTSTR)dlgLogin.m_szLogin);
382 strcpy(g_szPassword, (LPCTSTR)dlgLogin.m_szPassword);
383
384 // Save last connection parameters
385 WriteProfileString(_T("Connection"), _T("Server"), g_szServer);
386 WriteProfileString(_T("Connection"), _T("Login"), g_szLogin);
387
388 // Initiate connection
f7a7f8e4
VK
389 dwResult = DoLogin();
390 if (dwResult != RCC_SUCCESS)
3bf7e95e 391 {
f7a7f8e4
VK
392 char szBuffer[256];
393
394 sprintf(szBuffer, "Unable to connect: %s", NXCGetErrorText(dwResult));
395 m_pMainWnd->MessageBox(szBuffer, "Connection error", MB_OK | MB_ICONSTOP);
3bf7e95e
VK
396 }
397 }
f7a7f8e4 398 while(dwResult != RCC_SUCCESS);
3bf7e95e
VK
399}
400
401void CConsoleApp::OnViewObjectbrowser()
402{
403 CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, m_pMainWnd);
404
405 // create a new MDI child window or open existing
406 if (m_bObjectBrowserActive)
407 m_pwndObjectBrowser->BringWindowToTop();
408 else
409 pFrame->CreateNewChild(
2060ba91 410 RUNTIME_CLASS(CObjectBrowser), IDR_OBJECTS, m_hObjectBrowserMenu, m_hObjectBrowserAccel);
3bf7e95e
VK
411}
412
413
414//
415// Event handler for client libray events
416//
417
418void CConsoleApp::EventHandler(DWORD dwEvent, DWORD dwCode, void *pArg)
419{
3bf7e95e
VK
420 CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, m_pMainWnd);
421
422 switch(dwEvent)
423 {
424 case NXC_EVENT_STATE_CHANGED:
425 switch(dwCode)
426 {
427 case STATE_CONNECTING:
3bf7e95e
VK
428 break;
429 case STATE_IDLE:
3bf7e95e
VK
430 if ((m_bEventBrowserActive) && (m_dwClientState == STATE_SYNC_EVENTS))
431 m_pwndEventBrowser->EnableDisplay(TRUE);
432 break;
433 case STATE_DISCONNECTED:
3bf7e95e
VK
434 break;
435 case STATE_SYNC_EVENTS:
436 if (m_bEventBrowserActive)
437 m_pwndEventBrowser->EnableDisplay(FALSE);
438 break;
439 default:
440 break;
441 }
442 m_dwClientState = dwCode;
443 break;
3bf7e95e
VK
444 case NXC_EVENT_NEW_ELOG_RECORD:
445 if (m_bEventBrowserActive)
446 m_pwndEventBrowser->AddEvent((NXC_EVENT *)pArg);
447 MemFree(pArg);
3bf7e95e 448 break;
89d4d2a2
VK
449 case NXC_EVENT_OBJECT_CHANGED:
450 ((CMainFrame *)m_pMainWnd)->PostMessage(WM_OBJECT_CHANGE, dwCode, (LPARAM)pArg);
451 break;
fadbdf37
VK
452 case NXC_EVENT_USER_DB_CHANGED:
453 ((CMainFrame *)m_pMainWnd)->PostMessage(WM_USERDB_CHANGE, dwCode, (LPARAM)pArg);
454 break;
3bf7e95e
VK
455 default:
456 break;
457 }
458}
a5f8f9b0 459
999bd324
VK
460
461//
462// Handler for WM_COMMAND(ID_CONTROLPANEL_EVENTS) message
463//
464
a5f8f9b0
VK
465void CConsoleApp::OnControlpanelEvents()
466{
467 CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, m_pMainWnd);
468
469 // create a new MDI child window or open existing
470 if (m_bEventEditorActive)
471 m_pwndEventEditor->BringWindowToTop();
472 else
417924d6
VK
473 {
474 DWORD dwResult;
475
f7a7f8e4 476 dwResult = DoRequest(NXCOpenEventDB, "Opening event configuration database...");
417924d6
VK
477 if (dwResult == RCC_SUCCESS)
478 {
479 pFrame->CreateNewChild(
480 RUNTIME_CLASS(CEventEditor), IDR_EVENT_EDITOR, m_hMDIMenu, m_hMDIAccel);
481 }
482 else
483 {
484 char szBuffer[256];
485
486 sprintf(szBuffer, "Unable to open event configuration database:\n%s", NXCGetErrorText(dwResult));
487 GetMainWnd()->MessageBox(szBuffer, "Error", MB_ICONSTOP);
488 }
489 }
490}
491
492
493//
494// Handler for WM_COMMAND(ID_CONTROLPANEL_USERS) message
495//
496
497void CConsoleApp::OnControlpanelUsers()
498{
499 CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, m_pMainWnd);
500
501 // create a new MDI child window or open existing
502 if (m_bUserEditorActive)
503 m_pwndUserEditor->BringWindowToTop();
504 else
505 {
506 DWORD dwResult;
507
f7a7f8e4 508 dwResult = DoRequest(NXCLockUserDB, "Locking user database...");
417924d6
VK
509 if (dwResult == RCC_SUCCESS)
510 {
511 pFrame->CreateNewChild(
cad81e33 512 RUNTIME_CLASS(CUserEditor), IDR_USER_EDITOR, m_hUserEditorMenu, m_hUserEditorAccel);
417924d6
VK
513 }
514 else
515 {
516 char szBuffer[256];
517
518 sprintf(szBuffer, "Unable to lock user database:\n%s", NXCGetErrorText(dwResult));
519 GetMainWnd()->MessageBox(szBuffer, "Error", MB_ICONSTOP);
520 }
521 }
a5f8f9b0
VK
522}
523
524
8e748b3e
VK
525//
526// Handler for WM_COMMAND::ID_VIEW_DEBUG message
527//
528
529void CConsoleApp::OnViewDebug()
530{
531 CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, m_pMainWnd);
532
533 // create a new MDI child window or open existing
534 if (m_bDebugWindowActive)
535 m_pwndDebugWindow->BringWindowToTop();
536 else
537 pFrame->CreateNewChild(
538 RUNTIME_CLASS(CDebugFrame), IDR_DEBUG_WINDOW, m_hMDIMenu, m_hMDIAccel);
539}
89d4d2a2
VK
540
541
542//
543// Print debug information
544//
545
546void CConsoleApp::DebugPrintf(char *szFormat, ...)
547{
548 if (m_bDebugWindowActive)
549 {
550 char szBuffer[1024];
551 va_list args;
552
553 va_start(args, szFormat);
554 vsprintf(szBuffer, szFormat, args);
555 va_end(args);
556
557 m_pwndDebugWindow->AddMessage(szBuffer);
558 }
559}
2057008d
VK
560
561
562//
563// Edit properties of specific object
564//
565
566void CConsoleApp::ObjectProperties(DWORD dwObjectId)
567{
568 CObjectPropSheet wndPropSheet("Object Properties", GetMainWnd(), 0);
569 CNodePropsGeneral wndNodeGeneral;
8e2809bb 570 CObjectPropsGeneral wndObjectGeneral;
2057008d 571 CObjectPropCaps wndObjectCaps;
8e2809bb 572 CObjectPropsSecurity wndObjectSecurity;
2057008d
VK
573 NXC_OBJECT *pObject;
574 char szBuffer[32];
575
576 pObject = NXCFindObjectById(dwObjectId);
577 if (pObject != NULL)
578 {
579 // Create "General" tab
8e2809bb 580 if (pObject->iClass == OBJECT_NODE)
2057008d 581 {
8e2809bb
VK
582 wndNodeGeneral.m_dwObjectId = dwObjectId;
583 wndNodeGeneral.m_strName = pObject->szName;
584 wndNodeGeneral.m_strOID = pObject->node.szObjectId;
585 wndNodeGeneral.m_strPrimaryIp = IpToStr(pObject->dwIpAddr, szBuffer);
586 wndNodeGeneral.m_iAgentPort = (int)pObject->node.wAgentPort;
587 wndNodeGeneral.m_strCommunity = pObject->node.szCommunityString;
588 wndNodeGeneral.m_iAuthType = pObject->node.wAuthMethod;
589 wndNodeGeneral.m_strSecret = pObject->node.szSharedSecret;
590 wndPropSheet.AddPage(&wndNodeGeneral);
591 }
592 else
593 {
594 wndObjectGeneral.m_dwObjectId = dwObjectId;
595 wndObjectGeneral.m_strClass = g_szObjectClass[pObject->iClass];
596 wndObjectGeneral.m_strName = pObject->szName;
597 wndPropSheet.AddPage(&wndObjectGeneral);
2057008d
VK
598 }
599
600 // Create tabs specific for node objects
601 if (pObject->iClass == OBJECT_NODE)
602 {
603 // Create "Capabilities" tab
604 wndObjectCaps.m_pObject = pObject;
605 wndPropSheet.AddPage(&wndObjectCaps);
606 }
607
f6d9527a 608 // Create "Security" tab
8e2809bb
VK
609 wndObjectSecurity.m_pObject = pObject;
610 wndObjectSecurity.m_bInheritRights = pObject->bInheritRights;
611 wndPropSheet.AddPage(&wndObjectSecurity);
f6d9527a
VK
612
613 wndPropSheet.SetObject(pObject);
614 if (wndPropSheet.DoModal() == IDOK)
615 wndPropSheet.SaveObjectChanges();
2057008d
VK
616 }
617}