diff --git a/dll/win32/shell32/wine/control.c b/dll/win32/shell32/wine/control.c index 6632d19632f..82fd0ddd7c0 100644 --- a/dll/win32/shell32/wine/control.c +++ b/dll/win32/shell32/wine/control.c @@ -42,6 +42,40 @@ WINE_DEFAULT_DEBUG_CHANNEL(shlctrl); +#ifdef __REACTOS__ +// Function to get icon dimensions from an HICON handle +BOOL GetIconDims(HICON hIcon, int *width, int *height) { + ICONINFO ii; + BOOL ret = GetIconInfo(hIcon, &ii); + if (ret) + { + BITMAP bmp; + BOOL res; + // Retrieve + res = GetObject(ii.hbmMask, sizeof(bmp), &bmp) == sizeof(bmp); + if (res) + { + *width = bmp.bmWidth; + // Check for color or mono + *height = ii.hbmColor ? bmp.bmHeight : bmp.bmHeight / 2; + } + else + ERR("GetObject failed\n"); + + // We need to delete the extra objects now + if (ii.hbmMask) { + DeleteObject(ii.hbmMask); + } + if (ii.hbmColor) { + DeleteObject(ii.hbmColor); + } + } + else + ERR("GetIconInfo failed\n"); + return ret; +} +#endif + void Control_UnloadApplet(CPlApplet* applet) { unsigned i; @@ -69,8 +103,26 @@ CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) CPlApplet* applet; DWORD len; unsigned i; +#ifdef __REACTOS__ + UINT ret; + HICON hIconID[2] = { 0 }; + UINT pIconID[2] = { 0 }; + INT cx1 = 0, cy1 = 0, cx2 = 0,cy2 = 0; + BOOL IconDimsOK = FALSE; + + CPLINFO info = { 0 }; + /* Since we do not know if our CPL will use ASCII or Unicode, + * we use a union that can handle both and check the size after + * it is read from the CPL to determine which is returned. */ + union + { + NEWCPLINFOA NewCplInfoA; + NEWCPLINFOW NewCplInfoW; + } Newcpl = { 0 }; +#else CPLINFO info; NEWCPLINFOW newinfo; +#endif if (!(applet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*applet)))) return applet; @@ -125,8 +177,15 @@ CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) FIELD_OFFSET( CPlApplet, info[applet->count] )); for (i = 0; i < applet->count; i++) { +#ifdef __REACTOS__ + ZeroMemory(&Newcpl, sizeof(Newcpl)); + /* Set our defaults to CPL_DYNAMIC_RES */ + info.idIcon = info.idName = info.idInfo = CPL_DYNAMIC_RES; + info.lData = 0; +#else ZeroMemory(&newinfo, sizeof(newinfo)); newinfo.dwSize = sizeof(NEWCPLINFOA); +#endif applet->info[i].helpfile[0] = 0; /* proc is supposed to return a null value upon success for * CPL_INQUIRE and CPL_NEWINQUIRE @@ -136,6 +195,11 @@ CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) applet->proc(hWnd, CPL_INQUIRE, i, (LPARAM)&info); applet->info[i].data = info.lData; #ifdef __REACTOS__ + if (info.idIcon == 0 && info.idName == 0 && + info.idInfo == 0 && !info.lData) + { + ERR("'%S' does not implement CPL_INQUIRE\n", cmd); + } applet->info[i].idIcon = info.idIcon; #endif @@ -164,6 +228,67 @@ CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) if ((info.idIcon == CPL_DYNAMIC_RES) || (info.idName == CPL_DYNAMIC_RES) || (info.idInfo == CPL_DYNAMIC_RES)) { +#ifdef __REACTOS__ + applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&Newcpl); + applet->info[i].data = Newcpl.NewCplInfoA.lData; + + if (!Newcpl.NewCplInfoA.hIcon) + WARN("couldn't get icon for applet %u\n", i); + + /* This is CPL_NEWINQUIRE, so use the HICON value as icon value */ + applet->info[i].icon = Newcpl.NewCplInfoA.hIcon; + + /* We get the Icon Group number which contains Icon #1. This + * uses a ReactOS specific flag LR_GROUPFROMICONID which is used + * to request the group number of the specific icon number. The + * 2nd param is the negative first icon number and the flags tell + * the function to return the group numbers in pIconID[x]. The + * MAKELONG parameters request both 32x32 AND 16x16 icons. */ + ret = PrivateExtractIconsW(cmd, -1, MAKELONG(32, 16), MAKELONG(32, 16), + hIconID, pIconID, 2, LR_GROUPFROMICONID); + + IconDimsOK = GetIconDims(hIconID[0], &cx1, &cy1); + if (!IconDimsOK) + { + ERR("GetIconDims failed fir hIconID[0]"); + } + + if (!(GetIconDims(hIconID[1], &cx2, &cy2))) + { + ERR("GetIconDims failed fir hIconID[1]"); + } + + if (ret > 0 && pIconID[0] && (cx1 == 32 && cy1 == 32) && IconDimsOK) + applet->info[i].idIcon = pIconID[0]; + else + ERR("Icon for '%S' was not found\n", cmd); + + if (Newcpl.NewCplInfoA.dwSize == sizeof(NEWCPLINFOW)) + { + memcpy(applet->info[i].name, Newcpl.NewCplInfoW.szName, + sizeof(Newcpl.NewCplInfoW.szName)); + + memcpy(applet->info[i].info, Newcpl.NewCplInfoW.szInfo, + sizeof(Newcpl.NewCplInfoW.szInfo)); + + memcpy(applet->info[i].helpfile, Newcpl.NewCplInfoW.szHelpFile, + sizeof(Newcpl.NewCplInfoW.szHelpFile)); + } + else + { + MultiByteToWideChar(CP_ACP, 0, Newcpl.NewCplInfoA.szName, + ARRAYSIZE(Newcpl.NewCplInfoA.szName), + applet->info[i].name, ARRAYSIZE(applet->info[i].name)); + + MultiByteToWideChar(CP_ACP, 0, Newcpl.NewCplInfoA.szInfo, + ARRAYSIZE(Newcpl.NewCplInfoA.szInfo), + applet->info[i].info, ARRAYSIZE(applet->info[i].info)); + + MultiByteToWideChar(CP_ACP, 0, Newcpl.NewCplInfoA.szHelpFile, + ARRAYSIZE(Newcpl.NewCplInfoA.szHelpFile), + applet->info[i].helpfile, + ARRAYSIZE(applet->info[i].helpfile)); +#else applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&newinfo); applet->info[i].data = newinfo.lData; @@ -190,6 +315,7 @@ CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) sizeof(((LPNEWCPLINFOA)&newinfo)->szHelpFile) / sizeof(CHAR), applet->info[i].helpfile, sizeof(applet->info[i].helpfile) / sizeof(WCHAR)); +#endif } } } diff --git a/sdk/include/psdk/winuser.h b/sdk/include/psdk/winuser.h index 7602917570f..ac7f99c7b71 100644 --- a/sdk/include/psdk/winuser.h +++ b/sdk/include/psdk/winuser.h @@ -1105,6 +1105,7 @@ extern "C" { #define LR_DEFAULTSIZE 64 #define LR_LOADREALSIZE 128 #define LR_VGACOLOR 128 +#define LR_GROUPFROMICONID 0x0400 /* REACTOS Specific Only */ #define LR_LOADMAP3DCOLORS 4096 #define LR_CREATEDIBSECTION 8192 #define LR_COPYFROMRESOURCE 0x4000 diff --git a/win32ss/user/user32/misc/exticon.c b/win32ss/user/user32/misc/exticon.c index 04d129ea0b0..0f0cd74935c 100644 --- a/win32ss/user/user32/misc/exticon.c +++ b/win32ss/user/user32/misc/exticon.c @@ -310,6 +310,7 @@ static UINT ICO_ExtractIconExW( DWORD fsizeh,fsizel; #ifdef __REACTOS__ WCHAR szExpandedExePath[MAX_PATH]; + UINT groupno; #endif WCHAR szExePath[MAX_PATH]; DWORD dwSearchReturn; @@ -645,6 +646,14 @@ static UINT ICO_ExtractIconExW( const IMAGE_RESOURCE_DIRECTORY_ENTRY *xresent; ULONG size; UINT i; +#ifdef __REACTOS__ + UINT j; + LPicoICONDIR lpiID = NULL; + BYTE *pCIDir = 0; + ULONG uSize = 0; + UINT16 iconCount = 0; + CURSORICONDIR *icodir; +#endif rootresdir = RtlImageDirectoryEntryToData((HMODULE)peimage, FALSE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size); if (!rootresdir) @@ -686,11 +695,74 @@ static UINT ICO_ExtractIconExW( while(nId is is the Index Number of the group */ + if (!(flags & LR_GROUPFROMICONID)) + { + if(xprdeTmp->Id == iId) + { + nIconIndex = n; + break; + } + } + else + { + pIconId[0] = xprdeTmp->Id; + nIconIndex = n; + + /* starting from specified index */ + xresent = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(icongroupresdir+1) + nIconIndex; + + const IMAGE_RESOURCE_DIRECTORY *resdir; + + /* go down this resource entry, name */ + resdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)rootresdir + xresent->OffsetToDirectory); + + /* default language (0) */ + resdir = find_entry_default(resdir,rootresdir); + igdataent = (const IMAGE_RESOURCE_DATA_ENTRY*)resdir; + + /* lookup address in mapped image for virtual address */ + igdata = RtlImageRvaToVa(RtlImageNtHeader((HMODULE)peimage), (HMODULE)peimage, igdataent->OffsetToData, NULL); + if (!igdata) + { + ERR("no matching real address for icongroup!\n"); + goto end; /* failure */ + } + + pCIDir = ICO_GetIconDirectory(igdata, &lpiID, &uSize); + if (pCIDir) + { + iconCount = lpiID->idCount; + /* This is really a CURSORICONDIR pointer */ + icodir = (CURSORICONDIR*)igdata; + + /* Check all of the icons in this group for being iId */ + for (j=0; j < iconCount; j++) + { + /* Icon index is icodir->idEntries[j].wResId */ + if (iId == icodir->idEntries[j].wResId) + { + /* when we match it shows that this icon ID # + * is in this group number which is what we want */ + groupno = xprdeTmp->Id; + ret = 1; // Return success for function + nIcons = 2; + pIconId[j] = xprdeTmp->Id; + goto iconextract; + } + } + } + HeapFree(GetProcessHeap(), 0, pCIDir); + + } +#else if(xprdeTmp->Id == iId) { nIconIndex = n; break; } +#endif n++; xprdeTmp++; } @@ -739,6 +811,9 @@ static UINT ICO_ExtractIconExW( if (cx2 && cy2) pIconId[++i] = LookupIconIdFromDirectoryEx(igdata, TRUE, cx2, cy2, flags); } +#ifdef __REACTOS__ +iconextract: +#endif if (!(iconresdir=find_entry_by_id(rootresdir,LOWORD(RT_ICON),rootresdir))) { WARN("No Iconresourcedirectory!\n"); @@ -806,10 +881,25 @@ static UINT ICO_ExtractIconExW( { RetPtr[0] = CreateIconFromResourceEx(idata, igdataent->Size, TRUE, 0x00030000, cx1, cy1, flags); + if (RetPtr[0]) + { + ret = 1; // Set number of icons found + if (flags & LR_GROUPFROMICONID) + pIconId[0] = groupno; + } + if (cx2 && cy2) - RetPtr[1] = CreateIconFromResourceEx(idata, idataent->Size, + { + RetPtr[1] = CreateIconFromResourceEx(idata, igdataent->Size, TRUE, 0x00030000, cx2, cy2, flags); - ret = 1; // Set number of icons found + if (RetPtr[1]) + { + ret++; // if two found then ret = 2 + if (flags & LR_GROUPFROMICONID) + pIconId[1] = groupno; + } + } + goto end; // Success so Exit } } @@ -834,9 +924,21 @@ static UINT ICO_ExtractIconExW( RetPtr[i]=0; continue; } +#ifdef __REACTOS__ + if (flags & LR_GROUPFROMICONID) + pIconId[i] = groupno; +#endif RetPtr[i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx1, cy1, flags); if (cx2 && cy2) +#ifdef __REACTOS__ + { RetPtr[++i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx2, cy2, flags); + if (flags & LR_GROUPFROMICONID) + pIconId[i] = groupno; + } +#else + RetPtr[++i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx2, cy2, flags); +#endif } ret = i; /* return number of retrieved icons */ } /* if(sig == IMAGE_NT_SIGNATURE) */