I am writing a Win32 app (extract.exe) to list or extract ICONs or other resources in a module's resources (EXE or DLL). The app is written in C. It fails on 'FindResource()', I believe because of an incorrect name. The target app (app.exe) contains the following in it's RC script (app.rc):
MYICON ICON DISCARDABLE "app.ico"
MYRCDATA RCDATA DISCARDABLE "hello.txt"
I've examined the resources of app.exe with various third-party tools and my own apps: the resource name of the icon is displayed a "1" rather than "MYICON", but the name of the RCDATA correctly shows as "MYRCDATA".
I've confirmed that "app.ico" is a valid .ico file but still no joy.
What am I missing here?
Notes: I'm running win10/64 on a Dell machine and compiling with MS Visual C.
I finally figured this out. Apparently, the resource compiler splits an icon file into two parts: (1) an "icon directory" (aka "RT_GROUP_ICON") and (2) the icon itself. The directory contains a 6-byte header and one or more 16-byte entries that include the integer "ID" of the actual icon (1 in my case). The format of directory entries is:
typedef struct // This is the Directory Entry stored in resources
{
BYTE Width;
BYTE Height;
BYTE Colors;
BYTE Reserved;
WORD Planes;
WORD BitsPerPixel;
DWORD ImageSize;
WORD ResourceID
} IconDirResEntry, *PIconDirResEntry;
A good description of this can be found in
https://www.codeguru.com/cpp/w-p/win32/tutorials/article.php/c12873/Hacking-Icon-Resources.htm
In my case, resource "MYICON" is the RT_GROUP_ICON icon directory which contains ID value of "1".
Related
On Windows 7, I developed a shell namespace extension (NSE) that presents a hierarchy of data that is very similar to a file system. Its junction point is the Desktop. I am able to click the [+] of each node in the tree control of Windows Explorer to expand that node. When I click on a folder in the tree view, I see a list of "folders" and "files", as expected, in the view presented by DefView. If I double-click on a "file", DefView dutifully invokes my corresponding IShellFolder::CreateViewObject to ask for IContextMenu, then eventually invokes IContextMenu::InvokeCommand, at which point I execute ShellExecuteEx with lpClass set to the extension of the "file". Explorer then dutifully launches the appropriate EXE application according to the "file" extension with my weird "file" path supplied as a command-line argument. However, if I double-click on one of my "folders" in the DefView, Explorer refuses to browse into the folder. An analysis of the call stack reveals that Explorer is trying to do some type of zone-checking on my weird "file" paths. I tried fiddling with Control Panel->Internet Options->Security zones, by adding my weird "file" paths to various zones, but that did not work. I can see from the call stack that there are two zone checks: a primary and a secondary. I guess I could brute-force my way around this, but I would like to know the sanctioned way to get past these zone-checks, or, rather, to get Explorer to browse into my "folders". Strangely, the IFileDialog does not have this problem, and browses into my "folders" without hesitation. I also tried adding the following code to my IShellFolderView::MessageSFVCB:
switch (uMsg)
{
case SFVM_GETZONE:
{
DWORD zone = URLZONE_TRUSTED;
* ((DWORD *)lParam) = zone;
}
return S_OK;
...
That did not help.
I also have a strong feeling my drag-and-drop will be blocked for the same underlying reason.
Any ideas?
Here is (partial) call stack:
MyDLL.dll!MyShellFolder::GetAttributesOf(unsigned int uCount, const _ITEMIDLIST * * aPidls, unsigned long * pdwAttributes) Line 385 C++
shell32.dll!CShellItem::GetAttributes(unsigned long,unsigned long *) Unknown
shell32.dll!CDefView::_SelectionHasFolderJunction(void) Unknown
shell32.dll!CDefView::_ZoneCheckFrame(unsigned long,int) Unknown
shell32.dll!CDefView::_InvokeContextMenuVerbOnSelectionWorker(char const *,unsigned int) Unknown
shell32.dll!CDefView::_InvokeContextMenuVerbOnSelection(char const *,unsigned int) Unknown
shell32.dll!CDefView::OnActivateSelection(unsigned long) Unknown
ExplorerFrame.dll!UIItemsView::WndProc(struct HWND__ *,unsigned int,unsigned __int64,__int64) Unknown
I am struggling to understand what may be causing the issue in my case.
I am using
ShellExecuteW('open', 'explorer.exe', '/select,[file_name]', None, win32con.SW_SHOW)
What I am trying to do is open the file in the OS, highlight it, and bring the File Explorer to the foreground. This works fine for most cases, but when I try to open a file that exceeds the MAX_PATH limit (260 characters), the file doesn't open, and instead it takes me to the "My Files" page.
I have tried prepending "\\?\" to the beginning of my file name, because that is what other Stack Overflow posts said to do with regards to overriding the MAX_PATH limit, but it has not changed the situation.
Does the ShellExecuteW function not allow for files that exceed MAX_PATH? And, if so, is there any workaround I could use?
I read some cases, about this issue. Find this article:Long Paths in .NET, Part 1 of 3 [Kim Hamilton]
If you prefix the file name with "\?\" and call the Unicode versions of the Windows APIs, then you can use file names up to 32K characters in length. In other words, the \?\ prefix is a way to enable long paths while working with the Windows file APIs.
and:
Long paths with the \?\ prefix can be used in most of the file-related Windows APIs, but not all Windows APIs.
I also test ShellExcuteW with \\?\,it failed.
Working well with SHOpenFolderAndSelectItems
CoInitialize(NULL);
LPCWSTR file_name ;//Change the path according to your needs
PIDLIST_ABSOLUTE pidl;
if (SUCCEEDED(SHParseDisplayName(file_name, 0, &pidl, 0, 0)))
{
ITEMIDLIST idNull = { 0 };
LPCITEMIDLIST pidlNull[1] = { &idNull };
SHOpenFolderAndSelectItems(pidl, 1, pidlNull, 0);
ILFree(pidl);
}
Note:CoInitialize or CoInitializeEx must be called before using SHOpenFolderAndSelectItems. Not doing so causes SHOpenFolderAndSelectItems to fail.
I am trying to identify when a file is PNG or JPG to apply it as a wallpaper. I am using the SHGetFileInfo to get the type name with the .szTypeName variable, but I just realized that it changes if the OS is in another language.
This is my code:
SHFILEINFOW fileInfo;
UINT sizeFile = sizeof(fileInfo);
UINT Flags = SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES;
// Getting file info to find out if it has JPG or PNG format
SHGetFileInfoW(argv[1], 0, &fileInfo, sizeFile, Flags);
This is how I am validating:
if (wcscmp(fileInfo.szTypeName, L"JPG File") == 0)
{
//Code here
}
When the OS is in spanish, the value changes to "Archivo JPG" so I would have to validate against all language, and does not make sense.
Any idea what other function I can use?
This API is meant to be used to produce a user-facing string representation for known file types1). It is not meant to be used to implement code logic.
More importantly, it doesn't try to parse the file contents. It works off of the file extension alone. If you rename an Excel workbook MySpreadsheet.xlsx to MySpreadsheet.png, it will happily report, that this is a "PNG File".
The solution to your problem is simple: You don't have to do anything, other than filtering on the file extension. Use PathFindExtension (or PathCchFindExtension for Windows 8 and above) to get the file extension from a fully qualified path name.
This can fail, in case the user appended the wrong file extension. Arguably, this isn't something your application should fix, though.
As an aside, you pass SHGFI_USEFILEATTRIBUTES to SHGetFileInfoW but decided to not pass any file attributes (second argument) to the call. This is a bug. See What does SHGFI_USEFILEATTRIBUTES mean? for details.
1) It is the moral equivalent of SHGFI_DISPLAYNAME. The only thing you can do with display names is display them.
I need to add a watch in hexadecimal format in CLion.
ltoa(variable, 16) doesn't work, at least, on my system.
In Java/Python, I can have a workaround: write a custom toString()/__str__ for my class and have it displayed the way I need. gdb has p/x. How do I do it in CLion?
Edit: ltoa(variable, 16) works if I define ltoa in my code, as it's not always present in standard library.
set output-radix 16
You can set this as a default option in a file called .gdbinit, which you can put in your home directory, or the working directory from which you start GDB (project root, for instance).
They added hex view as an experimental feature: Hexadecimal view
To enable:
Invoke the Maintenance popup: press Ctrl+Alt+Shift+/, or call Help | Find Action and search for Maintenance. Choose Experimental features.
Select the cidr.debugger.value.numberFormatting.hex checkbox
Go to Settings / Preferences | Build, Execution, Deployment | Debugger | Data Views | C/C++ and set the checkbox Show hex values for numbers. Choose to have hexadecimal values displayed instead or alongside the original values.
Now the hexadecimal formatting is shown both in the Variables pane of the Debug tool window and in the editor's inline variables view.
...after refining the formulation, I see it.
I wrote my own char *lltoa(long long value, int radix) function. I can use it in watches now.
Update: in the respective feature request, Chris White found a workaround on OS X with lldb:
I decided to do a bit more digging and found a way to set lldb on OS X
to force HEX output for unsigned char data types:
type format add –format hex "unsigned char"
If you want to make this setting persistent you can also create a
.lldbinit file and add this command to it. Once you do this CLion
will display this data type in HEX format.
This makes ALL the variables of this type display in hex.
Update 2: My first workaround is pretty dirty, here's a better one.
You can assign formats to more specific types. The debugger keeps track of type inheritance. So, adding a hex format to uint8_t will not affect unsigned char. You can fine-tune the displays.
You can assign formats to structs also. Here's an example from my .lldbinit:
type format add --format dec int32_t
# https://lldb.llvm.org/varformats.html
type summary add --summary-string "addr=${var.address} depth=${var.depth}" Position
I am trying to write a code which is supposed to print out the names of all the imported dll's in the exe by using the 'name' field of the IMAGE_IMPORT_DESCRIPTOR structure in the .idata section of the exe, but the program seems to be getting stuck in an infinite loop. Can someone please tell me how to get the names printed out correctly...
#include<iostream>
#include<Windows.h>
#include<stdio.h>
#include<WinNT.h>
int main()
{
FILE *fp;
int i;
if((fp = fopen("c:\\Linked List.exe","rb"))==NULL)
std::cout<<"unable to open";
IMAGE_DOS_HEADER imdh;
fread(&imdh,sizeof(imdh),1,fp);
fseek(fp,imdh.e_lfanew,0);
IMAGE_NT_HEADERS imnth;
fread(&imnth,sizeof(imnth),1,fp);
IMAGE_SECTION_HEADER *pimsh;
pimsh = (IMAGE_SECTION_HEADER *)malloc(sizeof(IMAGE_SECTION_HEADER) * imnth.FileHeader.NumberOfSections);
long t;
fread(pimsh,sizeof(IMAGE_SECTION_HEADER),imnth.FileHeader.NumberOfSections,fp);
for(i=0;i<imnth.FileHeader.NumberOfSections;i++)
{
if(!strcmp((char *)pimsh->Name,".idata"))
t = pimsh->PointerToRawData;
pimsh++;
}
fseek(fp,t,0);
IMAGE_IMPORT_DESCRIPTOR iid;
char c;
while(1)
{
fread(&iid,sizeof(iid),1,fp);
if(iid.Characteristics == NULL)
break;
t = ftell(fp);
fseek(fp,(long)iid.Name,0);
while(c=fgetc(fp))
printf("%c",c);
printf("\n");
fseek(fp,t,0);
}
}
There are several problems.
You can't assume the import section is called ".idata". You should locate the imports using IMAGE_OPTIONAL_HEADER.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].
Most offsets within a PE file are Relative Virtual Addresses (RVAs), not file offsets. To convert an RVA to an offset you need to determine which section the virtual address is in, then calculate an offset based on where the section is in the file. Specifically, the IMAGE_IMPORT_DESCRIPTOR.Name field contains an RVA, not a file offset.
Your code will be much simpler (and quicker) if you use a memory-mapped file rather than file I/O.
This MSDN article explains RVAs, the data directory, etc. It also includes pedump, an application with full source code for dumping PE files, which is a useful reference.
The answer by mox is right on all points, however I would also like to add another solution - load the file as an image to read the data.
This is achieved very simply using LoadLibraryEx with just one line of code.
Base = LoadLibraryEx("c:\Linked List.exe", 0, DONT_RESOLVE_DLL_REFERENCES);
This load and maps your executable as an image, so no need for opening/reading/mapping or converting rva to raw offsets.
With the DONT_RESOLVE_DLL_REFERENCES flag the image is uninitialized, so all import data is untouched, and entrypoint code is not executed. The executable is just mapped into memory.
You can simply use Base + Rva to find imported dll name - or any other kind of PE information.
Free the executable image after use with FreeLibrary(Base)