Bring back ext2 code from branch
[reactos.git] / reactos / dll / cpl / ncpa / ncpa.c
1 /*
2 * Copyright 2004 Gero Kuehn
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 /*
19 * PROJECT: ReactOS Network Control Panel
20 * FILE: lib/cpl/system/ncpa.c
21 * PURPOSE: ReactOS Network Control Panel
22 * PROGRAMMER: Gero Kuehn (reactos.filter@gkware.com)
23 * UPDATE HISTORY:
24 * 07-18-2004 Created
25 */
26
27 /*
28 * Read this first !
29 *
30 * This file contains a first attempt for reactos network configuration
31 *
32 * - It is not complete.
33 * - It does not work the way it works on Windows.
34 *
35 * A lot of code that can be found here now, will probably be relocated into the OS core or some
36 * protocol Co-Installers or Notify Objects later when all the required COM
37 * and "netcfgx.dll" infrastructure (esp. headers and Interfaces) get implemented step by step.
38 *
39 * This code is only a first approach to provide a usable network configuration dialogs for
40 * the new network support in Reactos.
41 *
42 * If you intend to extend this code by more, please contact me to avoid duplicate work.
43 * There are already resources and code for TCP/IP configuration that are not
44 * mature enough for committing them to CVS yet.
45 */
46
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <stdarg.h>
50 #include <tchar.h>
51 #include <windows.h>
52 #include <iphlpapi.h>
53 #include <commctrl.h>
54 #include <cpl.h>
55
56 #include <wine/debug.h>
57 WINE_DEFAULT_DEBUG_CHANNEL(ncpa);
58 #ifndef _UNICODE
59 #define debugstr_aw debugstr_a
60 #else
61 #define debugstr_aw debugstr_w
62 #endif
63
64 #include "resource.h"
65 #include "ncpa.h"
66
67 #define NCF_VIRTUAL 0x1
68 #define NCF_SOFTWARE_ENUMERATED 0x2
69 #define NCF_PHYSICAL 0x4
70 #define NCF_HIDDEN 0x8
71 #define NCF_NO_SERVICE 0x10
72 #define NCF_NOT_USER_REMOVABLE 0x20
73 #define NCF_MULTIPORT_INSTANCED_ADAPTER 0x40
74 #define NCF_HAS_UI 0x80
75 #define NCF_FILTER 0x400
76 #define NCF_NDIS_PROTOCOL 0x4000
77
78 typedef void (ENUMREGKEYCALLBACK)(void *pCookie,HKEY hBaseKey,TCHAR *pszSubKey);
79
80 static LONG CALLBACK DisplayApplet(VOID);
81 static INT_PTR CALLBACK NetworkPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
82 void DisplayTCPIPProperties(HWND hParent,IP_ADAPTER_INFO *pInfo);
83
84 HINSTANCE hApplet = 0;
85
86 /* Applets */
87 static APPLET Applets[] =
88 {
89 {IDI_CPLSYSTEM, IDS_CPLSYSTEMNAME, IDS_CPLSYSTEMDESCRIPTION, DisplayApplet}
90 };
91
92
93 /* useful utilities */
94 static VOID
95 EnumRegKeys(ENUMREGKEYCALLBACK *pCallback,PVOID pCookie,HKEY hBaseKey,TCHAR *tpszRegPath)
96 {
97 HKEY hKey;
98 INT i;
99 LONG ret;
100 TCHAR tpszName[MAX_PATH];
101 DWORD dwNameLen = sizeof(tpszName);
102
103 if(RegOpenKeyEx(hBaseKey,tpszRegPath,0,KEY_ENUMERATE_SUB_KEYS,&hKey)!=ERROR_SUCCESS)
104 {
105 WARN("EnumRegKeys failed (key not found): %S\n", tpszRegPath);
106 return;
107 }
108
109 for(i=0;;i++)
110 {
111 TCHAR pszNewPath[MAX_PATH];
112 ret = RegEnumKeyEx(hKey,i,tpszName,&dwNameLen,NULL,NULL,NULL,NULL);
113 if(ret != ERROR_SUCCESS)
114 {
115 WARN("EnumRegKeys: RegEnumKeyEx failed for %S (rc 0x%lx)\n", tpszName, ret);
116 break;
117 }
118
119 _stprintf(pszNewPath,_T("%s\\%s"),tpszRegPath,tpszName);
120 TRACE("EnumRegKeys: Calling user supplied enum function\n");
121 pCallback(pCookie,hBaseKey,pszNewPath);
122
123 dwNameLen = sizeof(tpszName);
124 }
125
126 RegCloseKey(hKey);
127 }
128
129 void
130 InitPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DLGPROC DlgProc,LPARAM lParam)
131 {
132 ZeroMemory(psp, sizeof(PROPSHEETPAGE));
133 psp->dwSize = sizeof(PROPSHEETPAGE);
134 psp->dwFlags = PSP_DEFAULT;
135 psp->hInstance = hApplet;
136 psp->pszTemplate = MAKEINTRESOURCE(idDlg);
137 psp->pfnDlgProc = DlgProc;
138 psp->lParam = lParam;
139 }
140
141
142
143 static BOOL
144 FindNICClassKeyForCfgInstance(TCHAR *tpszCfgInst,TCHAR *tpszSubKeyOut)
145 {
146 int i;
147 TCHAR tpszSubKey[MAX_PATH];
148 TCHAR tpszCfgInst2[MAX_PATH];
149 HKEY hKey;
150 DWORD dwType,dwSize;
151
152 for (i = 0; i < 100; i++)
153 {
154 _stprintf(tpszSubKey,_T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%04d"),i);
155 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,tpszSubKey,0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
156 continue;
157 dwType = REG_SZ;
158 dwSize = sizeof(tpszCfgInst2);
159 if(RegQueryValueEx(hKey,_T("NetCfgInstanceId"),NULL,&dwType,(BYTE*)tpszCfgInst2,&dwSize)!=ERROR_SUCCESS) {
160 RegCloseKey(hKey);
161 continue;
162 }
163 RegCloseKey(hKey);
164 if(_tcscmp(tpszCfgInst,tpszCfgInst2)==0) {
165 _tcscpy(tpszSubKeyOut,tpszSubKey);
166 return TRUE;
167 }
168 }
169 return FALSE;
170 }
171
172
173 static void
174 NICPropertyProtocolCallback(void *pCookie,HKEY hBaseKey,TCHAR *tpszSubKey)
175 {
176 HWND hwndDlg;
177 DWORD dwCharacteristics;
178 HKEY hKey,hNDIKey;
179 DWORD dwType,dwSize;
180 TCHAR tpszDescription[MAX_PATH];
181 TCHAR tpszNotifyObjectCLSID[MAX_PATH];
182 TCHAR *tpszSubKeyCopy;
183 int nIndex;
184
185 UNREFERENCED_PARAMETER(hBaseKey);
186
187 // CLSID CLSID_NotifObj;
188 // IUnknown *pUnk = NULL;
189 // INetCfgComponentControl *pNetCfg;
190 // INetCfgComponentPropertyUi *pNetCfgPropUI;
191 hwndDlg = (HWND)pCookie;
192
193 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,tpszSubKey,0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
194 return;
195
196 dwType = REG_DWORD;
197 dwSize = sizeof(dwCharacteristics);
198 if(RegQueryValueEx(hKey,_T("Characteristics"),NULL,&dwType,(BYTE*)&dwCharacteristics,&dwSize)!= ERROR_SUCCESS)
199 return;
200
201 if(dwCharacteristics & NCF_HIDDEN)
202 {
203 RegCloseKey(hKey);
204 return;
205 }
206
207 dwType = REG_SZ;
208 dwSize = sizeof(tpszDescription);
209 if(RegQueryValueEx(hKey,_T("Description"),NULL,&dwType,(BYTE*)tpszDescription,&dwSize)!= ERROR_SUCCESS)
210 return;
211
212 RegOpenKeyEx(hKey,_T("Ndi"),0,KEY_QUERY_VALUE,&hNDIKey);
213 dwType = REG_SZ;
214 dwSize = sizeof(tpszNotifyObjectCLSID);
215 if(RegQueryValueEx(hNDIKey,_T("ClsId"),NULL,&dwType,(BYTE*)tpszNotifyObjectCLSID,&dwSize)!= ERROR_SUCCESS)
216 ;//return;
217
218 RegCloseKey(hNDIKey);
219
220 //
221 // This code works on Windows... but not on Reactos
222 //
223
224 // CLSIDFromString(tpszNotifyObjectCLSID,&CLSID_NotifObj);
225 // CoCreateInstance(&CLSID_NotifObj,NULL,CLSCTX_INPROC_SERVER,&IID_IUnknown,(void**)&pUnk);
226 // pUnk->lpVtbl->QueryInterface(pUnk,&IID_INetCfgComponentControl,(void**)&pNetCfg);
227 // pUnk->lpVtbl->QueryInterface(pUnk,&IID_INetCfgComponentPropertyUi,(void**)&pNetCfgPropUI);
228 {
229 /*
230 HRESULT hr;
231 hr = pNetCfg->lpVtbl->Initialize(pNetCfg,&NetCfgComponent,&NetCfg,FALSE);
232 hr = pNetCfgPropUI->lpVtbl->QueryPropertyUi(pNetCfgPropUI,(INetCfg*)&NetCfg);
233 hr = pNetCfgPropUI->lpVtbl->SetContext(pNetCfgPropUI,(INetCfg*)&NetCfgComponent);
234 DWORD dwNumPages = 10;
235 HPROPSHEETPAGE *bOut = NULL;
236 UINT nPages;
237 hr = pNetCfgPropUI->MergePropPages(&dwNumPages,(BYTE**)&bOut,&nPages,GetDesktopWindow(),NULL);
238 */
239 }
240
241 RegCloseKey(hKey);
242 nIndex = (int) SendDlgItemMessage(hwndDlg,IDC_COMPONENTSLIST,LB_ADDSTRING,0,(LPARAM)tpszDescription);
243 tpszSubKeyCopy = _tcsdup(tpszSubKey);
244 SendDlgItemMessage(hwndDlg,IDC_COMPONENTSLIST,LB_SETITEMDATA,nIndex,(LPARAM)tpszSubKeyCopy);
245 }
246
247
248
249 static INT_PTR CALLBACK
250 NICPropertyPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
251 {
252 PGLOBAL_NCPA_DATA pGlobalData = (PGLOBAL_NCPA_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
253
254 switch(uMsg)
255 {
256 case WM_INITDIALOG:
257 {
258 DWORD dwType,dwSize;
259 TCHAR tpszSubKey[MAX_PATH];
260 TCHAR tpszDisplayName[MAX_PATH];
261 HKEY hKey;
262
263 pGlobalData = (PGLOBAL_NCPA_DATA)((LPPROPSHEETPAGE)lParam)->lParam;
264 if (pGlobalData == NULL)
265 return FALSE;
266
267 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
268
269 if(!FindNICClassKeyForCfgInstance(pGlobalData->CurrentAdapterName, tpszSubKey))
270 {
271 WARN("NIC Entry not found for '%s'\n", debugstr_w(pGlobalData->CurrentAdapterName));
272 MessageBox(hwndDlg,_T("NIC Entry not found"),_T("Registry error"),MB_ICONSTOP);
273 MessageBox(hwndDlg,pGlobalData->CurrentAdapterName,tpszSubKey,MB_ICONSTOP);
274 }
275
276 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,tpszSubKey,0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
277 return 0;
278 dwType = REG_SZ;
279 dwSize = sizeof(tpszDisplayName);
280 if(RegQueryValueEx(hKey,_T("DriverDesc"),NULL,&dwType,(BYTE*)tpszDisplayName,&dwSize)!= ERROR_SUCCESS)
281 return 0;
282 RegCloseKey(hKey);
283
284 SetDlgItemText(hwndDlg,IDC_NETCARDNAME,tpszDisplayName);
285 EnableWindow(GetDlgItem(hwndDlg,IDC_CONFIGURE),FALSE);
286
287 //SetDlgItemTextA(hwndDlg,IDC_NETCARDNAME,Info[pPage->lParam].Description);
288 EnumRegKeys(NICPropertyProtocolCallback,hwndDlg,HKEY_LOCAL_MACHINE,_T("System\\CurrentControlSet\\Control\\Network\\{4D36E975-E325-11CE-BFC1-08002BE10318}"));
289
290 SendDlgItemMessage(hwndDlg, IDC_COMPONENTSLIST, LB_SETCURSEL, 0, 0);
291 SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_COMPONENTSLIST, LBN_SELCHANGE), 0);
292 }
293 break;
294 case WM_COMMAND:
295 switch(LOWORD(wParam))
296 {
297 case IDC_COMPONENTSLIST:
298 if(HIWORD(wParam)==LBN_SELCHANGE)
299 {
300 TCHAR *tpszSubKey;
301 TCHAR tpszHelpKey[MAX_PATH];
302 TCHAR tpszHelpText[MAX_PATH];
303 HKEY hNDIKey;
304 DWORD dwType,dwSize;
305 HWND hListBox = GetDlgItem(hwndDlg,IDC_COMPONENTSLIST);
306 tpszSubKey = (TCHAR*)SendMessage(hListBox,LB_GETITEMDATA,SendMessage(hListBox,LB_GETCURSEL,0,0),0);
307 if(!tpszSubKey)
308 break;
309 _stprintf(tpszHelpKey,_T("%s\\Ndi"),tpszSubKey);
310
311 RegOpenKeyEx(HKEY_LOCAL_MACHINE,tpszHelpKey,0,KEY_QUERY_VALUE,&hNDIKey);
312 dwType = REG_SZ;
313 dwSize = sizeof(tpszHelpText);
314 if(RegQueryValueEx(hNDIKey,_T("HelpText"),NULL,&dwType,(BYTE*)tpszHelpText,&dwSize)!= ERROR_SUCCESS)
315 ;//return;
316 RegCloseKey(hNDIKey);
317
318 SetDlgItemText(hwndDlg,IDC_DESCRIPTION,tpszHelpText);
319 }
320 if(HIWORD(wParam)!=LBN_DBLCLK)
321 break;
322 // drop though
323 case IDC_PROPERTIES:
324 {
325 if(pGlobalData->pCurrentAdapterInfo)
326 {
327 DisplayTCPIPProperties(hwndDlg, pGlobalData->pCurrentAdapterInfo);
328 }
329 else
330 {
331 FIXME("If you see this, then the IPHLPAPI.DLL probably needs more work because GetAdaptersInfo did not return the expected data.\n");
332 MessageBox(NULL,_T("If you see this, then the IPHLPAPI.DLL probably needs more work because GetAdaptersInfo did not return the expected data."),_T("Error"),MB_ICONSTOP);
333 }
334 }
335 break;
336 }
337 break;
338 }
339 return FALSE;
340 }
341
342
343 static void
344 DisplayNICProperties(HWND hParent, GLOBAL_NCPA_DATA* pGlobalData)
345 {
346 PROPSHEETPAGE psp[1];
347 PROPSHEETHEADER psh;
348 TCHAR tpszSubKey[MAX_PATH];
349 HKEY hKey;
350 DWORD dwType = REG_SZ;
351 TCHAR tpszName[MAX_PATH];
352 DWORD dwSize = sizeof(tpszName);
353 TCHAR tpszCfgInstanceID[MAX_ADAPTER_NAME_LENGTH];
354
355 #ifndef _UNICODE
356 WideCharToMultiByte(CP_UTF8, 0, pGlobalData->CurrentAdapterName, -1, tpszCfgInstanceID, MAX_ADAPTER_NAME_LENGTH, 0, 0);
357 #else
358 wcscpy(tpszCfgInstanceID, pGlobalData->CurrentAdapterName);
359 #endif
360
361 // Get the "Name" for this Connection
362 _stprintf(tpszSubKey,_T("System\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection"),tpszCfgInstanceID);
363 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,tpszSubKey,0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
364 return;
365 if(RegQueryValueEx(hKey,_T("Name"),NULL,&dwType,(BYTE*)tpszName,&dwSize)!=ERROR_SUCCESS)
366 _stprintf(tpszName,_T("[ERROR]"));
367 else
368 _tcscat(tpszName,_T(" Properties"));
369 RegCloseKey(hKey);
370
371 ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
372 psh.dwSize = sizeof(PROPSHEETHEADER);
373 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
374 psh.hwndParent = hParent;
375 psh.hInstance = hApplet;
376 psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCE(IDI_CPLSYSTEM));
377 psh.pszCaption = tpszName;
378 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
379 psh.nStartPage = 0;
380 psh.ppsp = psp;
381 psh.pfnCallback = NULL;
382
383 InitPropSheetPage(&psp[0], IDD_NETPROPERTIES, NICPropertyPageProc, (LPARAM)pGlobalData);
384 PropertySheet(&psh);
385 return;
386 }
387
388 void RefreshNICInfo(HWND hwndDlg, PGLOBAL_NCPA_DATA pGlobalData)
389 {
390 ULONG BufferSize;
391 DWORD ErrRet = 0;
392
393 if (pGlobalData->pFirstAdapterInfo)
394 HeapFree(GetProcessHeap(), 0, pGlobalData->pFirstAdapterInfo);
395
396 BufferSize = sizeof(IP_ADAPTER_INFO);
397 pGlobalData->pFirstAdapterInfo = (PIP_ADAPTER_INFO) HeapAlloc(GetProcessHeap(), 0, BufferSize);
398
399 if (GetAdaptersInfo(pGlobalData->pFirstAdapterInfo, &BufferSize) == ERROR_BUFFER_OVERFLOW)
400 {
401 HeapFree(GetProcessHeap(), 0, pGlobalData->pFirstAdapterInfo);
402 pGlobalData->pFirstAdapterInfo = (PIP_ADAPTER_INFO) HeapAlloc(GetProcessHeap(), 0, BufferSize);
403 }
404
405 if ((ErrRet = GetAdaptersInfo(pGlobalData->pFirstAdapterInfo, &BufferSize)) != NO_ERROR)
406 {
407 ERR("error adapterinfo\n");
408 MessageBox(hwndDlg, _T("error adapterinfo") ,_T("ncpa.cpl"),MB_ICONSTOP);
409
410 if (pGlobalData->pFirstAdapterInfo)
411 HeapFree(GetProcessHeap(), 0, pGlobalData->pFirstAdapterInfo);
412 }
413 }
414
415 void UpdateCurrentAdapterInfo(HWND hwndDlg, PGLOBAL_NCPA_DATA pGlobalData)
416 {
417 PIP_INTERFACE_INFO pInfo;
418 ULONG BufferSize = 0;
419 DWORD dwRetVal = 0;
420
421 if (!pGlobalData->pCurrentAdapterInfo)
422 return;
423
424 BufferSize = sizeof(IP_INTERFACE_INFO);
425 pInfo = (PIP_INTERFACE_INFO) HeapAlloc(GetProcessHeap(), 0, BufferSize);
426 if (ERROR_INSUFFICIENT_BUFFER == GetInterfaceInfo(pInfo, &BufferSize))
427 {
428 HeapFree(GetProcessHeap(), 0, pInfo);
429 pInfo = (PIP_INTERFACE_INFO) HeapAlloc(GetProcessHeap(), 0, BufferSize);
430 }
431
432 dwRetVal = GetInterfaceInfo(pInfo, &BufferSize);
433 if (NO_ERROR == dwRetVal)
434 {
435 DWORD i;
436
437 for (i = 0; i < pInfo->NumAdapters; i++)
438 {
439 if (0 == wcscmp(pGlobalData->CurrentAdapterName, pInfo->Adapter[i].Name))
440 {
441 if (pInfo->Adapter[i].Index != pGlobalData->pCurrentAdapterInfo->Index)
442 {
443 RefreshNICInfo(hwndDlg, pGlobalData);
444
445 pGlobalData->pCurrentAdapterInfo = pGlobalData->pFirstAdapterInfo;
446 while (pGlobalData->pCurrentAdapterInfo)
447 {
448 if (pGlobalData->pCurrentAdapterInfo->Index == pInfo->Adapter[i].Index)
449 return;
450
451 pGlobalData->pCurrentAdapterInfo = pGlobalData->pCurrentAdapterInfo->Next;
452 }
453 }
454 }
455 }
456 }
457 else if (ERROR_NO_DATA == dwRetVal)
458 WARN("There are no network adapters with IPv4 enabled on the local system\n");
459 else
460 ERR("GetInterfaceInfo failed.\n");
461 }
462
463 static VOID
464 UpdateNICStatusData(HWND hwndDlg, PGLOBAL_NCPA_DATA pGlobalData)
465 {
466 DWORD dwRet = NO_ERROR;
467
468 if (pGlobalData->pCurrentAdapterInfo)
469 {
470 if (NULL == pGlobalData->pIfTable)
471 {
472 pGlobalData->IfTableSize = sizeof(MIB_IFTABLE);
473 pGlobalData->pIfTable = (PMIB_IFTABLE)HeapAlloc(GetProcessHeap(), 0, pGlobalData->IfTableSize);
474 if (NULL == pGlobalData->pIfTable)
475 {
476 static BOOL firstError = TRUE;
477 if (firstError)
478 {
479 firstError = FALSE;
480 WARN("Out of memory - could not allocate MIB_IFTABLE(1)");
481 return;
482 }
483 }
484 }
485
486 /* Call GetIfTable once to see if we have a large enough buffer */
487 dwRet = GetIfTable(pGlobalData->pIfTable, &pGlobalData->IfTableSize, FALSE);
488 if (ERROR_INSUFFICIENT_BUFFER == dwRet)
489 {
490 HeapFree(GetProcessHeap(), 0, pGlobalData->pIfTable);
491
492 pGlobalData->pIfTable = (PMIB_IFTABLE)HeapAlloc(GetProcessHeap(), 0, pGlobalData->IfTableSize);
493 if (NULL == pGlobalData->pIfTable)
494 {
495 static BOOL firstError = TRUE;
496 if (firstError)
497 {
498 firstError = FALSE;
499 WARN("Out of memory - could not allocate MIB_IFTABLE(2)");
500 }
501
502 pGlobalData->IfTableSize = 0;
503 return;
504 }
505
506 dwRet = GetIfTable(pGlobalData->pIfTable, &pGlobalData->IfTableSize, FALSE);
507 if (NO_ERROR != dwRet)
508 {
509 HeapFree(GetProcessHeap(), 0, pGlobalData->pIfTable);
510 pGlobalData->pIfTable = NULL;
511 pGlobalData->IfTableSize = 0;
512 return;
513 }
514 }
515 }
516
517 if (NO_ERROR == dwRet)
518 {
519 DWORD i;
520 DWORD PktsOut = 0;
521 DWORD PktsIn = 0;
522 DWORD Mbps = 0;
523 DWORD OperStatus = IF_OPER_STATUS_DISCONNECTED;
524 PMIB_IFROW pIfRow = NULL;
525 TCHAR Buffer[256], LocBuffer[256];
526 SYSTEMTIME TimeConnected;
527
528 memset(&TimeConnected, 0, sizeof(TimeConnected));
529
530 if (pGlobalData->pCurrentAdapterInfo)
531 {
532 UpdateCurrentAdapterInfo(hwndDlg, pGlobalData);
533
534 for (i = 0; i < pGlobalData->pIfTable->dwNumEntries; i++)
535 {
536 pIfRow = (PMIB_IFROW)&pGlobalData->pIfTable->table[i];
537
538 if (pIfRow->dwIndex == pGlobalData->pCurrentAdapterInfo->Index)
539 {
540 DWORD DurationSeconds;
541 SYSTEMTIME SystemTime;
542 FILETIME SystemFileTime;
543 ULARGE_INTEGER LargeSystemTime;
544
545 PktsOut = pIfRow->dwOutUcastPkts;
546 PktsIn = pIfRow->dwInUcastPkts;
547 Mbps = pIfRow->dwSpeed;
548 OperStatus = pIfRow->dwOperStatus;
549
550 /* TODO: For some unknown reason, this doesn't correspond to the Windows duration */
551 GetSystemTime(&SystemTime);
552 SystemTimeToFileTime(&SystemTime, &SystemFileTime);
553 LargeSystemTime = *(ULARGE_INTEGER *)&SystemFileTime;
554 LargeSystemTime.QuadPart /= 100000ULL;
555 DurationSeconds = ((LargeSystemTime.LowPart - pIfRow->dwLastChange) / 100);
556 TimeConnected.wSecond = (DurationSeconds % 60);
557 TimeConnected.wMinute = (DurationSeconds / 60) % 60;
558 TimeConnected.wHour = (DurationSeconds / (60 * 60)) % 24;
559 TimeConnected.wDay = DurationSeconds / (60 * 60 * 24);
560
561 break;
562 }
563 }
564 }
565
566 _stprintf(Buffer, L"%u", PktsOut);
567 GetNumberFormat(LOCALE_USER_DEFAULT, 0, Buffer, NULL, LocBuffer, sizeof(LocBuffer) / sizeof(LocBuffer[0]));
568 SendDlgItemMessage(hwndDlg, IDC_SEND, WM_SETTEXT, 0, (LPARAM)LocBuffer);
569
570 _stprintf(Buffer, L"%u", PktsIn);
571 GetNumberFormat(LOCALE_USER_DEFAULT, 0, Buffer, NULL, LocBuffer, sizeof(LocBuffer) / sizeof(LocBuffer[0]));
572 SendDlgItemMessage(hwndDlg, IDC_RECEIVED, WM_SETTEXT, 0, (LPARAM)LocBuffer);
573
574 switch (OperStatus)
575 {
576 case IF_OPER_STATUS_NON_OPERATIONAL:
577 OperStatus = IDS_STATUS_NON_OPERATIONAL;
578 break;
579
580 case IF_OPER_STATUS_UNREACHABLE:
581 OperStatus = IDS_STATUS_UNREACHABLE;
582 break;
583
584 case IF_OPER_STATUS_DISCONNECTED:
585 OperStatus = IDS_STATUS_DISCONNECTED;
586 break;
587
588 case IF_OPER_STATUS_CONNECTING:
589 OperStatus = IDS_STATUS_CONNECTING;
590 break;
591
592 case IF_OPER_STATUS_CONNECTED:
593 OperStatus = IDS_STATUS_CONNECTED;
594 break;
595
596 case IF_OPER_STATUS_OPERATIONAL:
597 /* TODO: Find sub status, waiting for DHCP address, etc. */
598 OperStatus = IDS_STATUS_OPERATIONAL;
599 break;
600
601 default:
602 WARN("Unknown operation status: %d\n", OperStatus);
603 OperStatus = IDS_STATUS_OPERATIONAL;
604 break;
605 }
606 LoadString(hApplet, OperStatus, LocBuffer, sizeof(LocBuffer) / sizeof(LocBuffer[0]));
607 SendDlgItemMessage(hwndDlg, IDC_STATUS, WM_SETTEXT, 0, (LPARAM)LocBuffer);
608
609 GetTimeFormat(LOCALE_USER_DEFAULT, 0, &TimeConnected, L"HH':'mm':'ss", LocBuffer, sizeof(LocBuffer) / sizeof(LocBuffer[0]));
610 if (0 == TimeConnected.wDay)
611 {
612 SendDlgItemMessage(hwndDlg, IDC_DURATION, WM_SETTEXT, 0, (LPARAM)LocBuffer);
613 }
614 else
615 {
616 TCHAR DayBuffer[256];
617 if (1 == TimeConnected.wDay)
618 {
619 LoadString(hApplet, IDS_DURATION_DAY, DayBuffer, sizeof(DayBuffer) / sizeof(DayBuffer[0]));
620 }
621 else
622 {
623 LoadString(hApplet, IDS_DURATION_DAYS, DayBuffer, sizeof(DayBuffer) / sizeof(DayBuffer[0]));
624 }
625 _sntprintf(Buffer, 256, DayBuffer, TimeConnected.wDay, LocBuffer);
626 SendDlgItemMessage(hwndDlg, IDC_DURATION, WM_SETTEXT, 0, (LPARAM)Buffer);
627 }
628
629 LoadString(hApplet, IDS_SPEED_MBPS, LocBuffer, sizeof(LocBuffer) / sizeof(LocBuffer[0]));
630 _sntprintf(Buffer, 256, LocBuffer, Mbps / 1000000);
631 SendDlgItemMessage(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)Buffer);
632 }
633 else
634 {
635 static BOOL firstError = TRUE;
636 if (firstError)
637 {
638 firstError = FALSE;
639 ERR("GetIfTable failed with error code: %d\n", dwRet);
640 return;
641 }
642 }
643 }
644
645 static INT_PTR CALLBACK
646 NICStatusPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
647 {
648 PGLOBAL_NCPA_DATA pGlobalData;
649 pGlobalData = (PGLOBAL_NCPA_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
650
651 switch(uMsg)
652 {
653 case WM_INITDIALOG:
654 {
655 pGlobalData = (PGLOBAL_NCPA_DATA)((LPPROPSHEETPAGE)lParam)->lParam;
656 if (pGlobalData == NULL)
657 return FALSE;
658
659 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
660
661 EnableWindow(GetDlgItem(hwndDlg,IDC_ENDISABLE),FALSE);
662 pGlobalData->hStatsUpdateTimer = SetTimer(hwndDlg, 1, 1000, NULL);
663 UpdateNICStatusData(hwndDlg, pGlobalData);
664 }
665 break;
666 case WM_COMMAND:
667 switch(LOWORD(wParam))
668 {
669 case IDC_PROPERTIES:
670 {
671 DisplayNICProperties(hwndDlg, pGlobalData);
672 }
673 break;
674 }
675 break;
676 case WM_TIMER:
677 {
678 UpdateNICStatusData(hwndDlg, pGlobalData);
679 }
680 break;
681 case WM_DESTROY:
682 {
683 KillTimer(hwndDlg, pGlobalData->hStatsUpdateTimer);
684 pGlobalData->hStatsUpdateTimer = 0;
685
686 if (pGlobalData->pIfTable)
687 {
688 HeapFree(GetProcessHeap(), 0, pGlobalData->pIfTable);
689 pGlobalData->pIfTable = NULL;
690 pGlobalData->IfTableSize = 0;
691 }
692 }
693 break;
694 }
695 return FALSE;
696 }
697
698 static INT_PTR CALLBACK
699 NICSupportPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
700 {
701 PGLOBAL_NCPA_DATA pGlobalData;
702 pGlobalData = (PGLOBAL_NCPA_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
703
704 switch(uMsg)
705 {
706 case WM_INITDIALOG:
707 {
708 pGlobalData = (PGLOBAL_NCPA_DATA)((LPPROPSHEETPAGE)lParam)->lParam;
709 if (pGlobalData == NULL)
710 return FALSE;
711
712 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
713
714 if (pGlobalData->pCurrentAdapterInfo)
715 {
716 TCHAR Buffer[64];
717
718 if (pGlobalData->pCurrentAdapterInfo->DhcpEnabled)
719 LoadString(hApplet, IDS_ASSIGNED_DHCP, Buffer, sizeof(Buffer) / sizeof(TCHAR));
720 else
721 LoadString(hApplet, IDS_ASSIGNED_MANUAL, Buffer, sizeof(Buffer) / sizeof(TCHAR));
722
723 SendDlgItemMessage(hwndDlg, IDC_DETAILSTYPE, WM_SETTEXT, 0, (LPARAM)Buffer);
724 _stprintf(Buffer, _T("%S"), pGlobalData->pCurrentAdapterInfo->IpAddressList.IpAddress.String);
725 SendDlgItemMessage(hwndDlg, IDC_DETAILSIP, WM_SETTEXT, 0, (LPARAM)Buffer);
726 _stprintf(Buffer, _T("%S"), pGlobalData->pCurrentAdapterInfo->IpAddressList.IpMask.String);
727 SendDlgItemMessage(hwndDlg, IDC_DETAILSSUBNET, WM_SETTEXT, 0, (LPARAM)Buffer);
728 _stprintf(Buffer, _T("%S"), pGlobalData->pCurrentAdapterInfo->GatewayList.IpAddress.String);
729 SendDlgItemMessage(hwndDlg, IDC_DETAILSGATEWAY, WM_SETTEXT, 0, (LPARAM)Buffer);
730 }
731 }
732 break;
733 case WM_COMMAND:
734 switch(LOWORD(wParam))
735 {
736 case IDC_PROPERTIES:
737 {
738 }
739 break;
740 case IDC_DETAILS:
741 {
742 FIXME("Not implemented: show detail window\n");
743 MessageBox(hwndDlg,_T("not implemented: show detail window"),_T("ncpa.cpl"),MB_ICONSTOP);
744 }
745 break;
746 }
747 break;
748 }
749 return FALSE;
750 }
751
752 static VOID
753 DisplayNICStatus(HWND hParent,TCHAR *tpszCfgInstanceID)
754 {
755 PROPSHEETPAGE psp[2];
756 PROPSHEETHEADER psh;
757 TCHAR tpszSubKey[MAX_PATH];
758 HKEY hKey;
759 DWORD dwType = REG_SZ;
760 TCHAR tpszName[MAX_PATH];
761 DWORD dwSize = sizeof(tpszName);
762 PGLOBAL_NCPA_DATA pGlobalData;
763 PIP_ADAPTER_INFO pInfo;
764 WCHAR wcsAdapterName[MAX_ADAPTER_NAME];
765
766 pGlobalData = (PGLOBAL_NCPA_DATA)GetWindowLongPtr(hParent, DWLP_USER);
767
768 #ifndef _UNICODE
769 MultiByteToWideChar(CP_UTF8, 0, tpszCfgInstanceID, -1, pGlobalData->CurrentAdapterName, MAX_ADAPTER_NAME);
770 #else
771 wcscpy(pGlobalData->CurrentAdapterName, tpszCfgInstanceID);
772 #endif
773
774 // Get the "Name" for this Connection
775 _stprintf(tpszSubKey,_T("System\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection"),tpszCfgInstanceID);
776 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,tpszSubKey,0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
777 return;
778
779 if (RegQueryValueEx(hKey,_T("Name"),NULL,&dwType,(BYTE*)tpszName,&dwSize)!=ERROR_SUCCESS)
780 _stprintf(tpszName,_T("[ERROR]"));
781 //_stprintf(tpszName,_T("[ERROR]") _T(__FILE__) _T(" %d"),__LINE__ );
782 else
783 _tcscat(tpszName,_T(" Status"));
784 RegCloseKey(hKey);
785
786 ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
787 psh.dwSize = sizeof(PROPSHEETHEADER);
788 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
789 psh.hwndParent = hParent;
790 psh.hInstance = hApplet;
791 // FIX THESE REACTOS HEADERS !!!!!!!!!
792 psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCE(IDI_CPLSYSTEM));
793 psh.pszCaption = tpszName;//Caption;
794 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
795 psh.nStartPage = 0;
796 psh.ppsp = psp;
797 psh.pfnCallback = NULL;
798
799 RefreshNICInfo(hParent, pGlobalData);
800
801 pGlobalData->pCurrentAdapterInfo = NULL;
802 pInfo = pGlobalData->pFirstAdapterInfo;
803 while (pInfo)
804 {
805 MultiByteToWideChar(CP_UTF8, 0, pInfo->AdapterName, -1, wcsAdapterName, MAX_ADAPTER_NAME);
806 if (0 == wcscmp(wcsAdapterName, pGlobalData->CurrentAdapterName))
807 {
808 pGlobalData->pCurrentAdapterInfo = pInfo;
809 break;
810 }
811
812 pInfo = pInfo->Next;
813 }
814
815 InitPropSheetPage(&psp[0], IDD_CARDPROPERTIES, NICStatusPageProc, (LPARAM)pGlobalData);
816 InitPropSheetPage(&psp[1], IDD_CARDSUPPORT, NICSupportPageProc, (LPARAM)pGlobalData);
817
818 PropertySheet(&psh);
819 return;
820 }
821
822 //
823 // IPHLPAPI does not provide a list of all adapters
824 //
825 #if 0
826 static VOID
827 EnumAdapters(HWND hwndDlg)
828 {
829 TCHAR pszText[MAX_ADAPTER_NAME_LENGTH + 4];
830 IP_ADAPTER_INFO *pInfo;
831 ULONG size;
832 INT nIndex;
833
834 size=sizeof(Info);
835 if(GetAdaptersInfo(Info,&size)!=ERROR_SUCCESS)
836 {
837 WARN("IPHLPAPI.DLL failed to provide Adapter information\n");
838 MessageBox(hwndDlg,L"IPHLPAPI.DLL failed to provide Adapter information",L"Error",MB_ICONSTOP);
839 return;
840 }
841
842 pInfo = &Info[0];
843 while(pInfo)
844 {
845 swprintf(pszText,L"%S",Info[0].Description);
846 nIndex = SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_ADDSTRING,0,(LPARAM)pszText);
847 SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_SETITEMDATA,nIndex,(LPARAM)pInfo);
848 pInfo = pInfo->Next;
849 }
850 }
851 #endif
852
853
854
855 static void
856 NetAdapterCallback(void *pCookie,HKEY hBaseKey,TCHAR *tpszSubKey)
857 {
858 TCHAR tpszDisplayName[MAX_PATH];
859 //TCHAR tpszDeviceID[MAX_PATH];
860 TCHAR tpszCfgInstanceID[MAX_PATH];
861 TCHAR *ptpszCfgInstanceID;
862 HKEY hKey;
863 DWORD dwType = REG_SZ;
864 DWORD dwSize = sizeof(tpszDisplayName);
865 int nIndex;
866 HWND hwndDlg = (HWND)pCookie;
867 DWORD dwCharacteristics;
868
869 TRACE("NetAdapterCallback: %s\n", debugstr_aw(tpszSubKey));
870
871 if(RegOpenKeyEx(hBaseKey,tpszSubKey,0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
872 return;
873
874 TRACE("NetAdapterCallback: Reading Characteristics\n");
875 dwType = REG_DWORD;
876 dwSize = sizeof(dwCharacteristics);
877 if(RegQueryValueEx(hKey,_T("Characteristics"),NULL,&dwType,(BYTE*)&dwCharacteristics,&dwSize)!=ERROR_SUCCESS)
878 dwCharacteristics = 0;
879 if (dwCharacteristics & NCF_HIDDEN)
880 return;
881 if (!(dwCharacteristics & NCF_VIRTUAL) && !(dwCharacteristics & NCF_PHYSICAL))
882 return;
883
884 TRACE("NetAdapterCallback: Reading DriverDesc\n");
885 dwType = REG_SZ;
886 dwSize = sizeof(tpszDisplayName);
887 if (RegQueryValueEx(hKey,_T("DriverDesc"),NULL,&dwType,(BYTE*)tpszDisplayName,&dwSize)!= ERROR_SUCCESS)
888 _tcscpy(tpszDisplayName,_T("Unnamed Adapter"));
889 TRACE("Network card: '%s'\n", debugstr_aw(tpszDisplayName));
890
891 // get the link to the Enum Subkey (currently unused)
892 //dwType = REG_SZ;
893 //dwSize = sizeof(tpszDeviceID);
894 //if(RegQueryValueEx(hKey,_T("MatchingDeviceId"),NULL,&dwType,(BYTE*)tpszDeviceID,&dwSize) != ERROR_SUCCESS) {
895 // WARN("Missing MatchingDeviceId Entry\n");
896 // MessageBox(hwndDlg,_T("Missing MatchingDeviceId Entry"),_T("Registry Problem"),MB_ICONSTOP);
897 // return;
898 //}
899
900 // get the card configuration GUID
901 dwType = REG_SZ;
902 dwSize = sizeof(tpszCfgInstanceID);
903 if(RegQueryValueEx(hKey,_T("NetCfgInstanceId"),NULL,&dwType,(BYTE*)tpszCfgInstanceID,&dwSize) != ERROR_SUCCESS)
904 {
905 ERR("Missing NetCfgInstanceId Entry\n");
906 MessageBox(hwndDlg,_T("Missing NetCfgInstanceId Entry"),_T("Registry Problem"),MB_ICONSTOP);
907 return;
908 }
909
910 ptpszCfgInstanceID = _tcsdup(tpszCfgInstanceID);
911 //
912 // **TODO** **FIXME** TBD
913 // At this point, we should verify, if the device listed here
914 // really represents a device that is currently connected to the system
915 //
916 // How is this done properly ?
917
918 nIndex = (int) SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_ADDSTRING,0,(LPARAM)tpszDisplayName);
919 SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_SETITEMDATA,nIndex,(LPARAM)ptpszCfgInstanceID);
920 RegCloseKey(hKey);
921 }
922
923
924 static void
925 EnumAdapters(HWND hwndDlg)
926 {
927 LPTSTR lpRegPath = _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}");
928
929 EnumRegKeys(NetAdapterCallback,hwndDlg,HKEY_LOCAL_MACHINE,lpRegPath);
930 return;
931 }
932
933
934 static INT_PTR CALLBACK
935 NetworkPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
936 {
937 NMHDR* pnmh;
938 int nIndex;
939 switch(uMsg)
940 {
941 case WM_INITDIALOG:
942 {
943 PGLOBAL_NCPA_DATA pGlobalData = (PGLOBAL_NCPA_DATA)((LPPROPSHEETPAGE)lParam)->lParam;
944 if (pGlobalData == NULL)
945 return FALSE;
946
947 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
948
949 EnableWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
950 EnableWindow(GetDlgItem(hwndDlg,IDC_REMOVE),FALSE);
951
952 EnumAdapters(hwndDlg);
953 SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_SETCURSEL,0,0);
954 }
955 break;
956
957 case WM_NOTIFY:
958 pnmh=(NMHDR*)lParam;
959 switch(pnmh->code)
960 {
961 case PSN_APPLY:
962 case PSN_RESET:
963 while(SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_GETCOUNT,0,0)>0)
964 {
965 TCHAR *tpszString;
966
967 tpszString = (TCHAR*)SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_GETITEMDATA,0,0);
968 if(tpszString)
969 free(tpszString);
970 SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_DELETESTRING,0,0);
971 }
972 break;
973 }
974 break;
975
976 case WM_COMMAND:
977 switch(LOWORD(wParam))
978 {
979 case IDC_NETCARDLIST:
980 if(HIWORD(wParam)==LBN_DBLCLK) {
981 nIndex = (int) SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_GETCURSEL,0,0);
982 if(nIndex!=-1)
983 DisplayNICStatus(hwndDlg,(TCHAR*)SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_GETITEMDATA,nIndex,0));
984 }
985 break;
986
987 case IDC_PROPERTIES:
988 nIndex = (int) SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_GETCURSEL,0,0);
989 if(nIndex!=-1)
990 DisplayNICStatus(hwndDlg,(TCHAR*)SendDlgItemMessage(hwndDlg,IDC_NETCARDLIST,LB_GETITEMDATA,nIndex,0));
991 break;
992 }
993 break;
994 }
995
996 return FALSE;
997 }
998
999
1000
1001 /* First Applet */
1002 static LONG CALLBACK
1003 DisplayApplet(VOID)
1004 {
1005 PGLOBAL_NCPA_DATA pGlobalData;
1006 PROPSHEETPAGE psp[1];
1007 PROPSHEETHEADER psh = {0};
1008 TCHAR Caption[1024];
1009 int Ret;
1010
1011 LoadString(hApplet, IDS_CPLSYSTEMNAME, Caption, sizeof(Caption) / sizeof(TCHAR));
1012
1013 pGlobalData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLOBAL_NCPA_DATA));
1014 if (pGlobalData == NULL)
1015 return 0;
1016
1017 psh.dwSize = sizeof(PROPSHEETHEADER);
1018 psh.dwFlags = PSH_PROPSHEETPAGE;
1019 psh.hwndParent = NULL;
1020 psh.hInstance = hApplet;
1021 psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCE(IDI_CPLSYSTEM));
1022 psh.pszCaption = Caption;
1023 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
1024 psh.nStartPage = 0;
1025 psh.ppsp = psp;
1026 psh.pfnCallback = NULL;
1027
1028 InitPropSheetPage(&psp[0], IDD_PROPPAGENETWORK, NetworkPageProc, (LPARAM)pGlobalData);
1029
1030 Ret = PropertySheet(&psh);
1031
1032 HeapFree(GetProcessHeap(), 0, pGlobalData);
1033
1034 return (LONG)(Ret != -1);
1035 }
1036
1037 /* Control Panel Callback */
1038 LONG CALLBACK
1039 CPlApplet(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
1040 {
1041 UNREFERENCED_PARAMETER(hwndCPl);
1042 switch (uMsg)
1043 {
1044 case CPL_INIT:
1045 {
1046 return TRUE;
1047 }
1048
1049 case CPL_GETCOUNT:
1050 {
1051 return sizeof(Applets)/sizeof(APPLET);
1052 }
1053
1054 case CPL_INQUIRE:
1055 {
1056 CPLINFO *CPlInfo = (CPLINFO*)lParam2;
1057 CPlInfo->lData = 0;
1058 CPlInfo->idIcon = Applets[(int)lParam1].idIcon;
1059 CPlInfo->idName = Applets[(int)lParam1].idName;
1060 CPlInfo->idInfo = Applets[(int)lParam1].idDescription;
1061 break;
1062 }
1063
1064 case CPL_DBLCLK:
1065 {
1066 Applets[(int)lParam1].AppletProc();
1067 break;
1068 }
1069 }
1070
1071 return FALSE;
1072 }
1073
1074
1075 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
1076 {
1077 UNREFERENCED_PARAMETER(lpvReserved);
1078
1079 switch(dwReason)
1080 {
1081 case DLL_PROCESS_ATTACH:
1082 case DLL_THREAD_ATTACH:
1083 hApplet = hinstDLL;
1084 break;
1085 }
1086
1087 return TRUE;
1088 }