12db3711db0abf01ed26cbfa486fb845c3fa6d52
[reactos.git] / reactos / dll / shellext / netshell / shfldr_netconnect.cpp
1 /*
2 * Network Connections Shell Folder
3 *
4 * Copyright 2008 Johannes Anderwald <johannes.anderwald@reactos.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 #define MAX_PROPERTY_SHEET_PAGE (10)
24
25 /***********************************************************************
26 * IShellFolder implementation
27 */
28
29 class CNetworkConnections final :
30 public IShellFolder2,
31 public IPersistFolder2,
32 public IShellExecuteHookW
33 {
34 public:
35 CNetworkConnections();
36
37 /* IUnknown */
38 virtual HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvOut);
39 virtual ULONG WINAPI AddRef();
40 virtual ULONG WINAPI Release();
41
42 // IShellFolder
43 virtual HRESULT WINAPI ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes);
44 virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList);
45 virtual HRESULT WINAPI BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut);
46 virtual HRESULT WINAPI BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut);
47 virtual HRESULT WINAPI CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2);
48 virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut);
49 virtual HRESULT WINAPI GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut);
50 virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut);
51 virtual HRESULT WINAPI GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet);
52 virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut);
53
54 /* IShellFolder2 */
55 virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid);
56 virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum);
57 virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay);
58 virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags);
59 virtual HRESULT WINAPI GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv);
60 virtual HRESULT WINAPI GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd);
61 virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid);
62
63 // IPersistFolder2
64 virtual HRESULT WINAPI GetClassID(CLSID *lpClassId);
65 virtual HRESULT WINAPI Initialize(PCIDLIST_ABSOLUTE pidl);
66 virtual HRESULT WINAPI GetCurFolder(PIDLIST_ABSOLUTE *pidl);
67
68 // IShellExecuteHookW
69 virtual HRESULT WINAPI Execute(LPSHELLEXECUTEINFOW pei);
70
71 private:
72 ~CNetworkConnections();
73
74 LONG m_ref;
75 /* both paths are parsible from the desktop */
76 PIDLIST_ABSOLUTE m_pidlRoot;
77 IOleCommandTarget *m_lpOleCmd;
78 };
79
80 class CNetConUiObject final :
81 public IContextMenu3,
82 public IObjectWithSite,
83 public IQueryInfo,
84 public IExtractIconW
85 {
86 public:
87 CNetConUiObject(PCUITEMID_CHILD pidl, IOleCommandTarget *lpOleCmd);
88
89 // IUnknown
90 virtual HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvOut);
91 virtual ULONG WINAPI AddRef();
92 virtual ULONG WINAPI Release();
93
94 // IContextMenu3
95 virtual HRESULT WINAPI QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
96 virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpici);
97 virtual HRESULT WINAPI GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax);
98 virtual HRESULT WINAPI HandleMenuMsg( UINT uMsg, WPARAM wParam, LPARAM lParam);
99 virtual HRESULT WINAPI HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult);
100
101 // IObjectWithSite
102 virtual HRESULT WINAPI SetSite(IUnknown *punk);
103 virtual HRESULT WINAPI GetSite(REFIID iid, void **ppvSite);
104
105 // IQueryInfo
106 virtual HRESULT WINAPI GetInfoFlags(DWORD *pdwFlags);
107 virtual HRESULT WINAPI GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip);
108
109 // IExtractIconW
110 virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags);
111 virtual HRESULT STDMETHODCALLTYPE Extract(LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize);
112
113 private:
114 ~CNetConUiObject();
115
116 LONG m_ref;
117 PCUITEMID_CHILD m_pidl;
118 IUnknown *m_pUnknown;
119 IOleCommandTarget *m_lpOleCmd;
120 };
121
122 static const shvheader NetConnectSFHeader[] = {
123 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 20},
124 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 8},
125 {IDS_SHV_COLUMN_STATE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
126 {IDS_SHV_COLUMN_DEVNAME, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
127 {IDS_SHV_COLUMN_PHONE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
128 {IDS_SHV_COLUMN_OWNER, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
129 };
130
131 #define NETCONNECTSHELLVIEWCOLUMNS 6
132
133 #define COLUMN_NAME 0
134 #define COLUMN_TYPE 1
135 #define COLUMN_STATUS 2
136 #define COLUMN_DEVNAME 3
137 #define COLUMN_PHONE 4
138 #define COLUMN_OWNER 5
139
140 HRESULT ShowNetConnectionStatus(IOleCommandTarget * lpOleCmd, INetConnection * pNetConnect, HWND hwnd);
141
142 CNetworkConnections::CNetworkConnections() :
143 m_ref(0),
144 m_pidlRoot(_ILCreateNetConnect())
145 {
146 HRESULT hr;
147 hr = CoCreateInstance(CLSID_LanConnectStatusUI, NULL, CLSCTX_INPROC_SERVER, IID_IOleCommandTarget, reinterpret_cast<PVOID*>(&m_lpOleCmd));
148 if (FAILED(hr))
149 {
150 ERR("CoCreateInstance failed with %lx\n", hr);
151 m_lpOleCmd = NULL;
152 }
153 }
154
155 CNetworkConnections::~CNetworkConnections()
156 {
157 if (m_lpOleCmd)
158 m_lpOleCmd->Release();
159 SHFree(m_pidlRoot);
160 }
161
162 /**************************************************************************
163 * ISF_NetConnect_fnQueryInterface
164 *
165 * NOTE
166 * supports not IPersist/IPersistFolder
167 */
168 HRESULT WINAPI CNetworkConnections::QueryInterface(REFIID riid, LPVOID *ppvObj)
169 {
170 *ppvObj = NULL;
171
172 if (IsEqualIID(riid, IID_IUnknown) ||
173 IsEqualIID(riid, IID_IShellFolder) ||
174 IsEqualIID(riid, IID_IShellFolder2))
175 {
176 *ppvObj = static_cast<IShellFolder2*>(this);
177 }
178 else if (IsEqualIID (riid, IID_IPersistFolder) ||
179 IsEqualIID (riid, IID_IPersistFolder2))
180 {
181 *ppvObj = static_cast<IPersistFolder2*>(this);
182 }
183 else if (IsEqualIID(riid, IID_IShellExecuteHookW))
184 {
185 *ppvObj = static_cast<IShellExecuteHookW*>(this);
186 }
187 #if 0
188 else if (IsEqualIID(riid, IID_IPersistIDList))
189 {
190 //*ppvObj = static_cast<IPersistIDList*>(this);
191 }
192 #endif
193 if (*ppvObj)
194 {
195 AddRef();
196 return S_OK;
197 }
198
199 /* TODO:
200 * IID_IPersistFreeThreadedObject
201 * IID_IBrowserFrameOptions
202 * IID_IShellIconOverlay
203 * IID_IPersistIDList
204 * IID_IPersist
205 */
206
207 return E_NOINTERFACE;
208 }
209
210 ULONG WINAPI CNetworkConnections::AddRef()
211 {
212 ULONG refCount = InterlockedIncrement(&m_ref);
213
214 return refCount;
215 }
216
217 ULONG WINAPI CNetworkConnections::Release()
218 {
219 ULONG refCount = InterlockedDecrement(&m_ref);
220
221 if (!refCount)
222 delete this;
223
224 return refCount;
225 }
226
227 /**************************************************************************
228 * ISF_NetConnect_fnParseDisplayName
229 */
230 HRESULT WINAPI CNetworkConnections::ParseDisplayName (
231 HWND hwndOwner, LPBC pbcReserved, LPOLESTR lpszDisplayName,
232 DWORD * pchEaten, PIDLIST_RELATIVE * ppidl, DWORD * pdwAttributes)
233 {
234 HRESULT hr = E_UNEXPECTED;
235
236 *ppidl = 0;
237 if (pchEaten)
238 *pchEaten = 0; /* strange but like the original */
239
240 return hr;
241 }
242
243 /**************************************************************************
244 * CreateNetConnectEnumListss()
245 */
246 static BOOL CreateNetConnectEnumList(CEnumIDList *list, DWORD dwFlags)
247 {
248 HRESULT hr;
249 INetConnectionManager *pNetConMan;
250 IEnumNetConnection *pEnumCon;
251 INetConnection *INetCon;
252 ULONG Count;
253 PITEMID_CHILD pidl;
254
255 /* get an instance to of IConnectionManager */
256 hr = INetConnectionManager_Constructor(NULL, IID_INetConnectionManager, (LPVOID*)&pNetConMan);
257 if (FAILED(hr))
258 return FALSE;
259
260 hr = pNetConMan->EnumConnections(NCME_DEFAULT, &pEnumCon);
261 if (FAILED(hr))
262 {
263 pNetConMan->Release();
264 return FALSE;
265 }
266
267 do
268 {
269 hr = pEnumCon->Next(1, &INetCon, &Count);
270 if (hr == S_OK)
271 {
272 pidl = ILCreateNetConnectItem(INetCon);
273 if (pidl)
274 {
275 list->AddToEnumList(pidl);
276 }
277 }
278 else
279 {
280 break;
281 }
282 } while (TRUE);
283
284 pEnumCon->Release();
285 pNetConMan->Release();
286
287 return TRUE;
288 }
289
290 /**************************************************************************
291 * ISF_NetConnect_fnEnumObjects
292 */
293 HRESULT WINAPI CNetworkConnections::EnumObjects(
294 HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
295 {
296 CEnumIDList *pList = new CEnumIDList;
297 *ppEnumIDList = static_cast<LPENUMIDLIST>(pList);
298 if (!pList)
299 return E_OUTOFMEMORY;
300
301 pList->AddRef();
302 CreateNetConnectEnumList(pList, dwFlags);
303 return S_OK;
304 }
305
306 /**************************************************************************
307 * ISF_NetConnect_fnBindToObject
308 */
309 HRESULT WINAPI CNetworkConnections::BindToObject (
310 PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
311 {
312 return E_NOTIMPL;
313 }
314
315 /**************************************************************************
316 * ISF_NetConnect_fnBindToStorage
317 */
318 HRESULT WINAPI CNetworkConnections::BindToStorage(
319 PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
320 {
321 *ppvOut = NULL;
322 return E_NOTIMPL;
323 }
324
325 /**************************************************************************
326 * ISF_NetConnect_fnCompareIDs
327 */
328
329 HRESULT WINAPI CNetworkConnections::CompareIDs(
330 LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
331 {
332 return E_NOTIMPL;
333 }
334
335 /**************************************************************************
336 * ISF_NetConnect_fnCreateViewObject
337 */
338 HRESULT WINAPI CNetworkConnections::CreateViewObject(
339 HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
340 {
341 CSFV cvf;
342 HRESULT hr = E_NOINTERFACE;
343
344 if (!ppvOut)
345 return hr;
346
347 *ppvOut = NULL;
348
349 if (IsEqualIID(riid, IID_IShellView))
350 {
351 ZeroMemory(&cvf, sizeof(cvf));
352 cvf.cbSize = sizeof(cvf);
353 cvf.pshf = static_cast<IShellFolder*>(this);
354
355 IShellView* pShellView;
356 hr = SHCreateShellFolderViewEx(&cvf, &pShellView);
357 if (SUCCEEDED(hr))
358 {
359 hr = pShellView->QueryInterface(riid, ppvOut);
360 pShellView->Release();
361 }
362 }
363
364 return hr;
365 }
366
367 /**************************************************************************
368 * ISF_NetConnect_fnGetAttributesOf
369 */
370 HRESULT WINAPI CNetworkConnections::GetAttributesOf(
371 UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
372 {
373 //IGenericSFImpl *This = (IGenericSFImpl *)iface;
374 HRESULT hr = S_OK;
375 static const DWORD dwNetConnectAttributes = SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
376 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
377
378 static const DWORD dwNetConnectItemAttributes = SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
379 SFGAO_FILESYSANCESTOR | SFGAO_CANRENAME;
380
381 if (!rgfInOut)
382 return E_INVALIDARG;
383
384 if (cidl && !apidl)
385 return E_INVALIDARG;
386
387 if (*rgfInOut == 0)
388 *rgfInOut = ~0;
389
390 if (cidl == 0)
391 *rgfInOut = dwNetConnectAttributes;
392 else
393 *rgfInOut = dwNetConnectItemAttributes;
394
395 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
396 *rgfInOut &= ~SFGAO_VALIDATE;
397
398 return hr;
399 }
400
401 /**************************************************************************
402 * ISF_NetConnect_fnGetUIObjectOf
403 *
404 * PARAMETERS
405 * hwndOwner [in] Parent window for any output
406 * cidl [in] array size
407 * apidl [in] simple pidl array
408 * riid [in] Requested Interface
409 * prgfInOut [ ] reserved
410 * ppvObject [out] Resulting Interface
411 *
412 */
413
414 HRESULT IContextMenuImpl_Constructor(REFIID riid, PCUITEMID_CHILD pidl, LPVOID * ppvOut, IOleCommandTarget * lpOleCmd)
415 {
416 CNetConUiObject *pMenu = new CNetConUiObject(pidl, lpOleCmd);
417 if (!pMenu)
418 return E_OUTOFMEMORY;
419
420 pMenu->AddRef();
421 HRESULT hr = pMenu->QueryInterface(riid, ppvOut);
422 pMenu->Release();
423 return hr;
424 }
425
426 HRESULT WINAPI CNetworkConnections::GetUIObjectOf(
427 HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
428 UINT * prgfInOut, LPVOID * ppvOut)
429 {
430 IUnknown *pObj = NULL;
431 HRESULT hr = E_INVALIDARG;
432
433 if (!ppvOut)
434 return hr;
435
436 *ppvOut = NULL;
437
438 if ((IsEqualIID(riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2) || IsEqualIID(riid, IID_IContextMenu3) ||
439 IsEqualIID(riid, IID_IQueryInfo) || IsEqualIID(riid, IID_IExtractIconW)) && cidl >= 1)
440 {
441 return IContextMenuImpl_Constructor(riid, apidl[0], ppvOut, m_lpOleCmd);
442 }
443 else
444 hr = E_NOINTERFACE;
445
446 *ppvOut = pObj;
447 return hr;
448 }
449
450 /**************************************************************************
451 * ISF_NetConnect_fnGetDisplayNameOf
452 *
453 */
454 HRESULT WINAPI CNetworkConnections::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
455 {
456 LPWSTR pszName;
457 HRESULT hr = E_FAIL;
458 NETCON_PROPERTIES * pProperties;
459 const VALUEStruct * val;
460
461 if (!strRet)
462 return E_INVALIDARG;
463
464 pszName = static_cast<LPWSTR>(CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR)));
465 if (!pszName)
466 return E_OUTOFMEMORY;
467
468 if (_ILIsNetConnect(pidl))
469 {
470 if (LoadStringW(netshell_hInstance, IDS_NETWORKCONNECTION, pszName, MAX_PATH))
471 {
472 pszName[MAX_PATH-1] = L'\0';
473 hr = S_OK;
474 }
475 }
476 else
477 {
478 val = _ILGetValueStruct(pidl);
479 if (val)
480 {
481 if (val->pItem->GetProperties(&pProperties) == S_OK)
482 {
483 if (pProperties->pszwName)
484 {
485 wcscpy(pszName, pProperties->pszwName);
486 hr = S_OK;
487 }
488 NcFreeNetconProperties(pProperties);
489 }
490 }
491
492 }
493
494 if (SUCCEEDED(hr))
495 {
496 strRet->uType = STRRET_WSTR;
497 strRet->pOleStr = pszName;
498 }
499 else
500 {
501 CoTaskMemFree(pszName);
502 }
503
504 return hr;
505 }
506
507 /**************************************************************************
508 * ISF_NetConnect_fnSetNameOf
509 * Changes the name of a file object or subfolder, possibly changing its item
510 * identifier in the process.
511 *
512 * PARAMETERS
513 * hwndOwner [in] Owner window for output
514 * pidl [in] simple pidl of item to change
515 * lpszName [in] the items new display name
516 * dwFlags [in] SHGNO formatting flags
517 * ppidlOut [out] simple pidl returned
518 */
519 HRESULT WINAPI CNetworkConnections::SetNameOf (
520 HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */
521 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD * pPidlOut)
522 {
523 const VALUEStruct * val;
524
525 val = _ILGetValueStruct(pidl);
526 if (!val)
527 return E_FAIL;
528
529 if (!val->pItem)
530 return E_FAIL;
531
532 return val->pItem->Rename(lpName);
533 }
534
535 HRESULT WINAPI CNetworkConnections::GetDefaultSearchGUID(GUID * pguid)
536 {
537 return E_NOTIMPL;
538 }
539
540 HRESULT WINAPI CNetworkConnections::EnumSearches(IEnumExtraSearch ** ppenum)
541 {
542 return E_NOTIMPL;
543 }
544
545 HRESULT WINAPI CNetworkConnections::GetDefaultColumn(DWORD dwRes, ULONG * pSort, ULONG * pDisplay)
546 {
547 if (pSort)
548 *pSort = 0;
549 if (pDisplay)
550 *pDisplay = 0;
551
552 return S_OK;
553 }
554
555 HRESULT WINAPI CNetworkConnections::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
556 {
557 if (!pcsFlags || iColumn >= NETCONNECTSHELLVIEWCOLUMNS)
558 return E_INVALIDARG;
559 *pcsFlags = NetConnectSFHeader[iColumn].pcsFlags;
560 return S_OK;
561 }
562
563 HRESULT WINAPI CNetworkConnections::GetDetailsEx(
564 PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv)
565 {
566 return E_NOTIMPL;
567 }
568
569 HRESULT WINAPI CNetworkConnections::GetDetailsOf(
570 PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS * psd)
571 {
572 WCHAR buffer[MAX_PATH] = {0};
573 HRESULT hr = E_FAIL;
574 const VALUEStruct * val;
575 NETCON_PROPERTIES * pProperties;
576
577 if (iColumn >= NETCONNECTSHELLVIEWCOLUMNS)
578 return E_FAIL;
579
580 psd->fmt = NetConnectSFHeader[iColumn].fmt;
581 psd->cxChar = NetConnectSFHeader[iColumn].cxChar;
582 if (pidl == NULL)
583 {
584 psd->str.uType = STRRET_WSTR;
585 if (LoadStringW(netshell_hInstance, NetConnectSFHeader[iColumn].colnameid, buffer, MAX_PATH))
586 hr = SHStrDupW(buffer, &psd->str.pOleStr);
587
588 return hr;
589 }
590
591 if (iColumn == COLUMN_NAME)
592 {
593 psd->str.uType = STRRET_WSTR;
594 return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str);
595 }
596
597 val = _ILGetValueStruct(pidl);
598 if (!val)
599 return E_FAIL;
600
601 if (!val->pItem)
602 return E_FAIL;
603
604 if (val->pItem->GetProperties(&pProperties) != S_OK)
605 return E_FAIL;
606
607
608 switch (iColumn)
609 {
610 case COLUMN_TYPE:
611 if (pProperties->MediaType == NCM_LAN || pProperties->MediaType == NCM_SHAREDACCESSHOST_RAS)
612 {
613 if (LoadStringW(netshell_hInstance, IDS_TYPE_ETHERNET, buffer, MAX_PATH))
614 {
615 psd->str.uType = STRRET_WSTR;
616 hr = SHStrDupW(buffer, &psd->str.pOleStr);
617 }
618 }
619 break;
620 case COLUMN_STATUS:
621 buffer[0] = L'\0';
622 if (pProperties->Status == NCS_HARDWARE_DISABLED)
623 LoadStringW(netshell_hInstance, IDS_STATUS_NON_OPERATIONAL, buffer, MAX_PATH);
624 else if (pProperties->Status == NCS_DISCONNECTED)
625 LoadStringW(netshell_hInstance, IDS_STATUS_UNREACHABLE, buffer, MAX_PATH);
626 else if (pProperties->Status == NCS_MEDIA_DISCONNECTED)
627 LoadStringW(netshell_hInstance, IDS_STATUS_DISCONNECTED, buffer, MAX_PATH);
628 else if (pProperties->Status == NCS_CONNECTING)
629 LoadStringW(netshell_hInstance, IDS_STATUS_CONNECTING, buffer, MAX_PATH);
630 else if (pProperties->Status == NCS_CONNECTED)
631 LoadStringW(netshell_hInstance, IDS_STATUS_CONNECTED, buffer, MAX_PATH);
632
633 if (buffer[0])
634 {
635 buffer[MAX_PATH-1] = L'\0';
636 psd->str.uType = STRRET_WSTR;
637 hr = SHStrDupW(buffer, &psd->str.pOleStr);
638 }
639 break;
640 case COLUMN_DEVNAME:
641 if (pProperties->pszwDeviceName)
642 {
643 wcscpy(buffer, pProperties->pszwDeviceName);
644 buffer[MAX_PATH-1] = L'\0';
645 psd->str.uType = STRRET_WSTR;
646 hr = SHStrDupW(buffer, &psd->str.pOleStr);
647 }
648 else
649 {
650 psd->str.cStr[0] = '\0';
651 psd->str.uType = STRRET_CSTR;
652 }
653 break;
654 case COLUMN_PHONE:
655 case COLUMN_OWNER:
656 psd->str.cStr[0] = '\0';
657 psd->str.uType = STRRET_CSTR;
658 break;
659 }
660
661 NcFreeNetconProperties(pProperties);
662 return hr;
663 }
664
665 HRESULT WINAPI CNetworkConnections::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
666 {
667 return E_NOTIMPL;
668 }
669
670 //IObjectWithSite
671 //IInternetSecurityManager
672
673 /**************************************************************************
674 * IContextMenu2 Implementation
675 */
676
677 CNetConUiObject::CNetConUiObject(PCUITEMID_CHILD pidl, IOleCommandTarget *lpOleCmd)
678 : m_ref(0),
679 m_pidl(pidl),
680 m_pUnknown(NULL),
681 m_lpOleCmd(lpOleCmd)
682 {
683 if (m_lpOleCmd)
684 m_lpOleCmd->AddRef();
685 }
686
687 CNetConUiObject::~CNetConUiObject()
688 {
689 if (m_lpOleCmd)
690 m_lpOleCmd->Release();
691 }
692
693 /************************************************************************
694 * ISF_NetConnect_IContextMenu_QueryInterface
695 */
696 HRESULT WINAPI CNetConUiObject::QueryInterface(REFIID iid, LPVOID *ppvObject)
697 {
698 *ppvObject = NULL;
699
700 if (IsEqualIID(iid, IID_IContextMenu) || IsEqualIID(iid, IID_IContextMenu2) || IsEqualIID(iid, IID_IContextMenu3))
701 *ppvObject = static_cast<IContextMenu3*>(this);
702 else if (IsEqualIID(iid, IID_IObjectWithSite))
703 *ppvObject = static_cast<IObjectWithSite*>(this);
704 else if (IsEqualIID(iid, IID_IQueryInfo))
705 *ppvObject = static_cast<IQueryInfo*>(this);
706 else if (IsEqualIID(iid, IID_IExtractIconW))
707 *ppvObject = static_cast<IExtractIconW*>(this);
708
709 if (*ppvObject)
710 {
711 AddRef();
712 return S_OK;
713 }
714
715 //LPOLESTR pStr;
716 //StringFromCLSID(iid, &pStr);
717 //MessageBoxW(NULL, L"ISF_NetConnect_IContextMenu2_QueryInterface unhandled", pStr, MB_OK);
718 return E_NOINTERFACE;
719 }
720
721 /************************************************************************
722 * ISF_NetConnect_IContextMenu_AddRef
723 */
724 ULONG WINAPI CNetConUiObject::AddRef()
725 {
726 ULONG refCount;
727
728 refCount = InterlockedIncrement(&m_ref);
729
730 return refCount;
731 }
732
733 /************************************************************************
734 * ISF_NetConnect_IContextMenu_Release
735 */
736 ULONG WINAPI CNetConUiObject::Release()
737 {
738 ULONG refCount;
739
740 refCount = InterlockedDecrement(&m_ref);
741 if (!refCount)
742 delete this;
743
744 return refCount;
745 }
746
747 void WINAPI _InsertMenuItemW (
748 HMENU hmenu,
749 UINT indexMenu,
750 BOOL fByPosition,
751 UINT wID,
752 UINT fType,
753 LPCWSTR dwTypeData,
754 UINT fState)
755 {
756 MENUITEMINFOW mii;
757 WCHAR szText[100];
758
759 ZeroMemory(&mii, sizeof(mii));
760 mii.cbSize = sizeof(mii);
761 if (fType == MFT_SEPARATOR)
762 {
763 mii.fMask = MIIM_ID | MIIM_TYPE;
764 }
765 else if (fType == MFT_STRING)
766 {
767 mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
768 if ((ULONG_PTR)HIWORD((ULONG_PTR)dwTypeData) == 0)
769 {
770 if (LoadStringW(netshell_hInstance, LOWORD((ULONG_PTR)dwTypeData), szText, sizeof(szText)/sizeof(WCHAR)))
771 {
772 szText[(sizeof(szText)/sizeof(WCHAR))-1] = 0;
773 mii.dwTypeData = szText;
774 }
775 else
776 {
777 return;
778 }
779 }
780 else
781 {
782 mii.dwTypeData = (LPWSTR) dwTypeData;
783 }
784 mii.fState = fState;
785 }
786
787 mii.wID = wID;
788 mii.fType = fType;
789 InsertMenuItemW( hmenu, indexMenu, fByPosition, &mii);
790 }
791
792 /**************************************************************************
793 * ISF_NetConnect_IContextMenu_QueryContextMenu()
794 */
795 HRESULT WINAPI CNetConUiObject::QueryContextMenu(
796 HMENU hMenu,
797 UINT indexMenu,
798 UINT idCmdFirst,
799 UINT idCmdLast,
800 UINT uFlags)
801 {
802 const VALUEStruct * val;
803 NETCON_PROPERTIES * pProperties;
804
805 val = _ILGetValueStruct(m_pidl);
806 if (!val)
807 return E_FAIL;
808
809 if (val->pItem->GetProperties(&pProperties) != S_OK)
810 return E_FAIL;
811
812 if (pProperties->Status == NCS_HARDWARE_DISABLED)
813 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_ACTIVATE, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_ACTIVATE), MFS_DEFAULT);
814 else
815 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_DEACTIVATE, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_DEACTIVATE), MFS_ENABLED);
816
817 if (pProperties->Status == NCS_HARDWARE_DISABLED || pProperties->Status == NCS_MEDIA_DISCONNECTED || pProperties->Status == NCS_DISCONNECTED)
818 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_STATUS, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_STATUS), MFS_GRAYED);
819 else if (pProperties->Status == NCS_CONNECTED)
820 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_STATUS, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_STATUS), MFS_DEFAULT);
821 else
822 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_STATUS, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_STATUS), MFS_ENABLED);
823
824 if (pProperties->Status == NCS_HARDWARE_DISABLED || pProperties->Status == NCS_MEDIA_DISCONNECTED)
825 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_REPAIR, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_REPAIR), MFS_GRAYED);
826 else
827 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_REPAIR, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_REPAIR), MFS_ENABLED);
828
829 _InsertMenuItemW(hMenu, indexMenu++, TRUE, -1, MFT_SEPARATOR, NULL, MFS_ENABLED);
830 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_CREATELINK), MFS_ENABLED);
831
832 if (pProperties->dwCharacter & NCCF_ALLOW_REMOVAL)
833 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_DELETE, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_DELETE), MFS_ENABLED);
834 else
835 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_DELETE, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_DELETE), MFS_GRAYED);
836
837 if (pProperties->dwCharacter & NCCF_ALLOW_RENAME)
838 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_RENAME, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_RENAME), MFS_ENABLED);
839 else
840 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_RENAME, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_RENAME), MFS_GRAYED);
841
842 _InsertMenuItemW(hMenu, indexMenu++, TRUE, -1, MFT_SEPARATOR, NULL, MFS_ENABLED);
843 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_NET_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_NET_PROPERTIES), MFS_ENABLED);
844 NcFreeNetconProperties(pProperties);
845 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 9);
846 }
847
848 BOOL
849 CALLBACK
850 PropSheetExCallback(HPROPSHEETPAGE hPage, LPARAM lParam)
851 {
852 PROPSHEETHEADERW *pinfo = (PROPSHEETHEADERW *)lParam;
853
854 if (pinfo->nPages < MAX_PROPERTY_SHEET_PAGE)
855 {
856 pinfo->phpage[pinfo->nPages++] = hPage;
857 return TRUE;
858 }
859 return FALSE;
860 }
861
862 HRESULT
863 ShowNetConnectionStatus(
864 IOleCommandTarget *lpOleCmd,
865 INetConnection *pNetConnect,
866 HWND hwnd)
867 {
868 NETCON_PROPERTIES *pProperties;
869 HRESULT hr;
870
871 if (!lpOleCmd)
872 return E_FAIL;
873
874 if (pNetConnect->GetProperties(&pProperties) != S_OK)
875 return E_FAIL;
876
877 hr = lpOleCmd->Exec(&pProperties->guidId, OLECMDID_NEW, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
878
879 NcFreeNetconProperties(pProperties);
880 return hr;
881 }
882
883 HRESULT
884 ShowNetConnectionProperties(
885 INetConnection *pNetConnect,
886 HWND hwnd)
887 {
888 HRESULT hr;
889 CLSID ClassID;
890 PROPSHEETHEADERW pinfo;
891 HPROPSHEETPAGE hppages[MAX_PROPERTY_SHEET_PAGE];
892 INetConnectionPropertyUi * pNCP;
893 NETCON_PROPERTIES * pProperties;
894
895 if (pNetConnect->GetProperties(&pProperties) != S_OK)
896 return E_FAIL;
897
898 hr = pNetConnect->GetUiObjectClassId(&ClassID);
899 if (FAILED(hr))
900 {
901 NcFreeNetconProperties(pProperties);
902 return hr;
903 }
904
905 hr = CoCreateInstance(ClassID, NULL, CLSCTX_INPROC_SERVER, IID_INetConnectionPropertyUi, (LPVOID*)&pNCP);
906 if (FAILED(hr))
907 {
908 NcFreeNetconProperties(pProperties);
909 return hr;
910 }
911
912 hr = pNCP->SetConnection(pNetConnect);
913 if (SUCCEEDED(hr))
914 {
915 ZeroMemory(&pinfo, sizeof(PROPSHEETHEADERW));
916 ZeroMemory(hppages, sizeof(hppages));
917 pinfo.dwSize = sizeof(PROPSHEETHEADERW);
918 pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_PROPTITLE | PSH_NOAPPLYNOW;
919 pinfo.phpage = hppages;
920 pinfo.hwndParent = hwnd;
921
922 pinfo.pszCaption = pProperties->pszwName;
923 hr = pNCP->AddPages(hwnd, PropSheetExCallback, (LPARAM)&pinfo);
924 if (SUCCEEDED(hr))
925 {
926 if (PropertySheetW(&pinfo) < 0)
927 hr = E_FAIL;
928 }
929 }
930 pNCP->Release();
931 NcFreeNetconProperties(pProperties);
932 return hr;
933 }
934
935
936 /**************************************************************************
937 * ISF_NetConnect_IContextMenu_InvokeCommand()
938 */
939 HRESULT WINAPI CNetConUiObject::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
940 {
941 const VALUEStruct * val;
942
943 val = _ILGetValueStruct(m_pidl);
944 if (!val)
945 return E_FAIL;
946
947 if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_NET_STATUS) ||
948 lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_NET_STATUS-1)) //HACK for Windows XP
949 {
950 return ShowNetConnectionStatus(m_lpOleCmd, val->pItem, lpcmi->hwnd);
951 }
952 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_NET_PROPERTIES) ||
953 lpcmi->lpVerb == MAKEINTRESOURCEA(10099)) //HACK for Windows XP
954 {
955 /* FIXME perform version checks */
956 return ShowNetConnectionProperties(val->pItem, lpcmi->hwnd);
957 }
958
959 return S_OK;
960 }
961
962 /**************************************************************************
963 * ISF_NetConnect_IContextMenu_GetCommandString()
964 *
965 */
966 HRESULT WINAPI CNetConUiObject::GetCommandString(
967 UINT_PTR idCommand,
968 UINT uFlags,
969 UINT* lpReserved,
970 LPSTR lpszName,
971 UINT uMaxNameLen)
972 {
973 return E_FAIL;
974 }
975
976 /**************************************************************************
977 * ISF_NetConnect_IContextMenu_HandleMenuMsg()
978 */
979 HRESULT WINAPI CNetConUiObject::HandleMenuMsg(
980 UINT uMsg,
981 WPARAM wParam,
982 LPARAM lParam)
983 {
984 return E_NOTIMPL;
985 }
986
987 HRESULT WINAPI CNetConUiObject::HandleMenuMsg2(
988 UINT uMsg,
989 WPARAM wParam,
990 LPARAM lParam,
991 LRESULT *plResult)
992 {
993 return E_NOTIMPL;
994 }
995
996 HRESULT WINAPI CNetConUiObject::GetSite(REFIID riid, PVOID *ppvSite)
997 {
998 HRESULT hr;
999 IUnknown *pUnknown;
1000
1001 if (!m_pUnknown)
1002 {
1003 *ppvSite = NULL;
1004 return E_FAIL;
1005 }
1006
1007 hr = m_pUnknown->QueryInterface(riid, reinterpret_cast<PVOID*>(&pUnknown));
1008 if (SUCCEEDED(hr))
1009 {
1010 pUnknown->AddRef();
1011 *ppvSite = pUnknown;
1012 return S_OK;
1013 }
1014
1015 *ppvSite = NULL;
1016 return hr;
1017 }
1018
1019 HRESULT WINAPI CNetConUiObject::SetSite(IUnknown *pUnkSite)
1020 {
1021 if (!pUnkSite)
1022 {
1023 if (m_pUnknown)
1024 {
1025 m_pUnknown->Release();
1026 m_pUnknown = NULL;
1027 }
1028 }
1029 else
1030 {
1031 pUnkSite->AddRef();
1032 if (m_pUnknown)
1033 m_pUnknown->Release();
1034 m_pUnknown = pUnkSite;
1035 }
1036
1037 return S_OK;
1038 }
1039
1040 /************************************************************************
1041 * ISF_NetConnect_IExtractIcon_GetIconLocation
1042 */
1043 HRESULT WINAPI CNetConUiObject::GetIconLocation(
1044 UINT uFlags,
1045 LPWSTR szIconFile,
1046 UINT cchMax,
1047 int *piIndex,
1048 UINT *pwFlags)
1049 {
1050 const VALUEStruct *val;
1051 NETCON_PROPERTIES *pProperties;
1052
1053 *pwFlags = 0;
1054 if (!GetModuleFileNameW(netshell_hInstance, szIconFile, cchMax))
1055 {
1056 ERR("GetModuleFileNameW failed\n");
1057 return E_FAIL;
1058 }
1059
1060 val = _ILGetValueStruct(m_pidl);
1061 if (!val)
1062 {
1063 ERR("_ILGetValueStruct failed\n");
1064 return E_FAIL;
1065 }
1066
1067 if (val->pItem->GetProperties(&pProperties) != NOERROR)
1068 {
1069 ERR("INetConnection_GetProperties failed\n");
1070 return E_FAIL;
1071 }
1072
1073 if (pProperties->Status == NCS_CONNECTED || pProperties->Status == NCS_CONNECTING)
1074 *piIndex = -IDI_NET_IDLE;
1075 else
1076 *piIndex = -IDI_NET_OFF;
1077
1078 NcFreeNetconProperties(pProperties);
1079
1080 return NOERROR;
1081 }
1082
1083 /************************************************************************
1084 * ISF_NetConnect_IExtractIcon_Extract
1085 */
1086 HRESULT WINAPI CNetConUiObject::Extract(
1087 LPCWSTR pszFile,
1088 UINT nIconIndex,
1089 HICON *phiconLarge,
1090 HICON *phiconSmall,
1091 UINT nIconSize)
1092 {
1093 //IContextMenuImpl * This = impl_from_IExtractIcon(iface);
1094 if (nIconIndex == IDI_NET_IDLE)
1095 {
1096 *phiconLarge = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_IDLE), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
1097 *phiconSmall = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_IDLE), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1098 return NOERROR;
1099 }
1100 else if (nIconIndex == IDI_NET_OFF)
1101 {
1102 *phiconLarge = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
1103 *phiconSmall = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1104 return NOERROR;
1105 }
1106
1107 return S_FALSE;
1108 }
1109
1110 /************************************************************************
1111 * ISF_NetConnect_PersistFolder2_GetClassID
1112 */
1113 HRESULT WINAPI CNetworkConnections::GetClassID(CLSID *lpClassId)
1114 {
1115 if (!lpClassId)
1116 return E_POINTER;
1117
1118 *lpClassId = CLSID_NetworkConnections;
1119
1120 return S_OK;
1121 }
1122
1123 /************************************************************************
1124 * ISF_NetConnect_PersistFolder2_Initialize
1125 *
1126 * NOTES: it makes no sense to change the pidl
1127 */
1128 HRESULT WINAPI CNetworkConnections::Initialize(PCIDLIST_ABSOLUTE pidl)
1129 {
1130 SHFree(m_pidlRoot);
1131 m_pidlRoot = ILClone(pidl);
1132
1133 return S_OK;
1134 }
1135
1136 /**************************************************************************
1137 * ISF_NetConnect_PersistFolder2_GetCurFolder
1138 */
1139 HRESULT WINAPI CNetworkConnections::GetCurFolder(PIDLIST_ABSOLUTE *pidl)
1140 {
1141 if (!pidl)
1142 return E_POINTER;
1143
1144 *pidl = ILClone(m_pidlRoot);
1145
1146 return S_OK;
1147 }
1148
1149 /************************************************************************
1150 * ISF_NetConnect_ShellExecuteHookW_Execute
1151 */
1152 HRESULT WINAPI CNetworkConnections::Execute(LPSHELLEXECUTEINFOW pei)
1153 {
1154 const VALUEStruct *val;
1155 NETCON_PROPERTIES * pProperties;
1156
1157 val = _ILGetValueStruct(ILFindLastID((ITEMIDLIST*)pei->lpIDList));
1158 if (!val)
1159 return E_FAIL;
1160
1161 if (val->pItem->GetProperties(&pProperties) != NOERROR)
1162 return E_FAIL;
1163
1164 if (pProperties->Status == NCS_CONNECTED)
1165 {
1166 NcFreeNetconProperties(pProperties);
1167 return ShowNetConnectionStatus(m_lpOleCmd, val->pItem, pei->hwnd);
1168 }
1169
1170 NcFreeNetconProperties(pProperties);
1171
1172 return S_OK;
1173 }
1174
1175 HRESULT WINAPI CNetConUiObject::GetInfoFlags(DWORD *pdwFlags)
1176 {
1177 *pdwFlags = 0;
1178
1179 return S_OK;
1180 }
1181
1182 /************************************************************************
1183 * ISF_NetConnect_PersistFolder2_Initialize
1184 *
1185 * NOTES: it makes no sense to change the pidl
1186 */
1187 HRESULT WINAPI CNetConUiObject::GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip)
1188 {
1189 *ppwszTip = NULL;
1190 return S_OK;
1191 }
1192
1193 /**************************************************************************
1194 * ISF_NetConnect_Constructor
1195 */
1196 HRESULT WINAPI ISF_NetConnect_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv)
1197 {
1198 TRACE("ISF_NetConnect_Constructor\n");
1199
1200 if (!ppv)
1201 return E_POINTER;
1202 if (pUnkOuter)
1203 return CLASS_E_NOAGGREGATION;
1204
1205 CNetworkConnections *pnc = new CNetworkConnections;
1206 if (!pnc)
1207 return E_OUTOFMEMORY;
1208
1209 pnc->AddRef();
1210 HRESULT hr = pnc->QueryInterface(riid, ppv);
1211 pnc->Release();
1212
1213 return hr;
1214 }