/* Process items in the StartUp group of the user's Programs under the Start Menu. Some installers put * shell links here to restart themselves after boot. */ static BOOL ProcessStartupItems(void) { BOOL ret = FALSE; HRESULT hr; IMalloc *ppM = NULL; IShellFolder *psfDesktop = NULL, *psfStartup = NULL; LPITEMIDLIST pidlStartup = NULL, pidlItem; ULONG NumPIDLs; IEnumIDList *iEnumList = NULL; STRRET strret; WCHAR wszCommand[MAX_PATH]; WINE_TRACE("Processing items in the StartUp folder.\n"); hr = SHGetMalloc(&ppM); if (FAILED(hr)) { WINE_ERR("Couldn't get IMalloc object.\n"); goto done; } hr = SHGetDesktopFolder(&psfDesktop); if (FAILED(hr)) { WINE_ERR("Couldn't get desktop folder.\n"); goto done; } hr = SHGetSpecialFolderLocation(NULL, CSIDL_STARTUP, &pidlStartup); if (FAILED(hr)) { WINE_TRACE("Couldn't get StartUp folder location.\n"); goto done; } hr = IShellFolder_BindToObject(psfDesktop, pidlStartup, NULL, &IID_IShellFolder, (LPVOID*)&psfStartup); if (FAILED(hr)) { WINE_TRACE("Couldn't bind IShellFolder to StartUp folder.\n"); goto done; } hr = IShellFolder_EnumObjects(psfStartup, NULL, SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList); if (FAILED(hr)) { WINE_TRACE("Unable to enumerate StartUp objects.\n"); goto done; } while (IEnumIDList_Next(iEnumList, 1, &pidlItem, &NumPIDLs) == S_OK && (NumPIDLs) == 1) { hr = IShellFolder_GetDisplayNameOf(psfStartup, pidlItem, SHGDN_FORPARSING, &strret); if (FAILED(hr)) WINE_TRACE("Unable to get display name of enumeration item.\n"); else { hr = StrRetToBufW(&strret, pidlItem, wszCommand, MAX_PATH); if (FAILED(hr)) WINE_TRACE("Unable to parse display name.\n"); else { HINSTANCE hinst; hinst = ShellExecuteW(NULL, NULL, wszCommand, NULL, NULL, SW_SHOWNORMAL); if (PtrToUlong(hinst) <= 32) WINE_WARN("Error %p executing command %s.\n", hinst, wine_dbgstr_w(wszCommand)); } } IMalloc_Free(ppM, pidlItem); } /* Return success */ ret = TRUE; done: if (iEnumList) IEnumIDList_Release(iEnumList); if (psfStartup) IShellFolder_Release(psfStartup); if (pidlStartup) IMalloc_Free(ppM, pidlStartup); return ret; }
static void update_path_box(explorer_info *info) { COMBOBOXEXITEMW item; COMBOBOXEXITEMW main_item; IShellFolder *desktop; IPersistFolder2 *persist; LPITEMIDLIST desktop_pidl; IEnumIDList *ids; ImageList_Remove((HIMAGELIST)info->icon_list,-1); SendMessageW(info->path_box,CB_RESETCONTENT,0,0); SHGetDesktopFolder(&desktop); IShellFolder_QueryInterface(desktop,&IID_IPersistFolder2,(void**)&persist); IPersistFolder2_GetCurFolder(persist,&desktop_pidl); IPersistFolder2_Release(persist); persist = NULL; /*Add Desktop*/ item.iItem = -1; item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_LPARAM; item.iIndent = 0; create_combobox_item(desktop,desktop_pidl,info->icon_list,&item); item.lParam = (LPARAM)desktop_pidl; SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item); if(ILIsEqual(info->pidl,desktop_pidl)) main_item = item; else CoTaskMemFree(item.pszText); /*Add all direct subfolders of Desktop*/ if(SUCCEEDED(IShellFolder_EnumObjects(desktop,NULL,SHCONTF_FOLDERS,&ids)) && ids!=NULL) { LPITEMIDLIST curr_pidl=NULL; HRESULT hres; item.iIndent = 1; while(1) { ILFree(curr_pidl); curr_pidl=NULL; hres = IEnumIDList_Next(ids,1,&curr_pidl,NULL); if(FAILED(hres) || hres == S_FALSE) break; if(!create_combobox_item(desktop,curr_pidl,info->icon_list,&item)) WINE_WARN("Could not create a combobox item\n"); else { LPITEMIDLIST full_pidl = ILCombine(desktop_pidl,curr_pidl); item.lParam = (LPARAM)full_pidl; SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item); if(ILIsEqual(full_pidl,info->pidl)) main_item = item; else if(ILIsParent(full_pidl,info->pidl,FALSE)) { /*add all parents of the pidl passed in*/ LPITEMIDLIST next_pidl = ILFindChild(full_pidl,info->pidl); IShellFolder *curr_folder = NULL, *temp; hres = IShellFolder_BindToObject(desktop,curr_pidl,NULL, &IID_IShellFolder, (void**)&curr_folder); if(FAILED(hres)) WINE_WARN("Could not get an IShellFolder\n"); while(!ILIsEmpty(next_pidl)) { LPITEMIDLIST first = ILCloneFirst(next_pidl); CoTaskMemFree(item.pszText); if(!create_combobox_item(curr_folder,first, info->icon_list,&item)) { WINE_WARN("Could not create a combobox item\n"); break; } ++item.iIndent; full_pidl = ILCombine(full_pidl,first); item.lParam = (LPARAM)full_pidl; SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item); temp=NULL; hres = IShellFolder_BindToObject(curr_folder,first,NULL, &IID_IShellFolder, (void**)&temp); if(FAILED(hres)) { WINE_WARN("Could not get an IShellFolder\n"); break; } IShellFolder_Release(curr_folder); curr_folder = temp; ILFree(first); next_pidl = ILGetNext(next_pidl); } memcpy(&main_item,&item,sizeof(item)); if(curr_folder) IShellFolder_Release(curr_folder); item.iIndent = 1; } else CoTaskMemFree(item.pszText); } } ILFree(curr_pidl); IEnumIDList_Release(ids); } else WINE_WARN("Could not enumerate the desktop\n"); SendMessageW(info->path_box,CBEM_SETITEMW,0,(LPARAM)&main_item); CoTaskMemFree(main_item.pszText); }
/* some of this code appears to be broken by bugs in Wine: the label * setting code has no effect, for instance */ void apply_drive_changes(void) { int i; HANDLE mgr; DWORD len; struct mountmgr_unix_drive *ioctl; WINE_TRACE("\n"); if ((mgr = open_mountmgr()) == INVALID_HANDLE_VALUE) return; /* add each drive and remove as we go */ for(i = 0; i < 26; i++) { if (!drives[i].modified) continue; drives[i].modified = FALSE; len = sizeof(*ioctl); if (drives[i].in_use) { if (drives[i].unixpath) len += strlen(drives[i].unixpath) + 1; if (drives[i].device) len += strlen(drives[i].device) + 1; } if (!(ioctl = HeapAlloc( GetProcessHeap(), 0, len ))) continue; ioctl->size = len; ioctl->type = DRIVE_NO_ROOT_DIR; ioctl->letter = 'a' + i; ioctl->mount_point_offset = 0; ioctl->device_offset = 0; if (drives[i].in_use) { char *ptr = (char *)(ioctl + 1); ioctl->type = drives[i].type; if (drives[i].unixpath) { strcpy( ptr, drives[i].unixpath ); ioctl->mount_point_offset = ptr - (char *)ioctl; ptr += strlen(ptr) + 1; } if (drives[i].device) { strcpy( ptr, drives[i].device ); ioctl->device_offset = ptr - (char *)ioctl; } } if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_DEFINE_UNIX_DRIVE, ioctl, len, NULL, 0, NULL, NULL )) { set_drive_label( drives[i].letter, drives[i].label ); if (drives[i].in_use) set_drive_serial( drives[i].letter, drives[i].serial ); WINE_TRACE( "set drive %c: to %s type %u\n", 'a' + i, wine_dbgstr_a(drives[i].unixpath), drives[i].type ); } else WINE_WARN( "failed to set drive %c: to %s type %u err %u\n", 'a' + i, wine_dbgstr_a(drives[i].unixpath), drives[i].type, GetLastError() ); HeapFree( GetProcessHeap(), 0, ioctl ); } CloseHandle( mgr ); }
/*********************************************************************** * break_restart_execution * * Set the bp to the correct state to restart execution * in the given mode. */ void break_restart_execution(int count) { ADDRESS64 addr; enum dbg_line_status status; enum dbg_exec_mode mode, ret_mode; ADDRESS64 callee; void* linear; memory_get_current_pc(&addr); linear = memory_to_linear_addr(&addr); /* * This is the mode we will be running in after we finish. We would like * to be able to modify this in certain cases. */ ret_mode = mode = dbg_curr_thread->exec_mode; /* we've stopped on a xpoint (other than step over) */ if (dbg_curr_thread->stopped_xpoint > 0) { /* * If we have set a new value, then save it in the BP number. */ if (count != 0 && mode == dbg_exec_cont) { dbg_curr_process->bp[dbg_curr_thread->stopped_xpoint].skipcount = count; } /* If we've stopped on a breakpoint, single step over it (, then run) */ if (is_xpoint_break(dbg_curr_thread->stopped_xpoint)) mode = dbg_exec_step_into_insn; } else if (mode == dbg_exec_cont && count > 1) { dbg_printf("Not stopped at any breakpoint; argument ignored.\n"); } if (mode == dbg_exec_finish && be_cpu->is_function_return(linear)) { mode = ret_mode = dbg_exec_step_into_insn; } /* * See if the function we are stepping into has debug info * and line numbers. If not, then we step over it instead. * FIXME - we need to check for things like thunks or trampolines, * as the actual function may in fact have debug info. */ if (be_cpu->is_function_call(linear, &callee)) { status = symbol_get_function_line_status(&callee); #if 0 /* FIXME: we need to get the thunk type */ /* * Anytime we have a trampoline, step over it. */ if ((mode == EXEC_STEP_OVER || mode == EXEC_STEPI_OVER) && status == dbg_in_a_thunk) { WINE_WARN("Not stepping into trampoline at %p (no lines)\n", memory_to_linear_addr(&callee)); mode = EXEC_STEP_OVER_TRAMPOLINE; } #endif if (mode == dbg_exec_step_into_line && status == dbg_no_line_info) { WINE_WARN("Not stepping into function at %p (no lines)\n", memory_to_linear_addr(&callee)); mode = dbg_exec_step_over_line; } } if (mode == dbg_exec_step_into_line && symbol_get_function_line_status(&addr) == dbg_no_line_info) { dbg_printf("Single stepping until exit from function,\n" "which has no line number information.\n"); ret_mode = mode = dbg_exec_finish; } switch (mode) { case dbg_exec_cont: /* Continuous execution */ be_cpu->single_step(&dbg_context, FALSE); break_set_xpoints(TRUE); break; #if 0 case EXEC_STEP_OVER_TRAMPOLINE: /* * This is the means by which we step over our conversion stubs * in callfrom*.s and callto*.s. We dig the appropriate address * off the stack, and we set the breakpoint there instead of the * address just after the call. */ be_cpu->get_addr(dbg_curr_thread->handle, &dbg_context, be_cpu_addr_stack, &addr); /* FIXME: we assume stack grows as on an i386 */ addr.Offset += 2 * sizeof(unsigned int); dbg_read_memory(memory_to_linear_addr(&addr), &addr.Offset, sizeof(addr.Offset)); dbg_curr_process->bp[0].addr = addr; dbg_curr_process->bp[0].enabled = TRUE; dbg_curr_process->bp[0].refcount = 1; dbg_curr_process->bp[0].skipcount = 0; dbg_curr_process->bp[0].xpoint_type = be_xpoint_break; dbg_curr_process->bp[0].condition = NULL; be_cpu->single_step(&dbg_context, FALSE); break_set_xpoints(TRUE); break; #endif case dbg_exec_finish: case dbg_exec_step_over_insn: /* Stepping over a call */ case dbg_exec_step_over_line: /* Stepping over a call */ if (be_cpu->is_step_over_insn(linear)) { be_cpu->disasm_one_insn(&addr, FALSE); dbg_curr_process->bp[0].addr = addr; dbg_curr_process->bp[0].enabled = TRUE; dbg_curr_process->bp[0].refcount = 1; dbg_curr_process->bp[0].skipcount = 0; dbg_curr_process->bp[0].xpoint_type = be_xpoint_break; dbg_curr_process->bp[0].condition = NULL; be_cpu->single_step(&dbg_context, FALSE); break_set_xpoints(TRUE); break; } /* else fall through to single-stepping */ case dbg_exec_step_into_line: /* Single-stepping a line */ case dbg_exec_step_into_insn: /* Single-stepping an instruction */ be_cpu->single_step(&dbg_context, TRUE); break; default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); } dbg_curr_thread->step_over_bp = dbg_curr_process->bp[0]; dbg_curr_thread->exec_mode = ret_mode; }
HRESULT osx_write_icon(IStream *icoStream, int exeIndex, LPCWSTR icoPathW, const char *destFilename) { ICONDIRENTRY *iconDirEntries = NULL; int numEntries; struct { int index; int maxBits; BOOL scaled; } best[ICNS_SLOTS]; int indexes[ICNS_SLOTS]; int i; char *icnsPath = NULL; LARGE_INTEGER zero; HRESULT hr; hr = read_ico_direntries(icoStream, &iconDirEntries, &numEntries); if (FAILED(hr)) goto end; for (i = 0; i < ICNS_SLOTS; i++) { best[i].index = -1; best[i].maxBits = 0; } for (i = 0; i < numEntries; i++) { int slot; int width = iconDirEntries[i].bWidth ? iconDirEntries[i].bWidth : 256; int height = iconDirEntries[i].bHeight ? iconDirEntries[i].bHeight : 256; BOOL scaled = FALSE; WINE_TRACE("[%d]: %d x %d @ %d\n", i, width, height, iconDirEntries[i].wBitCount); if (height != width) continue; slot = size_to_slot(width); if (slot == -2) { scaled = TRUE; slot = CLASSIC_SLOT; } else if (slot < 0) continue; if (scaled && best[slot].maxBits && !best[slot].scaled) continue; /* don't replace unscaled with scaled */ if (iconDirEntries[i].wBitCount >= best[slot].maxBits || (!scaled && best[slot].scaled)) { best[slot].index = i; best[slot].maxBits = iconDirEntries[i].wBitCount; best[slot].scaled = scaled; } } /* remove the scaled icon if a larger unscaled icon exists */ if (best[CLASSIC_SLOT].scaled) { for (i = CLASSIC_SLOT+1; i < ICNS_SLOTS; i++) if (best[i].index >= 0 && !best[i].scaled) { best[CLASSIC_SLOT].index = -1; break; } } numEntries = 0; for (i = 0; i < ICNS_SLOTS; i++) { if (best[i].index >= 0) { indexes[numEntries] = best[i].index; numEntries++; } } icnsPath = heap_printf("%s.icns", destFilename); if (icnsPath == NULL) { hr = E_OUTOFMEMORY; WINE_WARN("out of memory creating ICNS path\n"); goto end; } zero.QuadPart = 0; hr = IStream_Seek(icoStream, zero, STREAM_SEEK_SET, NULL); if (FAILED(hr)) { WINE_WARN("seeking icon stream failed, error 0x%08X\n", hr); goto end; } hr = convert_to_native_icon(icoStream, indexes, numEntries, &CLSID_WICIcnsEncoder, icnsPath, icoPathW); if (FAILED(hr)) { WINE_WARN("converting %s to %s failed, error 0x%08X\n", wine_dbgstr_w(icoPathW), wine_dbgstr_a(icnsPath), hr); goto end; } end: HeapFree(GetProcessHeap(), 0, iconDirEntries); HeapFree(GetProcessHeap(), 0, icnsPath); return hr; }
/*********************************************************************** * symbol_get_lvalue * * Get the address of a named symbol. * Return values: * sglv_found: if the symbol is found * sglv_unknown: if the symbol isn't found * sglv_aborted: some error occurred (likely, many symbols of same name exist, * and user didn't pick one of them) */ enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno, struct dbg_lvalue* rtn, BOOL bp_disp) { struct sgv_data sgv; int i; char buffer[512]; DWORD opt; IMAGEHLP_STACK_FRAME ihsf; if (strlen(name) + 4 > sizeof(buffer)) { WINE_WARN("Too long symbol (%s)\n", name); return sglv_unknown; } sgv.num = 0; sgv.num_thunks = 0; sgv.name = &buffer[2]; sgv.do_thunks = DBG_IVAR(AlwaysShowThunks); if (strchr(name, '!')) { strcpy(buffer, name); } else { buffer[0] = '*'; buffer[1] = '!'; strcpy(&buffer[2], name); } /* this is a wine specific options to return also ELF modules in the * enumeration */ SymSetOptions((opt = SymGetOptions()) | 0x40000000); SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv); if (!sgv.num) { const char* ptr = strchr(name, '!'); if ((ptr && ptr[1] != '_') || (!ptr && *name != '_')) { if (ptr) { int offset = ptr - name; memcpy(buffer, name, offset + 1); buffer[offset + 1] = '_'; strcpy(&buffer[offset + 2], ptr + 1); } else { buffer[0] = '*'; buffer[1] = '!'; buffer[2] = '_'; strcpy(&buffer[3], name); } SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv); } } SymSetOptions(opt); /* now grab local symbols */ if (stack_get_current_frame(&ihsf) && sgv.num < NUMDBGV) { sgv.frame_offset = ihsf.FrameOffset; SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv); } if (!sgv.num) { dbg_printf("No symbols found for %s\n", name); return sglv_unknown; } /* recompute potential offsets for functions (linenumber, skip prolog) */ for (i = 0; i < sgv.num; i++) { if (sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL|SYMFLAG_LOCAL|SYMFLAG_THUNK)) continue; if (lineno == -1) { struct dbg_type type; ULONG64 addr; type.module = sgv.syms[i].lvalue.type.module; type.id = sgv.syms[i].sym_info; if (bp_disp && symbol_get_debug_start(&type, &addr)) sgv.syms[i].lvalue.addr.Offset = addr; } else { DWORD disp; IMAGEHLP_LINE il; BOOL found = FALSE; il.SizeOfStruct = sizeof(il); SymGetLineFromAddr(dbg_curr_process->handle, (DWORD)memory_to_linear_addr(&sgv.syms[i].lvalue.addr), &disp, &il); do { if (lineno == il.LineNumber) { sgv.syms[i].lvalue.addr.Offset = il.Address; found = TRUE; break; } } while (SymGetLineNext(dbg_curr_process->handle, &il)); if (!found) WINE_FIXME("No line (%d) found for %s (setting to symbol start)\n", lineno, name); } } if (sgv.num - sgv.num_thunks > 1 || /* many symbols non thunks (and showing only non thunks) */ (sgv.num > 1 && DBG_IVAR(AlwaysShowThunks)) || /* many symbols (showing symbols & thunks) */ (sgv.num == sgv.num_thunks && sgv.num_thunks > 1)) { return symbol_current_picker(name, &sgv, rtn); } /* first symbol is the one we want: * - only one symbol found, * - or many symbols but only one non thunk when AlwaysShowThunks is FALSE */ *rtn = sgv.syms[0].lvalue; return sglv_found; }
static BOOL SaveIconResAsPNG(const BITMAPINFO *pIcon, const char *png_filename, LPCWSTR commentW) { static const char comment_key[] = "Created from"; FILE *fp; png_structp png_ptr; png_infop info_ptr; png_text comment; int nXORWidthBytes, nANDWidthBytes, color_type = 0, i, j; BYTE *row, *copy = NULL; const BYTE *pXOR, *pAND = NULL; int nWidth = pIcon->bmiHeader.biWidth; int nHeight = pIcon->bmiHeader.biHeight; int nBpp = pIcon->bmiHeader.biBitCount; switch (nBpp) { case 32: color_type |= PNG_COLOR_MASK_ALPHA; /* fall through */ case 24: color_type |= PNG_COLOR_MASK_COLOR; break; default: return FALSE; } if (!libpng_handle && !load_libpng()) { WINE_WARN("Unable to load libpng\n"); return FALSE; } if (!(fp = fopen(png_filename, "w"))) { WINE_ERR("unable to open '%s' for writing: %s\n", png_filename, strerror(errno)); return FALSE; } nXORWidthBytes = 4 * ((nWidth * nBpp + 31) / 32); nANDWidthBytes = 4 * ((nWidth + 31 ) / 32); pXOR = (const BYTE*) pIcon + sizeof(BITMAPINFOHEADER) + pIcon->bmiHeader.biClrUsed * sizeof(RGBQUAD); if (nHeight > nWidth) { nHeight /= 2; pAND = pXOR + nHeight * nXORWidthBytes; } /* Apply mask if present */ if (pAND) { RGBQUAD bgColor; /* copy bytes before modifying them */ copy = HeapAlloc( GetProcessHeap(), 0, nHeight * nXORWidthBytes ); memcpy( copy, pXOR, nHeight * nXORWidthBytes ); pXOR = copy; /* image and mask are upside down reversed */ row = copy + (nHeight - 1) * nXORWidthBytes; /* top left corner */ bgColor.rgbRed = row[0]; bgColor.rgbGreen = row[1]; bgColor.rgbBlue = row[2]; bgColor.rgbReserved = 0; for (i = 0; i < nHeight; i++, row -= nXORWidthBytes) for (j = 0; j < nWidth; j++, row += nBpp >> 3) if (MASK(j, i)) { RGBQUAD *pixel = (RGBQUAD *)row; pixel->rgbBlue = bgColor.rgbBlue; pixel->rgbGreen = bgColor.rgbGreen; pixel->rgbRed = bgColor.rgbRed; if (nBpp == 32) pixel->rgbReserved = bgColor.rgbReserved; } } comment.text = NULL; if (!(png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) || !(info_ptr = ppng_create_info_struct(png_ptr))) goto error; if (setjmp(png_jmpbuf(png_ptr))) { /* All future errors jump here */ WINE_ERR("png error\n"); goto error; } ppng_init_io(png_ptr, fp); ppng_set_IHDR(png_ptr, info_ptr, nWidth, nHeight, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Set comment */ comment.compression = PNG_TEXT_COMPRESSION_NONE; comment.key = (png_charp)comment_key; i = WideCharToMultiByte(CP_UNIXCP, 0, commentW, -1, NULL, 0, NULL, NULL); comment.text = HeapAlloc(GetProcessHeap(), 0, i); WideCharToMultiByte(CP_UNIXCP, 0, commentW, -1, comment.text, i, NULL, NULL); comment.text_length = i - 1; ppng_set_text(png_ptr, info_ptr, &comment, 1); ppng_write_info(png_ptr, info_ptr); ppng_set_bgr(png_ptr); for (i = nHeight - 1; i >= 0 ; i--) ppng_write_row(png_ptr, (png_bytep)pXOR + nXORWidthBytes * i); ppng_write_end(png_ptr, info_ptr); ppng_destroy_write_struct(&png_ptr, &info_ptr); if (png_ptr) ppng_destroy_write_struct(&png_ptr, NULL); fclose(fp); HeapFree(GetProcessHeap(), 0, copy); HeapFree(GetProcessHeap(), 0, comment.text); return TRUE; error: if (png_ptr) ppng_destroy_write_struct(&png_ptr, NULL); fclose(fp); unlink(png_filename); HeapFree(GetProcessHeap(), 0, copy); HeapFree(GetProcessHeap(), 0, comment.text); return FALSE; }
/* * WFP is Windows File Protection, in NT5 and Windows 2000 it maintains a cache * of known good dlls and scans through and replaces corrupted DLLs with these * known good versions. The only programs that should install into this dll * cache are Windows Updates and IE (which is treated like a Windows Update) * * Implementing this allows installing ie in win2k mode to actually install the * system dlls that we expect and need */ static int ProcessWindowsFileProtection(void) { static const WCHAR winlogonW[] = {'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', 'W','i','n','d','o','w','s',' ','N','T','\\', 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 'W','i','n','l','o','g','o','n',0}; static const WCHAR cachedirW[] = {'S','F','C','D','l','l','C','a','c','h','e','D','i','r',0}; static const WCHAR dllcacheW[] = {'\\','d','l','l','c','a','c','h','e','\\','*',0}; static const WCHAR wildcardW[] = {'\\','*',0}; WIN32_FIND_DATAW finddata; HANDLE find_handle; BOOL find_rc; DWORD rc; HKEY hkey; LPWSTR dllcache = NULL; if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, winlogonW, &hkey )) { DWORD sz = 0; if (!RegQueryValueExW( hkey, cachedirW, 0, NULL, NULL, &sz)) { sz += sizeof(WCHAR); dllcache = HeapAlloc(GetProcessHeap(),0,sz + sizeof(wildcardW)); RegQueryValueExW( hkey, cachedirW, 0, NULL, (LPBYTE)dllcache, &sz); strcatW( dllcache, wildcardW ); } } RegCloseKey(hkey); if (!dllcache) { DWORD sz = GetSystemDirectoryW( NULL, 0 ); dllcache = HeapAlloc( GetProcessHeap(), 0, sz * sizeof(WCHAR) + sizeof(dllcacheW)); GetSystemDirectoryW( dllcache, sz ); strcatW( dllcache, dllcacheW ); } find_handle = FindFirstFileW(dllcache,&finddata); dllcache[ strlenW(dllcache) - 2] = 0; /* strip off wildcard */ find_rc = find_handle != INVALID_HANDLE_VALUE; while (find_rc) { static const WCHAR dotW[] = {'.',0}; static const WCHAR dotdotW[] = {'.','.',0}; WCHAR targetpath[MAX_PATH]; WCHAR currentpath[MAX_PATH]; UINT sz; UINT sz2; WCHAR tempfile[MAX_PATH]; if (strcmpW(finddata.cFileName,dotW) == 0 || strcmpW(finddata.cFileName,dotdotW) == 0) { find_rc = FindNextFileW(find_handle,&finddata); continue; } sz = MAX_PATH; sz2 = MAX_PATH; VerFindFileW(VFFF_ISSHAREDFILE, finddata.cFileName, windowsdir, windowsdir, currentpath, &sz, targetpath, &sz2); sz = MAX_PATH; rc = VerInstallFileW(0, finddata.cFileName, finddata.cFileName, dllcache, targetpath, currentpath, tempfile, &sz); if (rc != ERROR_SUCCESS) { WINE_WARN("WFP: %s error 0x%x\n",wine_dbgstr_w(finddata.cFileName),rc); DeleteFileW(tempfile); } /* now delete the source file so that we don't try to install it over and over again */ lstrcpynW( targetpath, dllcache, MAX_PATH - 1 ); sz = strlenW( targetpath ); targetpath[sz++] = '\\'; lstrcpynW( targetpath + sz, finddata.cFileName, MAX_PATH - sz ); if (!DeleteFileW( targetpath )) WINE_WARN( "failed to delete %s: error %u\n", wine_dbgstr_w(targetpath), GetLastError() ); find_rc = FindNextFileW(find_handle,&finddata); } FindClose(find_handle); HeapFree(GetProcessHeap(),0,dllcache); return 1; }