Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenlistview.c
Go to the documentation of this file.
00001 /* 00002 * Regedit listviews 00003 * 00004 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include <regedit.h> 00022 00023 00024 #define CX_ICON 16 00025 #define CY_ICON 16 00026 #define NUM_ICONS 2 00027 00028 int Image_String = 0; 00029 int Image_Bin = 0; 00030 INT iListViewSelect = -1; 00031 00032 typedef struct tagLINE_INFO 00033 { 00034 DWORD dwValType; 00035 LPTSTR name; 00036 void* val; 00037 size_t val_len; 00038 } LINE_INFO, *PLINE_INFO; 00039 00040 /******************************************************************************* 00041 * Global and Local Variables: 00042 */ 00043 00044 static DWORD g_columnToSort = ~0UL; 00045 static BOOL g_invertSort = FALSE; 00046 00047 #define MAX_LIST_COLUMNS (IDS_LIST_COLUMN_LAST - IDS_LIST_COLUMN_FIRST + 1) 00048 static const int default_column_widths[MAX_LIST_COLUMNS] = { 200, 175, 400 }; 00049 static const int column_alignment[MAX_LIST_COLUMNS] = { LVCFMT_LEFT, LVCFMT_LEFT, LVCFMT_LEFT }; 00050 00051 LPCTSTR GetValueName(HWND hwndLV, int iStartAt) 00052 { 00053 int item; 00054 LVITEM LVItem; 00055 PLINE_INFO lineinfo; 00056 00057 /* 00058 if a new item is inserted, then no allocation, 00059 otherwise the heap block will be lost! 00060 */ 00061 item = ListView_GetNextItem(hwndLV, iStartAt, LVNI_SELECTED); 00062 if (item == -1) return NULL; 00063 00064 /* 00065 Should be always TRUE anyways 00066 */ 00067 LVItem.iItem = item; 00068 LVItem.iSubItem = 0; 00069 LVItem.mask = LVIF_PARAM; 00070 if (ListView_GetItem(hwndLV, &LVItem) == FALSE) 00071 return NULL; 00072 00073 lineinfo = (PLINE_INFO)LVItem.lParam; 00074 if (lineinfo == NULL) 00075 return NULL; 00076 00077 return lineinfo->name; 00078 } 00079 00080 VOID SetValueName(HWND hwndLV, LPCTSTR pszValueName) 00081 { 00082 INT i, c; 00083 LV_FINDINFO fi; 00084 00085 c = ListView_GetItemCount(hwndLV); 00086 for(i = 0; i < c; i++) 00087 { 00088 ListView_SetItemState(hwndLV, i, 0, LVIS_FOCUSED | LVIS_SELECTED); 00089 } 00090 if (pszValueName == NULL) 00091 i = 0; 00092 else 00093 { 00094 fi.flags = LVFI_STRING; 00095 fi.psz = pszValueName; 00096 i = ListView_FindItem(hwndLV, -1, &fi); 00097 } 00098 ListView_SetItemState(hwndLV, i, LVIS_FOCUSED | LVIS_SELECTED, 00099 LVIS_FOCUSED | LVIS_SELECTED); 00100 iListViewSelect = i; 00101 } 00102 00103 BOOL IsDefaultValue(HWND hwndLV, int i) 00104 { 00105 PLINE_INFO lineinfo; 00106 LVITEM Item; 00107 00108 Item.mask = LVIF_PARAM; 00109 Item.iItem = i; 00110 if(ListView_GetItem(hwndLV, &Item)) 00111 { 00112 lineinfo = (PLINE_INFO)Item.lParam; 00113 return lineinfo && (!lineinfo->name || !_tcscmp(lineinfo->name, _T(""))); 00114 } 00115 return FALSE; 00116 } 00117 00118 /******************************************************************************* 00119 * Local module support methods 00120 */ 00121 static void AddEntryToList(HWND hwndLV, LPTSTR Name, DWORD dwValType, void* ValBuf, DWORD dwCount, int Position, BOOL ValExists) 00122 { 00123 PLINE_INFO linfo; 00124 LVITEM item; 00125 int index; 00126 00127 linfo = (PLINE_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINE_INFO) + dwCount); 00128 linfo->dwValType = dwValType; 00129 linfo->val_len = dwCount; 00130 if(dwCount > 0) 00131 { 00132 memcpy(&linfo[1], ValBuf, dwCount); 00133 } 00134 linfo->name = _tcsdup(Name); 00135 00136 item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; 00137 item.iItem = (Position == -1 ? 0: Position); 00138 item.iSubItem = 0; 00139 item.state = 0; 00140 item.stateMask = 0; 00141 item.pszText = Name; 00142 item.cchTextMax = (int) _tcslen(item.pszText); 00143 if (item.cchTextMax == 0) 00144 item.pszText = LPSTR_TEXTCALLBACK; 00145 item.iImage = 0; 00146 item.lParam = (LPARAM)linfo; 00147 switch(dwValType) 00148 { 00149 case REG_SZ: 00150 case REG_EXPAND_SZ: 00151 case REG_MULTI_SZ: 00152 item.iImage = Image_String; 00153 break; 00154 default: 00155 item.iImage = Image_Bin; 00156 break; 00157 } 00158 00159 /* item.lParam = (LPARAM)ValBuf; */ 00160 #if (_WIN32_IE >= 0x0300) 00161 item.iIndent = 0; 00162 #endif 00163 00164 index = ListView_InsertItem(hwndLV, &item); 00165 if (index != -1) 00166 { 00167 switch (dwValType) 00168 { 00169 case REG_SZ: 00170 case REG_EXPAND_SZ: 00171 if(dwCount > 0) 00172 { 00173 ListView_SetItemText(hwndLV, index, 2, ValBuf); 00174 } 00175 else if(!ValExists) 00176 { 00177 TCHAR buffer[255]; 00178 /* load (value not set) string */ 00179 LoadString(hInst, IDS_VALUE_NOT_SET, buffer, sizeof(buffer)/sizeof(TCHAR)); 00180 ListView_SetItemText(hwndLV, index, 2, buffer); 00181 } 00182 break; 00183 case REG_MULTI_SZ: 00184 { 00185 LPTSTR src, str; 00186 if(dwCount >= 2) 00187 { 00188 src = (LPTSTR)ValBuf; 00189 str = HeapAlloc(GetProcessHeap(), 0, dwCount + sizeof(TCHAR)); 00190 if(str != NULL) 00191 { 00192 *str = _T('\0'); 00193 /* concatenate all srings */ 00194 while(*src != _T('\0')) 00195 { 00196 _tcscat(str, src); 00197 _tcscat(str, _T(" ")); 00198 src += _tcslen(src) + 1; 00199 } 00200 ListView_SetItemText(hwndLV, index, 2, str); 00201 HeapFree(GetProcessHeap(), 0, str); 00202 } 00203 else 00204 ListView_SetItemText(hwndLV, index, 2, _T("")); 00205 } 00206 else 00207 ListView_SetItemText(hwndLV, index, 2, _T("")); 00208 } 00209 break; 00210 case REG_DWORD: 00211 { 00212 TCHAR buf[200]; 00213 if(dwCount == sizeof(DWORD)) 00214 { 00215 wsprintf(buf, _T("0x%08x (%u)"), *(DWORD*)ValBuf, *(DWORD*)ValBuf); 00216 } 00217 else 00218 { 00219 LoadString(hInst, IDS_INVALID_DWORD, buf, sizeof(buf)/sizeof(TCHAR)); 00220 } 00221 ListView_SetItemText(hwndLV, index, 2, buf); 00222 } 00223 /* lpsRes = convertHexToDWORDStr(lpbData, dwLen); */ 00224 break; 00225 default: 00226 { 00227 unsigned int i; 00228 LPBYTE pData = (LPBYTE)ValBuf; 00229 LPTSTR strBinary; 00230 if(dwCount > 0) 00231 { 00232 strBinary = HeapAlloc(GetProcessHeap(), 0, (dwCount * sizeof(TCHAR) * 3) + sizeof(TCHAR)); 00233 for (i = 0; i < dwCount; i++) 00234 { 00235 wsprintf( strBinary + i*3, _T("%02X "), pData[i] ); 00236 } 00237 strBinary[dwCount * 3] = 0; 00238 ListView_SetItemText(hwndLV, index, 2, strBinary); 00239 HeapFree(GetProcessHeap(), 0, strBinary); 00240 } 00241 else 00242 { 00243 TCHAR szText[128]; 00244 LoadString(hInst, IDS_BINARY_EMPTY, szText, sizeof(szText)/sizeof(TCHAR)); 00245 ListView_SetItemText(hwndLV, index, 2, szText); 00246 } 00247 } 00248 break; 00249 } 00250 } 00251 } 00252 00253 static BOOL CreateListColumns(HWND hWndListView) 00254 { 00255 TCHAR szText[50]; 00256 int index; 00257 LV_COLUMN lvC; 00258 00259 /* Create columns. */ 00260 lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; 00261 lvC.pszText = szText; 00262 00263 /* Load the column labels from the resource file. */ 00264 for (index = 0; index < MAX_LIST_COLUMNS; index++) 00265 { 00266 lvC.iSubItem = index; 00267 lvC.cx = default_column_widths[index]; 00268 lvC.fmt = column_alignment[index]; 00269 LoadString(hInst, IDS_LIST_COLUMN_FIRST + index, szText, sizeof(szText)/sizeof(TCHAR)); 00270 if (ListView_InsertColumn(hWndListView, index, &lvC) == -1) return FALSE; 00271 } 00272 return TRUE; 00273 } 00274 00275 static BOOL InitListViewImageLists(HWND hwndLV) 00276 { 00277 HIMAGELIST himl; /* handle to image list */ 00278 HICON hico; /* handle to icon */ 00279 00280 /* Create the image list. */ 00281 if ((himl = ImageList_Create(CX_ICON, CY_ICON, 00282 ILC_MASK, 0, NUM_ICONS)) == NULL) 00283 return FALSE; 00284 00285 hico = LoadIcon(hInst, MAKEINTRESOURCE(IDI_BIN)); 00286 Image_Bin = ImageList_AddIcon(himl, hico); 00287 00288 hico = LoadIcon(hInst, MAKEINTRESOURCE(IDI_STRING)); 00289 Image_String = ImageList_AddIcon(himl, hico); 00290 00291 00292 /* Fail if not all of the images were added. */ 00293 if (ImageList_GetImageCount(himl) < NUM_ICONS) 00294 { 00295 return FALSE; 00296 } 00297 00298 /* Associate the image list with the tree view control. */ 00299 (void)ListView_SetImageList(hwndLV, himl, LVSIL_SMALL); 00300 00301 return TRUE; 00302 } 00303 00304 /* OnGetDispInfo - processes the LVN_GETDISPINFO notification message. */ 00305 00306 static void OnGetDispInfo(NMLVDISPINFO* plvdi) 00307 { 00308 static TCHAR buffer[200]; 00309 00310 plvdi->item.pszText = NULL; 00311 plvdi->item.cchTextMax = 0; 00312 00313 switch (plvdi->item.iSubItem) 00314 { 00315 case 0: 00316 LoadString(hInst, IDS_DEFAULT_VALUE_NAME, buffer, sizeof(buffer)/sizeof(TCHAR)); 00317 plvdi->item.pszText = buffer; 00318 break; 00319 case 1: 00320 switch (((LINE_INFO*)plvdi->item.lParam)->dwValType) 00321 { 00322 case REG_NONE: 00323 plvdi->item.pszText = _T("REG_NONE"); 00324 break; 00325 case REG_SZ: 00326 plvdi->item.pszText = _T("REG_SZ"); 00327 break; 00328 case REG_EXPAND_SZ: 00329 plvdi->item.pszText = _T("REG_EXPAND_SZ"); 00330 break; 00331 case REG_BINARY: 00332 plvdi->item.pszText = _T("REG_BINARY"); 00333 break; 00334 case REG_DWORD: /* REG_DWORD_LITTLE_ENDIAN */ 00335 plvdi->item.pszText = _T("REG_DWORD"); 00336 break; 00337 case REG_DWORD_BIG_ENDIAN: 00338 plvdi->item.pszText = _T("REG_DWORD_BIG_ENDIAN"); 00339 break; 00340 case REG_LINK: 00341 plvdi->item.pszText = _T("REG_LINK"); 00342 break; 00343 case REG_MULTI_SZ: 00344 plvdi->item.pszText = _T("REG_MULTI_SZ"); 00345 break; 00346 case REG_RESOURCE_LIST: 00347 plvdi->item.pszText = _T("REG_RESOURCE_LIST"); 00348 break; 00349 case REG_FULL_RESOURCE_DESCRIPTOR: 00350 plvdi->item.pszText = _T("REG_FULL_RESOURCE_DESCRIPTOR"); 00351 break; 00352 case REG_RESOURCE_REQUIREMENTS_LIST: 00353 plvdi->item.pszText = _T("REG_RESOURCE_REQUIREMENTS_LIST"); 00354 break; 00355 case REG_QWORD: /* REG_QWORD_LITTLE_ENDIAN */ 00356 plvdi->item.pszText = _T("REG_QWORD"); 00357 break; 00358 default: 00359 { 00360 TCHAR buf2[200]; 00361 LoadString(hInst, IDS_UNKNOWN_TYPE, buf2, sizeof(buf2)/sizeof(TCHAR)); 00362 wsprintf(buffer, buf2, ((LINE_INFO*)plvdi->item.lParam)->dwValType); 00363 plvdi->item.pszText = buffer; 00364 break; 00365 } 00366 } 00367 break; 00368 case 3: 00369 plvdi->item.pszText = _T(""); 00370 break; 00371 } 00372 } 00373 00374 static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 00375 { 00376 LINE_INFO*l, *r; 00377 UNREFERENCED_PARAMETER(lParamSort); 00378 00379 l = (LINE_INFO*)lParam1; 00380 r = (LINE_INFO*)lParam2; 00381 00382 if (g_columnToSort == ~0UL) 00383 g_columnToSort = 0; 00384 00385 if (g_columnToSort == 1 && l->dwValType != r->dwValType) 00386 return g_invertSort ? (int)r->dwValType - (int)l->dwValType : (int)l->dwValType - (int)r->dwValType; 00387 if (g_columnToSort == 2) 00388 { 00389 /* FIXME: Sort on value */ 00390 } 00391 return g_invertSort ? _tcsicmp(r->name, l->name) : _tcsicmp(l->name, r->name); 00392 } 00393 00394 BOOL ListWndNotifyProc(HWND hWnd, WPARAM wParam, LPARAM lParam, BOOL *Result) 00395 { 00396 NMLVDISPINFO* Info; 00397 UNREFERENCED_PARAMETER(wParam); 00398 *Result = TRUE; 00399 switch (((LPNMHDR)lParam)->code) 00400 { 00401 case LVN_GETDISPINFO: 00402 OnGetDispInfo((NMLVDISPINFO*)lParam); 00403 return TRUE; 00404 case LVN_COLUMNCLICK: 00405 if (g_columnToSort == (DWORD)((LPNMLISTVIEW)lParam)->iSubItem) 00406 g_invertSort = !g_invertSort; 00407 else 00408 { 00409 g_columnToSort = ((LPNMLISTVIEW)lParam)->iSubItem; 00410 g_invertSort = FALSE; 00411 } 00412 00413 (void)ListView_SortItems(hWnd, CompareFunc, (WPARAM)hWnd); 00414 return TRUE; 00415 case NM_DBLCLK: 00416 case NM_RETURN: 00417 { 00418 SendMessage(hFrameWnd, WM_COMMAND, MAKEWPARAM(ID_EDIT_MODIFY, 0), 0); 00419 } 00420 return TRUE; 00421 case NM_SETFOCUS: 00422 g_pChildWnd->nFocusPanel = 0; 00423 break; 00424 case LVN_BEGINLABELEDIT: 00425 Info = (NMLVDISPINFO*)lParam; 00426 if(Info) 00427 { 00428 PLINE_INFO lineinfo = (PLINE_INFO)Info->item.lParam; 00429 if(!lineinfo->name || !_tcscmp(lineinfo->name, _T(""))) 00430 { 00431 *Result = TRUE; 00432 } 00433 else 00434 { 00435 *Result = FALSE; 00436 } 00437 } 00438 else 00439 *Result = TRUE; 00440 return TRUE; 00441 case LVN_ENDLABELEDIT: 00442 Info = (NMLVDISPINFO*)lParam; 00443 if(Info && Info->item.pszText) 00444 { 00445 PLINE_INFO lineinfo = (PLINE_INFO)Info->item.lParam; 00446 if(!lineinfo->name || !_tcscmp(lineinfo->name, _T(""))) 00447 { 00448 *Result = FALSE; 00449 } 00450 else 00451 { 00452 if(_tcslen(Info->item.pszText) == 0) 00453 { 00454 TCHAR msg[128], caption[128]; 00455 00456 LoadString(hInst, IDS_ERR_RENVAL_TOEMPTY, msg, sizeof(msg)/sizeof(TCHAR)); 00457 LoadString(hInst, IDS_ERR_RENVAL_CAPTION, caption, sizeof(caption)/sizeof(TCHAR)); 00458 MessageBox(0, msg, caption, 0); 00459 *Result = TRUE; 00460 } 00461 else 00462 { 00463 HKEY hKeyRoot; 00464 LPCTSTR keyPath; 00465 LONG lResult; 00466 00467 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot); 00468 lResult = RenameValue(hKeyRoot, keyPath, Info->item.pszText, lineinfo->name); 00469 lineinfo->name = realloc(lineinfo->name, (_tcslen(Info->item.pszText)+1)*sizeof(TCHAR)); 00470 if (lineinfo->name != NULL) 00471 _tcscpy(lineinfo->name, Info->item.pszText); 00472 00473 *Result = TRUE; 00474 return (lResult == ERROR_SUCCESS); 00475 } 00476 } 00477 } 00478 else 00479 *Result = TRUE; 00480 00481 return TRUE; 00482 } 00483 return FALSE; 00484 } 00485 00486 00487 HWND CreateListView(HWND hwndParent, HMENU id) 00488 { 00489 RECT rcClient; 00490 HWND hwndLV; 00491 00492 /* Get the dimensions of the parent window's client area, and create the list view control. */ 00493 GetClientRect(hwndParent, &rcClient); 00494 hwndLV = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, _T("List View"), 00495 WS_VISIBLE | WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_EDITLABELS, 00496 0, 0, rcClient.right, rcClient.bottom, 00497 hwndParent, id, hInst, NULL); 00498 if (!hwndLV) return NULL; 00499 00500 /* Initialize the image list, and add items to the control. */ 00501 if (!CreateListColumns(hwndLV)) goto fail; 00502 if (!InitListViewImageLists(hwndLV)) goto fail; 00503 00504 return hwndLV; 00505 fail: 00506 DestroyWindow(hwndLV); 00507 return NULL; 00508 } 00509 00510 void DestroyListView(HWND hwndLV) 00511 { 00512 INT count, i; 00513 LVITEM item; 00514 00515 count = ListView_GetItemCount(hwndLV); 00516 for (i = 0; i < count; i++) 00517 { 00518 item.mask = LVIF_PARAM; 00519 item.iItem = i; 00520 (void)ListView_GetItem(hwndLV, &item); 00521 free(((LINE_INFO*)item.lParam)->name); 00522 HeapFree(GetProcessHeap(), 0, (void*)item.lParam); 00523 } 00524 00525 } 00526 00527 BOOL RefreshListView(HWND hwndLV, HKEY hKey, LPCTSTR keyPath) 00528 { 00529 DWORD max_sub_key_len; 00530 DWORD max_val_name_len; 00531 DWORD max_val_size; 00532 DWORD val_count; 00533 HKEY hNewKey; 00534 LONG errCode; 00535 INT i, c; 00536 BOOL AddedDefault = FALSE; 00537 00538 if (!hwndLV) return FALSE; 00539 00540 (void)ListView_EditLabel(hwndLV, -1); 00541 00542 SendMessage(hwndLV, WM_SETREDRAW, FALSE, 0); 00543 DestroyListView(hwndLV); 00544 00545 g_columnToSort = ~0UL; 00546 (void)ListView_DeleteAllItems(hwndLV); 00547 00548 if(!hKey) return FALSE; 00549 00550 errCode = RegOpenKeyEx(hKey, keyPath, 0, KEY_READ, &hNewKey); 00551 if (errCode != ERROR_SUCCESS) return FALSE; 00552 00553 /* get size information and resize the buffers if necessary */ 00554 errCode = RegQueryInfoKey(hNewKey, NULL, NULL, NULL, NULL, &max_sub_key_len, NULL, 00555 &val_count, &max_val_name_len, &max_val_size, NULL, NULL); 00556 00557 if (errCode == ERROR_SUCCESS) 00558 { 00559 TCHAR* ValName = HeapAlloc(GetProcessHeap(), 0, ++max_val_name_len * sizeof(TCHAR)); 00560 DWORD dwValNameLen = max_val_name_len; 00561 BYTE* ValBuf = HeapAlloc(GetProcessHeap(), 0, max_val_size + sizeof(TCHAR)); 00562 DWORD dwValSize = max_val_size; 00563 DWORD dwIndex = 0L; 00564 DWORD dwValType; 00565 /* if (RegQueryValueEx(hNewKey, NULL, NULL, &dwValType, ValBuf, &dwValSize) == ERROR_SUCCESS) { */ 00566 /* AddEntryToList(hwndLV, _T("(Default)"), dwValType, ValBuf, dwValSize); */ 00567 /* } */ 00568 /* dwValSize = max_val_size; */ 00569 while (RegEnumValue(hNewKey, dwIndex, ValName, &dwValNameLen, NULL, &dwValType, ValBuf, &dwValSize) == ERROR_SUCCESS) 00570 { 00571 /* Add a terminating 0 character. Usually this is only necessary for strings. */ 00572 ValBuf[dwValSize] = 0; 00573 #ifdef UNICODE 00574 ValBuf[dwValSize + 1] = 0; 00575 #endif 00576 AddEntryToList(hwndLV, ValName, dwValType, ValBuf, dwValSize, -1, TRUE); 00577 dwValNameLen = max_val_name_len; 00578 dwValSize = max_val_size; 00579 dwValType = 0L; 00580 ++dwIndex; 00581 if(!_tcscmp(ValName, _T(""))) 00582 { 00583 AddedDefault = TRUE; 00584 } 00585 } 00586 HeapFree(GetProcessHeap(), 0, ValBuf); 00587 HeapFree(GetProcessHeap(), 0, ValName); 00588 } 00589 if(!AddedDefault) 00590 { 00591 AddEntryToList(hwndLV, _T(""), REG_SZ, NULL, 0, 0, FALSE); 00592 } 00593 ListView_SortItems(hwndLV, CompareFunc, (WPARAM)hwndLV); 00594 c = ListView_GetItemCount(hwndLV); 00595 for(i = 0; i < c; i++) 00596 { 00597 ListView_SetItemState(hwndLV, i, 0, LVIS_FOCUSED | LVIS_SELECTED); 00598 } 00599 ListView_SetItemState(hwndLV, iListViewSelect, 00600 LVIS_FOCUSED | LVIS_SELECTED, 00601 LVIS_FOCUSED | LVIS_SELECTED); 00602 RegCloseKey(hNewKey); 00603 SendMessage(hwndLV, WM_SETREDRAW, TRUE, 0); 00604 00605 return TRUE; 00606 } Generated on Sun May 27 2012 04:16:59 for ReactOS by
1.7.6.1
|