xref: /reactos/dll/win32/netcfgx/netcfg_iface.c (revision 84ccccab)
1 #include "precomp.h"
2 
3 typedef struct
4 {
5     const INetCfg * lpVtbl;
6     const INetCfgLock * lpVtblLock;
7     const INetCfgPnpReconfigCallback *lpVtblPnpReconfigCallback;
8     LONG                       ref;
9     BOOL bInitialized;
10     HANDLE hMutex;
11     NetCfgComponentItem *pNet;
12     NetCfgComponentItem * pService;
13     NetCfgComponentItem * pClient;
14     NetCfgComponentItem * pProtocol;
15 } INetCfgImpl, *LPINetCfgImpl;
16 
17 static __inline LPINetCfgImpl impl_from_INetCfgLock(INetCfgLock *iface)
18 {
19     return (INetCfgImpl*)((char *)iface - FIELD_OFFSET(INetCfgImpl, lpVtblLock));
20 }
21 
22 static __inline LPINetCfgImpl impl_from_INetCfgPnpReconfigCallback(INetCfgPnpReconfigCallback *iface)
23 {
24     return (INetCfgImpl*)((char *)iface - FIELD_OFFSET(INetCfgImpl, lpVtblPnpReconfigCallback));
25 }
26 
27 
28 HRESULT
29 WINAPI
30 INetCfgLock_fnQueryInterface(
31     INetCfgLock * iface,
32     REFIID iid,
33     LPVOID * ppvObj)
34 {
35     INetCfgImpl * This = impl_from_INetCfgLock(iface);
36     return INetCfg_QueryInterface((INetCfg*)This, iid, ppvObj);
37 }
38 
39 
40 ULONG
41 WINAPI
42 INetCfgLock_fnAddRef(
43     INetCfgLock * iface)
44 {
45     INetCfgImpl * This = impl_from_INetCfgLock(iface);
46 
47     return INetCfg_AddRef((INetCfg*)This);
48 }
49 
50 ULONG
51 WINAPI
52 INetCfgLock_fnRelease(
53     INetCfgLock * iface)
54 {
55     INetCfgImpl * This = impl_from_INetCfgLock(iface);
56     return INetCfg_Release((INetCfg*)This);
57 }
58 
59 HRESULT
60 WINAPI
61 INetCfgLock_fnAcquireWriteLock(
62     INetCfgLock * iface,
63     DWORD cmsTimeout,
64     LPCWSTR pszwClientDescription,
65     LPWSTR *ppszwClientDescription)
66 {
67     DWORD dwResult;
68     HKEY hKey;
69     WCHAR szValue[100];
70     INetCfgImpl * This = impl_from_INetCfgLock(iface);
71 
72     if (This->bInitialized)
73         return NETCFG_E_ALREADY_INITIALIZED;
74 
75     dwResult = WaitForSingleObject(This->hMutex, cmsTimeout);
76     if (dwResult == WAIT_TIMEOUT)
77     {
78         if (ppszwClientDescription)
79         {
80             if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Network\\NetCfgLockHolder", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
81             {
82                 dwResult = sizeof(szValue);
83                 if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)szValue, &dwResult) == ERROR_SUCCESS)
84                 {
85                      szValue[(sizeof(szValue)/sizeof(WCHAR))-1] = L'\0';
86                      *ppszwClientDescription = CoTaskMemAlloc((wcslen(szValue)+1) * sizeof(WCHAR));
87                      if (*ppszwClientDescription)
88                          wcscpy(*ppszwClientDescription, szValue);
89                 }
90                 RegCloseKey(hKey);
91             }
92         }
93         return S_FALSE;
94     }
95     else if (dwResult == WAIT_OBJECT_0)
96     {
97         if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Network\\NetCfgLockHolder", 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
98         {
99             RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)pszwClientDescription, (wcslen(pszwClientDescription)+1) * sizeof(WCHAR));
100             RegCloseKey(hKey);
101         }
102         return S_OK;
103     }
104 
105     return E_FAIL;
106 }
107 
108 HRESULT
109 WINAPI
110 INetCfgLock_fnReleaseWriteLock(
111     INetCfgLock * iface)
112 {
113     INetCfgImpl * This = impl_from_INetCfgLock(iface);
114 
115     if (This->bInitialized)
116         return NETCFG_E_ALREADY_INITIALIZED;
117 
118 
119     if (ReleaseMutex(This->hMutex))
120         return S_OK;
121     else
122         return S_FALSE;
123 }
124 
125 HRESULT
126 WINAPI
127 INetCfgLock_fnIsWriteLocked(
128     INetCfgLock * iface,
129     LPWSTR *ppszwClientDescription)
130 {
131     HKEY hKey;
132     WCHAR szValue[100];
133     DWORD dwSize, dwType;
134     HRESULT hr;
135 
136     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Network\\NetCfgLockHolder", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
137         return S_FALSE;
138 
139     dwSize = sizeof(szValue);
140     if (RegQueryValueExW(hKey, NULL, NULL, &dwType, (LPBYTE)szValue, &dwSize) == ERROR_SUCCESS && dwType == REG_SZ)
141     {
142         hr = S_OK;
143         szValue[(sizeof(szValue)/sizeof(WCHAR))-1] = L'\0';
144         *ppszwClientDescription = CoTaskMemAlloc((wcslen(szValue)+1) * sizeof(WCHAR));
145         if (*ppszwClientDescription)
146             wcscpy(*ppszwClientDescription, szValue);
147         else
148             hr = E_OUTOFMEMORY;
149     }
150     else
151     {
152         hr = E_FAIL;
153     }
154     RegCloseKey(hKey);
155     return hr;
156 }
157 
158 static const INetCfgLockVtbl vt_NetCfgLock =
159 {
160     INetCfgLock_fnQueryInterface,
161     INetCfgLock_fnAddRef,
162     INetCfgLock_fnRelease,
163     INetCfgLock_fnAcquireWriteLock,
164     INetCfgLock_fnReleaseWriteLock,
165     INetCfgLock_fnIsWriteLocked
166 };
167 
168 /***************************************************************
169  * INetCfgPnpReconfigCallback
170  */
171 
172 HRESULT
173 WINAPI
174 INetCfgPnpReconfigCallback_fnQueryInterface(
175     INetCfgPnpReconfigCallback * iface,
176     REFIID iid,
177     LPVOID * ppvObj)
178 {
179     INetCfgImpl * This = impl_from_INetCfgPnpReconfigCallback(iface);
180     return INetCfg_QueryInterface((INetCfg*)This, iid, ppvObj);
181 }
182 
183 ULONG
184 WINAPI
185 INetCfgPnpReconfigCallback_fnAddRef(
186     INetCfgPnpReconfigCallback * iface)
187 {
188     INetCfgImpl * This = impl_from_INetCfgPnpReconfigCallback(iface);
189 
190     return INetCfg_AddRef((INetCfg*)This);
191 }
192 
193 ULONG
194 WINAPI
195 INetCfgPnpReconfigCallback_fnRelease(
196     INetCfgPnpReconfigCallback * iface)
197 {
198     INetCfgImpl * This = impl_from_INetCfgPnpReconfigCallback(iface);
199     return INetCfg_Release((INetCfg*)This);
200 }
201 
202 HRESULT
203 WINAPI
204 INetCfgPnpReconfigCallback_fnSendPnpReconfig(
205     INetCfgPnpReconfigCallback * iface,
206     NCPNP_RECONFIG_LAYER Layer,
207     LPCWSTR pszwUpper,
208     LPCWSTR pszwLower,
209     PVOID pvData,
210     DWORD dwSizeOfData)
211 {
212     /* FIXME */
213     return E_NOTIMPL;
214 }
215 
216 static const INetCfgPnpReconfigCallbackVtbl vt_NetCfgPnpReconfigCallback =
217 {
218     INetCfgPnpReconfigCallback_fnQueryInterface,
219     INetCfgPnpReconfigCallback_fnAddRef,
220     INetCfgPnpReconfigCallback_fnRelease,
221     INetCfgPnpReconfigCallback_fnSendPnpReconfig
222 };
223 
224 
225 /***************************************************************
226  * INetCfg
227  */
228 
229 HRESULT
230 EnumClientServiceProtocol(HKEY hKey, const GUID * pGuid, NetCfgComponentItem ** pHead)
231 {
232     DWORD dwIndex = 0;
233     DWORD dwSize;
234     DWORD dwType;
235     WCHAR szName[100];
236     WCHAR szText[100];
237     HKEY hSubKey, hNDIKey;
238     NetCfgComponentItem * pLast = NULL, *pCurrent;
239 
240     *pHead = NULL;
241     do
242     {
243         szText[0] = L'\0';
244 
245         dwSize = sizeof(szName)/sizeof(WCHAR);
246         if (RegEnumKeyExW(hKey, dwIndex++, szName, &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
247         {
248             pCurrent = CoTaskMemAlloc(sizeof(NetCfgComponentItem));
249             if (!pCurrent)
250                 return E_OUTOFMEMORY;
251 
252             ZeroMemory(pCurrent, sizeof(NetCfgComponentItem));
253             CopyMemory(&pCurrent->ClassGUID, pGuid, sizeof(GUID));
254 
255             if (FAILED(CLSIDFromString(szName, &pCurrent->InstanceId)))
256             {
257                 /// ReactOS tcpip guid is not yet generated
258                 //CoTaskMemFree(pCurrent);
259                 //return E_FAIL;
260             }
261             if (RegOpenKeyExW(hKey, szName, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
262             {
263                 /* retrieve Characteristics */
264                 dwSize = sizeof(DWORD);
265 
266                 RegQueryValueExW(hSubKey, L"Characteristics", NULL, &dwType, (LPBYTE)&pCurrent->dwCharacteristics, &dwSize);
267                 if (dwType != REG_DWORD)
268                     pCurrent->dwCharacteristics = 0;
269 
270                 /* retrieve ComponentId */
271                 dwSize = sizeof(szText);
272                 if (RegQueryValueExW(hSubKey, L"ComponentId", NULL, &dwType, (LPBYTE)szText, &dwSize) == ERROR_SUCCESS)
273                 {
274                     if (dwType == REG_SZ)
275                     {
276                         szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
277                         pCurrent->szId = CoTaskMemAlloc((wcslen(szText)+1)* sizeof(WCHAR));
278                         if (pCurrent->szId)
279                             wcscpy(pCurrent->szId, szText);
280                     }
281                 }
282 
283                 /* retrieve Description */
284                 dwSize = sizeof(szText);
285                 if (RegQueryValueExW(hSubKey, L"Description", NULL, &dwType, (LPBYTE)szText, &dwSize) == ERROR_SUCCESS)
286                 {
287                     if (dwType == REG_SZ)
288                     {
289                         szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
290                         pCurrent->szDisplayName = CoTaskMemAlloc((wcslen(szText)+1)* sizeof(WCHAR));
291                         if (pCurrent->szDisplayName)
292                             wcscpy(pCurrent->szDisplayName, szText);
293                     }
294                 }
295 
296                 if (RegOpenKeyExW(hKey, L"NDI", 0, KEY_READ, &hNDIKey) == ERROR_SUCCESS)
297                 {
298                     /* retrieve HelpText */
299                     dwSize = sizeof(szText);
300                     if (RegQueryValueExW(hNDIKey, L"HelpText", NULL, &dwType, (LPBYTE)szText, &dwSize) == ERROR_SUCCESS)
301                     {
302                         if (dwType == REG_SZ)
303                         {
304                             szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
305                             pCurrent->szHelpText = CoTaskMemAlloc((wcslen(szText)+1)* sizeof(WCHAR));
306                             if (pCurrent->szHelpText)
307                                 wcscpy(pCurrent->szHelpText, szText);
308                         }
309                     }
310 
311                     /* retrieve Service */
312                     dwSize = sizeof(szText);
313                     if (RegQueryValueExW(hNDIKey, L"Service", NULL, &dwType, (LPBYTE)szText, &dwSize) == ERROR_SUCCESS)
314                     {
315                         if (dwType == REG_SZ)
316                         {
317                             szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
318                             pCurrent->szBindName = CoTaskMemAlloc((wcslen(szText)+1)* sizeof(WCHAR));
319                             if (pCurrent->szBindName)
320                                 wcscpy(pCurrent->szBindName, szText);
321                         }
322                     }
323                     RegCloseKey(hNDIKey);
324                 }
325                 RegCloseKey(hSubKey);
326 
327                 if (!pLast)
328                     *pHead = pCurrent;
329                 else
330                     pLast->pNext = pCurrent;
331 
332                 pLast = pCurrent;
333             }
334         }
335         else
336            break;
337 
338     }while(TRUE);
339     return S_OK;
340 }
341 
342 
343 
344 HRESULT
345 EnumerateNetworkComponent(
346     const GUID *pGuid, NetCfgComponentItem ** pHead)
347 {
348     HKEY hKey;
349     LPOLESTR pszGuid;
350     HRESULT hr;
351     WCHAR szName[150];
352 
353     hr = StringFromCLSID(pGuid, &pszGuid);
354     if (SUCCEEDED(hr))
355     {
356         swprintf(szName, L"SYSTEM\\CurrentControlSet\\Control\\Network\\%s", pszGuid);
357         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
358         {
359             hr = EnumClientServiceProtocol(hKey, pGuid, pHead);
360             RegCloseKey(hKey);
361         }
362         CoTaskMemFree(pszGuid);
363     }
364     return hr;
365 }
366 
367 HRESULT
368 EnumerateNetworkAdapter(NetCfgComponentItem ** pHead)
369 {
370     DWORD dwSize, dwIndex;
371     HDEVINFO hInfo;
372     SP_DEVINFO_DATA DevInfo;
373     HKEY hKey;
374     WCHAR szNetCfg[50];
375     WCHAR szAdapterNetCfg[50];
376     WCHAR szDetail[200] = L"SYSTEM\\CurrentControlSet\\Control\\Class\\";
377     WCHAR szName[130] = L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
378     NetCfgComponentItem * pLast = NULL, *pCurrent;
379 
380     hInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT );
381     if (!hInfo)
382     {
383         return E_FAIL;
384     }
385 
386     dwIndex = 0;
387     do
388     {
389         ZeroMemory(&DevInfo, sizeof(SP_DEVINFO_DATA));
390         DevInfo.cbSize = sizeof(DevInfo);
391 
392         /* get device info */
393         if (!SetupDiEnumDeviceInfo(hInfo, dwIndex++, &DevInfo))
394             break;
395 
396         /* get device software registry path */
397         if (!SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DRIVER, NULL, (LPBYTE)&szDetail[39], sizeof(szDetail)/sizeof(WCHAR) - 40, &dwSize))
398             break;
399 
400         /* open device registry key */
401         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szDetail, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
402             break;
403 
404         /* query NetCfgInstanceId for current device */
405         dwSize = sizeof(szNetCfg);
406         if (RegQueryValueExW(hKey, L"NetCfgInstanceId", NULL, NULL, (LPBYTE)szNetCfg, &dwSize) != ERROR_SUCCESS)
407         {
408             RegCloseKey(hKey);
409             break;
410         }
411 
412         /* allocate new INetConnectionItem */
413         pCurrent = CoTaskMemAlloc(sizeof(NetCfgComponentItem));
414         if (!pCurrent)
415             break;
416 
417         ZeroMemory(pCurrent, sizeof(NetCfgComponentItem));
418         CopyMemory(&pCurrent->ClassGUID, &GUID_DEVCLASS_NET, sizeof(GUID));
419         CLSIDFromString(szNetCfg, &pCurrent->InstanceId); //FIXME
420 
421         /* set bind name */
422         pCurrent->szBindName = CoTaskMemAlloc((wcslen(szNetCfg)+1) *sizeof(WCHAR));
423         if (pCurrent->szBindName)
424             wcscpy(pCurrent->szBindName, szNetCfg);
425 
426         /* retrieve ComponentId */
427         dwSize = sizeof(szAdapterNetCfg);
428         if (RegQueryValueExW(hKey, L"ComponentId", NULL, NULL, (LPBYTE)szAdapterNetCfg, &dwSize) == ERROR_SUCCESS)
429         {
430             pCurrent->szId = CoTaskMemAlloc((wcslen(szAdapterNetCfg)+1) * sizeof(WCHAR));
431             if (pCurrent->szId)
432                 wcscpy(pCurrent->szId, szAdapterNetCfg);
433         }
434         /* set INetCfgComponent::GetDisplayName */
435         dwSize = sizeof(szAdapterNetCfg);
436         if (RegQueryValueExW(hKey, L"DriverDesc", NULL, NULL, (LPBYTE)szAdapterNetCfg, &dwSize) == ERROR_SUCCESS)
437         {
438             pCurrent->szDisplayName = CoTaskMemAlloc((wcslen(szAdapterNetCfg)+1) * sizeof(WCHAR));
439             if (pCurrent->szDisplayName)
440                 wcscpy(pCurrent->szDisplayName, szAdapterNetCfg);
441         }
442 
443         RegCloseKey(hKey);
444         /*  open network connections details */
445         wcscpy(&szName[80], szNetCfg);
446         wcscpy(&szName[118], L"\\Connection");
447 
448         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
449         {
450             /* retrieve pnp instance id */
451             dwSize = sizeof(szAdapterNetCfg);
452             if (RegQueryValueExW(hKey, L"PnpInstanceID", NULL, NULL, (LPBYTE)szAdapterNetCfg, &dwSize) == ERROR_SUCCESS)
453             {
454                 pCurrent->szNodeId = CoTaskMemAlloc((wcslen(szAdapterNetCfg)+1) * sizeof(WCHAR));
455                 if (pCurrent->szNodeId)
456                     wcscpy(pCurrent->szNodeId, szAdapterNetCfg);
457             }
458             RegCloseKey(hKey);
459         }
460 
461         if (SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DEVICEDESC, NULL, (PBYTE)szNetCfg, sizeof(szNetCfg)/sizeof(WCHAR), &dwSize))
462         {
463             szNetCfg[(sizeof(szNetCfg)/sizeof(WCHAR))-1] = L'\0';
464             pCurrent->szDisplayName = CoTaskMemAlloc((wcslen(szNetCfg)+1) * sizeof(WCHAR));
465             if (pCurrent->szDisplayName)
466                 wcscpy(pCurrent->szDisplayName, szNetCfg);
467         }
468 
469         if (pLast)
470             pLast->pNext = pCurrent;
471         else
472             *pHead = pCurrent;
473 
474         pLast = pCurrent;
475 
476     }while(TRUE);
477 
478     SetupDiDestroyDeviceInfoList(hInfo);
479     return NOERROR;
480 }
481 
482 
483 HRESULT
484 FindNetworkComponent(
485     NetCfgComponentItem * pHead,
486     LPCWSTR pszwComponentId,
487     INetCfgComponent **pComponent,
488     INetCfg * iface)
489 {
490     while(pHead)
491     {
492         if (!_wcsicmp(pHead->szId, pszwComponentId))
493         {
494             return INetCfgComponent_Constructor(NULL, &IID_INetCfgComponent, (LPVOID*)pComponent, pHead, iface);
495         }
496         pHead = pHead->pNext;
497     }
498     return S_FALSE;
499 }
500 
501 
502 
503 HRESULT
504 WINAPI
505 INetCfg_fnQueryInterface(
506     INetCfg * iface,
507     REFIID iid,
508     LPVOID * ppvObj)
509 {
510     INetCfgImpl * This = (INetCfgImpl*)iface;
511     *ppvObj = NULL;
512 
513     if (IsEqualIID (iid, &IID_IUnknown) ||
514         IsEqualIID (iid, &IID_INetCfg))
515     {
516         *ppvObj = This;
517         INetCfg_AddRef(iface);
518         return S_OK;
519     }
520     else if (IsEqualIID (iid, &IID_INetCfgLock))
521     {
522         if (This->bInitialized)
523             return NETCFG_E_ALREADY_INITIALIZED;
524 
525         *ppvObj = (LPVOID)&This->lpVtblLock;
526         This->hMutex = CreateMutexW(NULL, FALSE, L"NetCfgLock");
527 
528         INetCfgLock_AddRef(iface);
529         return S_OK;
530     }
531     else if (IsEqualIID (iid, &IID_INetCfgPnpReconfigCallback))
532     {
533         if (This->bInitialized)
534             return NETCFG_E_ALREADY_INITIALIZED;
535 
536         *ppvObj = (LPVOID)&This->lpVtblPnpReconfigCallback;
537         INetCfgPnpReconfigCallback_AddRef(iface);
538         return S_OK;
539     }
540 
541     return E_NOINTERFACE;
542 }
543 
544 ULONG
545 WINAPI
546 INetCfg_fnAddRef(
547     INetCfg * iface)
548 {
549     INetCfgImpl * This = (INetCfgImpl*)iface;
550     ULONG refCount = InterlockedIncrement(&This->ref);
551 
552     return refCount;
553 }
554 
555 ULONG
556 WINAPI
557 INetCfg_fnRelease(
558     INetCfg * iface)
559 {
560     INetCfgImpl * This = (INetCfgImpl*)iface;
561     ULONG refCount = InterlockedDecrement(&This->ref);
562 
563     if (!refCount)
564     {
565         CoTaskMemFree (This);
566     }
567     return refCount;
568 }
569 
570 HRESULT
571 WINAPI
572 INetCfg_fnInitialize(
573     INetCfg * iface,
574     PVOID pReserved)
575 {
576     HRESULT hr;
577     INetCfgImpl *This = (INetCfgImpl *)iface;
578 
579     if (This->bInitialized)
580         return NETCFG_E_ALREADY_INITIALIZED;
581 
582     hr = EnumerateNetworkAdapter(&This->pNet);
583     if (FAILED(hr))
584         return hr;
585 
586 
587     hr = EnumerateNetworkComponent(&GUID_DEVCLASS_NETCLIENT, &This->pClient);
588     if (FAILED(hr))
589         return hr;
590 
591     hr = EnumerateNetworkComponent(&GUID_DEVCLASS_NETSERVICE, &This->pService);
592     if (FAILED(hr))
593         return hr;
594 
595 
596     hr = EnumerateNetworkComponent(&GUID_DEVCLASS_NETTRANS, &This->pProtocol);
597     if (FAILED(hr))
598         return hr;
599 
600     This->bInitialized = TRUE;
601     return S_OK;
602 }
603 
604 VOID
605 ApplyOrCancelChanges(
606     NetCfgComponentItem *pHead,
607     const CLSID * lpClassGUID,
608     BOOL bApply)
609 {
610     HKEY hKey;
611     WCHAR szName[200];
612     LPOLESTR pszGuid;
613 
614     while(pHead)
615     {
616         if (pHead->bChanged)
617         {
618             if (IsEqualGUID(lpClassGUID, &GUID_DEVCLASS_NET))
619             {
620                 if (bApply)
621                 {
622                     if (StringFromCLSID(&pHead->InstanceId, &pszGuid) == NOERROR)
623                     {
624                         swprintf(szName, L"SYSTEM\\CurrentControlSet\\Control\\Network\\%s", pszGuid);
625                         CoTaskMemFree(pszGuid);
626 
627                         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
628                         {
629                             RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)pHead->szDisplayName, (wcslen(pHead->szDisplayName)+1) * sizeof(WCHAR));
630                             RegCloseKey(hKey);
631                         }
632                     }
633                 }
634             }
635             else if (pHead->pNCCC)
636             {
637                 if (bApply)
638                 {
639                     INetCfgComponentControl_ApplyRegistryChanges(pHead->pNCCC);
640                     //FIXME
641                     // implement INetCfgPnpReconfigCallback and pass it to
642                     //INetCfgComponentControl_ApplyPnpChanges(pHead->pNCCC, NULL);
643                 }
644                 else
645                 {
646                     INetCfgComponentControl_CancelChanges(pHead->pNCCC);
647                 }
648             }
649         }
650         pHead = pHead->pNext;
651     }
652 }
653 
654 HRESULT
655 WINAPI
656 INetCfg_fnUninitialize(
657     INetCfg * iface)
658 {
659     INetCfgImpl *This = (INetCfgImpl *)iface;
660 
661     if (!This->bInitialized)
662         return NETCFG_E_NOT_INITIALIZED;
663 
664     return E_FAIL;
665 }
666 
667 
668 HRESULT
669 WINAPI
670 INetCfg_fnApply(
671     INetCfg * iface)
672 {
673     INetCfgImpl *This = (INetCfgImpl *)iface;
674 
675     if (!This->bInitialized)
676         return NETCFG_E_NOT_INITIALIZED;
677 
678     ApplyOrCancelChanges(This->pNet, &GUID_DEVCLASS_NET, TRUE);
679     ApplyOrCancelChanges(This->pClient, &GUID_DEVCLASS_NETCLIENT, TRUE);
680     ApplyOrCancelChanges(This->pService, &GUID_DEVCLASS_NETSERVICE, TRUE);
681     ApplyOrCancelChanges(This->pProtocol, &GUID_DEVCLASS_NETTRANS, TRUE);
682 
683     return S_OK;
684 }
685 
686 HRESULT
687 WINAPI
688 INetCfg_fnCancel(
689     INetCfg * iface)
690 {
691     INetCfgImpl *This = (INetCfgImpl *)iface;
692 
693     if (!This->bInitialized)
694         return NETCFG_E_NOT_INITIALIZED;
695 
696     ApplyOrCancelChanges(This->pClient, &GUID_DEVCLASS_NETCLIENT, FALSE);
697     ApplyOrCancelChanges(This->pService, &GUID_DEVCLASS_NETSERVICE, FALSE);
698     ApplyOrCancelChanges(This->pProtocol, &GUID_DEVCLASS_NETTRANS, FALSE);
699 
700     return S_OK;
701 }
702 
703 HRESULT
704 WINAPI
705 INetCfg_fnEnumComponents(
706     INetCfg * iface,
707     const GUID *pguidClass,
708     IEnumNetCfgComponent **ppenumComponent)
709 {
710     INetCfgImpl *This = (INetCfgImpl *)iface;
711 
712     if (!This->bInitialized)
713         return NETCFG_E_NOT_INITIALIZED;
714 
715     if (IsEqualGUID(&GUID_DEVCLASS_NET, pguidClass))
716         return IEnumNetCfgComponent_Constructor (NULL, &IID_IEnumNetCfgComponent, (LPVOID*)ppenumComponent, This->pNet, iface);
717     else if (IsEqualGUID(&GUID_DEVCLASS_NETCLIENT, pguidClass))
718         return IEnumNetCfgComponent_Constructor (NULL, &IID_IEnumNetCfgComponent, (LPVOID*)ppenumComponent, This->pClient, iface);
719     else if (IsEqualGUID(&GUID_DEVCLASS_NETSERVICE, pguidClass))
720         return IEnumNetCfgComponent_Constructor (NULL, &IID_IEnumNetCfgComponent, (LPVOID*)ppenumComponent, This->pService, iface);
721     else if (IsEqualGUID(&GUID_DEVCLASS_NETTRANS, pguidClass))
722         return IEnumNetCfgComponent_Constructor (NULL, &IID_IEnumNetCfgComponent, (LPVOID*)ppenumComponent, This->pProtocol, iface);
723     else
724        return E_NOINTERFACE;
725 }
726 
727 
728 HRESULT
729 WINAPI
730 INetCfg_fnFindComponent(
731     INetCfg * iface,
732     LPCWSTR pszwComponentId,
733     INetCfgComponent **pComponent)
734 {
735     HRESULT hr;
736     INetCfgImpl *This = (INetCfgImpl *)iface;
737 
738     if (!This->bInitialized)
739         return NETCFG_E_NOT_INITIALIZED;
740 
741     hr = FindNetworkComponent(This->pClient, pszwComponentId, pComponent, iface);
742     if (hr == S_OK)
743         return hr;
744 
745     hr = FindNetworkComponent(This->pService, pszwComponentId, pComponent, iface);
746     if (hr == S_OK)
747         return hr;
748 
749     hr = FindNetworkComponent(This->pProtocol, pszwComponentId, pComponent, iface);
750     if (hr == S_OK)
751         return hr;
752 
753     return S_FALSE;
754 }
755 
756 HRESULT
757 WINAPI
758 INetCfg_fnQueryNetCfgClass(
759     INetCfg * iface,
760     const GUID *pguidClass,
761     REFIID riid,
762     void **ppvObject)
763 {
764     return E_FAIL;
765 }
766 
767 static const INetCfgVtbl vt_NetCfg =
768 {
769     INetCfg_fnQueryInterface,
770     INetCfg_fnAddRef,
771     INetCfg_fnRelease,
772     INetCfg_fnInitialize,
773     INetCfg_fnUninitialize,
774     INetCfg_fnApply,
775     INetCfg_fnCancel,
776     INetCfg_fnEnumComponents,
777     INetCfg_fnFindComponent,
778     INetCfg_fnQueryNetCfgClass,
779 };
780 
781 HRESULT WINAPI INetCfg_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
782 {
783     INetCfgImpl *This;
784 
785     if (!ppv)
786         return E_POINTER;
787 
788     This = (INetCfgImpl *) CoTaskMemAlloc(sizeof (INetCfgImpl));
789     if (!This)
790         return E_OUTOFMEMORY;
791 
792     This->ref = 1;
793     This->lpVtbl = (const INetCfg*)&vt_NetCfg;
794     This->lpVtblLock = (const INetCfgLock*)&vt_NetCfgLock;
795     This->lpVtblPnpReconfigCallback = (const INetCfgPnpReconfigCallback*)&vt_NetCfgPnpReconfigCallback;
796     This->hMutex = NULL;
797     This->bInitialized = FALSE;
798     This->pNet = NULL;
799     This->pClient = NULL;
800     This->pService = NULL;
801     This->pProtocol = NULL;
802 
803     if (!SUCCEEDED (INetCfg_QueryInterface ((INetCfg*)This, riid, ppv)))
804     {
805         INetCfg_Release((INetCfg*)This);
806         return E_NOINTERFACE;
807     }
808 
809     INetCfg_Release((INetCfg*)This);
810     return S_OK;
811 }
812