How to get version info from resources? - winapi

I have the Version Info in resources declared:
100 VERSIONINFO
FILEVERSION 1,0,0,2
PRODUCTVERSION 1,0,0,2
FILEOS VOS_NT
FILETYPE VFT_APP
{
BLOCK "StringFileInfo"
{
BLOCK "000004b0"
{
VALUE "FileDescription", "My application"
VALUE "FileVersion", "1.0.0.2"
VALUE "InternalName", "app.exe"
VALUE "LegalCopyright", "Copyright © 2012 by David."
VALUE "OriginalFilename", "app.exe"
VALUE "ProductName", "app"
VALUE "ProductVersion", "1.0.0.2"
VALUE "Assembly Version", "1.0.0.2"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0000 0x04B0
}
}
I am getting Version Info this way:
HRSRC hResInfo;
HGLOBAL hResData;
LPCVOID pRes;
UINT uLen;
VS_FIXEDFILEINFO *lpFfi;
hResInfo = FindResource(hInst, MAKEINTRESOURCE(100), RT_VERSION);
MessageBox(0, "FindResource", 0,0);
hResData = LoadResource(hInst, hResInfo);
MessageBox(0, "LoadResource", 0,0);
pRes = LockResource(hResData);
MessageBox(0, "LockResource", 0,0);
VerQueryValue(pRes, "\\" ,(LPVOID*)&lpFfi, &uLen);
MessageBox(0, "VerQueryValue", 0,0);
FreeResource(hResData);
DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;
DWORD dwLeftMost = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
DWORD dwSecondRight = HIWORD(dwFileVersionLS);
DWORD dwRightMost = LOWORD(dwFileVersionLS);
In function VerQueryValue is an error, because program breaks (MessageBox with text "VerQueryValue" doesn't show) and Visual C++ shows me the following message:
First-chance exception at 0x77bf15a5 in ProxyCU.exe: 0xC0000005:
Access violation writing location 0x00483192.
How to repair this code?
Regards, David

VerQueryValue() cannot access version info from the original resource directly. You must make a copy of the resource in memory, then pass that memory to VerQueryValue() instead. The reason is because VerQueryValue() is designed to work with GetFileVersionInfo(), which requires a user-allocated block of writable memory and performs certain fixups within that memory. Accessing the VS_FIXEDFILEINFO struct does not require the fixups, but the memory block must still be writable. You cannot pass the original resource directly to VerQueryValue() because it is read-only memory.
Try this instead:
HRSRC hResInfo;
DWORD dwSize;
HGLOBAL hResData;
LPVOID pRes, pResCopy;
UINT uLen;
VS_FIXEDFILEINFO *lpFfi;
hResInfo = FindResource(hInst, MAKEINTRESOURCE(100), RT_VERSION);
dwSize = SizeofResource(hInst, hResInfo);
hResData = LoadResource(hInst, hResInfo);
pRes = LockResource(hResData);
pResCopy = LocalAlloc(LMEM_FIXED, dwSize);
CopyMemory(pResCopy, pRes, dwSize);
FreeResource(hResData);
VerQueryValue(pResCopy, TEXT("\\"), (LPVOID*)&lpFfi, &uLen);
DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;
DWORD dwLeftMost = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
DWORD dwSecondRight = HIWORD(dwFileVersionLS);
DWORD dwRightMost = LOWORD(dwFileVersionLS);
LocalFree(pResCopy);
UPDATE: this only works if you access the VS_FIXEDFILEINFO struct only. If you need to access any other values, you must use GetFileVersionInfo(). Per Raymond Chen's blog:
The first parameter to VerQueryValue really must be a buffer you obtained from GetFileVersionInfo
The documentation says that the first parameter to VerQueryValue must be a buffer returned by the GetFileVersionInfo function for a reason. The buffer returned by GetFileVersionInfo is an opaque data block specifically formatted so that VerQueryValue will work. You're not supposed to look inside that buffer, and you certainly can't try to "obtain the data some other way". Because if you do, VerQueryValue will look for something in a buffer that is not formatted in the manner the function expects.

The above would create a heap corruption error message in debug mode, such as "Free Heap block b753e70 modified at b753ed4 after it was freed". Someone has posted this problem many years ago at http://microsoft.public.win32.programmer.kernel.narkive.com/mqoHgVwM/verqueryvalue-bug. It is still hapenning today. One can make the message disappear by making dwSize sufficiently large, such as multiplying it by 4.

Related

LoadResource() returning hGlobal that I can't interrogate?

The following chunk of code results in err1 = 0 (success) and err2 = 6 (invalid handle).
HGLOBAL hGlobal = LoadResource(hInst, hrSrc);
INT err1 = GetLastError();
UINT gflags = GlobalFlags(hGlobal);
INT err2 = GetLastError();
gflags has a value of 0x8000 which means GMEM_INVALID_HANDLE. I know that the resource exists and if I lock the memory, I get the data in the resource.
My question is why do I get an invalid handle result? Is the memory returned by LoadResource() a 'special' HGLOBAL that is really not what it seems?
The value returned by LoadResource is not really an HGLOBAL.
From the LoadResource documentation:
The return type of LoadResource is HGLOBAL for backward compatibility, not because the function returns a handle to a global memory block. Do not pass this handle to the GlobalLock or GlobalFree function. To obtain a pointer to the first byte of the resource data, call the LockResource function; to obtain the size of the resource, call SizeofResource.
All you ever do with the value returned from LoadResource is pass it to LockResource and SizeofResource.
These functions are this way for reasons of backwards compatibility. Older versions of Windows did return real global memory blocks.

Unable to write to process memory

I am trying to fix a problem in code I am not familiar with. I have traced it down to call to WriteProcessMemory always failing with ERROR_INVALID_ADDRESS. I have no idea why it fails.I tried to check if my process has the required access to write to its child process using VirtualQUery and it does. Can anyone shed some light on this? The code path is extremely convoluted so I have skipped a lot of it. Please let me know if left out any info.
CreateProcessAsUserW(hToken, exe, cmd_line,
NULL, // No security attribute.
NULL, // No thread attribute.
false, // do not inherit handles
CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | EXTENDED_STARTUPINFO_PRESENT | CREATE_BREAKAWAY_FROM_JOB, // start suspended, extended startup info, break out of job
NULL, // Use the environment of the caller
NULL, // Use current directory of the caller.
&si,
&pi);
/*
....lots of work here
*/
void* address = {...};
void* var = address; // note this line
SIZE_T written;
if(!WriteProcessMemory( pi.handle,
var, address, // not completely sure what it is doing here - writing contents of address to address of var?
size, &written))
{
DWORD error = GetLastError(); // ERROR_INVALID_ADDRESS
MEMORY_BASIC_INFORMATION buffer;
SIZE_T num = VirtualQuery(address,&buffer,sizeof(MEMORY_BASIC_INFORMATION));
if(num > 0)
{
DWORD access = buffer.AllocationProtect; // PAGE_EXECUTE_WRITECOPY
DWORD state = buffer.State; // MEM_COMMIT
DWORD type = buffer.Type;
}
}
This is a 32-bit process running on 64-bit Win7.
You're performing a local VirtualQuery before trying to write into another process, whose address space may be wildly different.
If you want to be sure to have a valid pointer in that process's adress space, either you find where that process puts what interests you (good luck with ASLR), or you allocate some memory for you within that process (with, say VirtualAllocEx()).
Note: If you actually want shared memory, you should use CreateFileMapping(INVALID_HANDLE_VALUE) instead.

cbClsExtra and cbWndExtra

I want more detailed information about cbClsExtra and cbWndExtra WNDCLASSEX members that are used in RegisterClassEx winapi.
MSDN says that this members can be used to set size of extra bytes that will be allocated for class and for each window instance accordingly.
MSDN says
The system initializes the bytes to zero.
1) Does this mean that bytes are initialized with zero value or system allocates zero (none) bytes by default?
2) The most important question is how to use this extra bytes (provide examples please with winapi used) and how they are used most common?
Thanks in advance.
Does this mean that bytes are initialized with zero value or system allocates zero (none) bytes by default?
initialization is always done on variables, so it means to sets the allocated extra memory to 0.
The most important question is how to use this extra bytes (provide
examples please with winapi used) and how they are used most common?
The only way to do this is via the GetClassLongPtr and GetWindowLongPtr functions, these functions are simple enough to not need examples (call Get* to get the value, and Set* set set the value, passing either the class ATOM or window HWND).
I guess this is a really old question and the person already went on with life, but I think it deserves a proper answer as I was struggling with it and the answer wasn't much help. Yes it stated how to set the extra memory and the ONLY functions to use; but much much more detail was NECESSARY.
You see, experience persons thinks things are obvious and common sense, but I beg to differ. Win32 API is not a very intuitive API. Once you learn it you get to understand certain patterns, but later discover that some parts of the API is very different from some. Example, Setting font for your window, is different from setting font in an Edit control; which is surprisingly very very different for Rich Edit Control.
Thus I always refer to MSDN documentation and when I cant get the information there; ask Stack Overflow.
///______MY SOLUTION _________
Here is how you use cbWndExtra, which is extra bytes you can allocate to each Window Instance of that class. I know not about cbClassExtra.
Note I use cbWndExtra as an alternative to GWL_USERDATA. With the latter I would create and new pointer to my special structure and set it to GWL_USERDATA. This struct has all state I need to manage the window object.
However I have been trying out cbWndExtra to avoid creating memory on the heap. For simple primitive variables.
Step 1. Create windowProc.def file. This contains enumerations and functions for accessing the window bytes in a type safe way.
#include <windows.h>
#define LINE_NUM_VIEW_WIDTH 0
#define CODE_EDITOR_EDITOR 0
#define CODE_EDITOR_LINE_VIEW (CODE_EDITOR_EDITOR + sizeof(HWND))
#define CODE_EDITOR_HEIGHT (CODE_EDITOR_LINE_VIEW + sizeof(HWND))
#define CODE_EDITOR_RESIZABLE (CODE_EDITOR_HEIGHT + sizeof(LONG))
#define LINE_NUMBER_VIEW_WND_EXTRA_BYTES sizeof(LONG)
#define CODE_EDITOR_WND_EXTRA_BYTES (CODE_EDITOR_RESIZABLE + sizeof(LONG))
#define getLineNumberViewWidth( hwnd) GetWindowLong(hwnd,LINE_NUM_VIEW_WIDTH)
#define setLineNumberViewWidth( hwnd, n) SetWindowLong(hwnd,LINE_NUM_VIEW_WIDTH,n)
#define getTextEditor( hwnd) ((HWND)GetWindowLongPtr(hwnd,CODE_EDITOR_EDITOR))
#define getLineNumberView( hwnd) ((HWND)GetWindowLongPtr(hwnd,CODE_EDITOR_LINE_VIEW))
#define setCodeEditorHeight(hwnd,n) SetWindowLong(hwnd,CODE_EDITOR_HEIGHT,n)
#define getCodeEditorHeight(hwnd) GetWindowLong(hwnd,CODE_EDITOR_HEIGHT)
#define isCodeEditorResizable(hwnd) GetWindowLong(hwnd,CODE_EDITOR_RESIZABLE)
#define setCodeEditorResizable(hwnd, yes) SetWindowLong(hwnd,CODE_EDITOR_RESIZABLE,yes)
Note the trick with GetWindowLong, GetWindowLongPtr. Use GetWindowLong for Long, int, bool, and the likes. Use GetWindowLongPtr for pointers. Also notice the Long in the name. the function returns sizeof(LONG) and stores sizeof(Long). And msdn states valid range is 0 to cbWndExtra - sizeof(Long). Thus even though you can allocate 1 byte of cbWndExtra, DONT! Allocate multiples of LONG. And also remember that GetWindowLongPtr stores and retrieves sizeof(LONG_PTR). valid range 0 - cbWndExtra - sizeof(LONG_PTR). LONG_PTR and LONG are different size on 64 bit windows.
It is really simple. GetWindowLong will always try retrieve Long. Thus if you allocate 12 bytes and try to retrieve index 10; that is a mistake as only 2 bytes can be retrieved. Maybe windows gives you a bly, but as far as I am concernes that is undefined behaviour. And I stay clear of undefined behaviour.
Note there is GetWindowWord as well. Never used it. There is no GetWindowByte, Short, Bool or any mechanism getting and setting 1 byte or 2 byte. Thus allocate one Long block for all your bools.
Step 2. create windowProc.cpp
#include <stdio.h>
#include "windowProc.def"
LRESULT CALLBACK windowProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
switch(msg)
{
case WM_CREATE:
setCodeEditorHeight(hwnd,100); // from windowProc.def
printf("%i",getCodeEditorHeight(hwnd)); // from windowProc.def
return 0;
default: return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
ATOM registerMainWindow()
{
WNDCLASSEX wincl = {0};
wincl.cbSize = sizeof(WNDCLASSEX);
wincl.hInstance = (HINSTANCE)0x400000;
wincl.lpszClassName = "JavWindowProc";
wincl.lpfnWndProc = windowProc;
wincl.hCursor = LoadCursor(NULL,IDC_IBEAM);
wincl.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
wincl.cbWndExtra = CODE_EDITOR_WND_EXTRA_BYTES; // Safely set the size with our enumeration from windowProc.def
return (LPCSTR)RegisterClassEx(&wincl);
}
HWND createMainWindow(const char *title,int width,int height)
{
static auto className = registerMainWindow();
return CreateWindowExA(
0, // Extended possibilites for variation
className,
title,
WS_CHILD,
0,0,width,height,
HWND_DESKTOP,
0,
(HINSTANCE)0x400000,
NULL // No Window Creation data// The alternative to cbWndExtra
);
}
Steps 3 Obviously create your main function with your message loop.
Hope this was a help to somebody.

Creating a file exceeding filepath limit

I have a test that creates a series of folders in a loop until it exceeds the MAX_PATH (260). This returns ERROR_PATH_NOT_FOUND(0x3). We have a build machine that runs this test but on the build machine it returns ERROR_FILENAME_EXCED_RANGE (0xce).
My machine is Windows 7 but the build machine is Vista. Could that be why they return different values? If not, does anyone know why this might happen?
EDIT: I am expecting to get an error, im testing a file system driver. I just do not understand why i am getting two different error codes from the same test on different machines.
Here is the code
homeDir << "C:\Users\me\TestFolder";
string childDir = "\\LongChildDirectoryName";
string dir = homeDir.str();
DWORD lastErr = ERROR_SUCCESS;
while(lastErr == ERROR_SUCCESS)
{
int len = dir.size();
if(len > (MAX_PATH - 12))
{
CuFail(tc, "Filepath greater than max allowed should be");
}
dir += childDir;
if(!CreateDirectory(dir.c_str(), NULL))
{
lastErr = GetLastError();
if (lastErr == ERROR_ALREADY_EXISTS)
lastErr = ERROR_SUCCESS;
}
}
CuAssert(tc, "Check error is ERROR_PATH_NOT_FOUND", lastErr == ERROR_PATH_NOT_FOUND);
The logic is flawed. If homeDir.str() returns a name that doesn't exist, the return value from CreateDirectory will be ERROR_PATH_NOT_FOUND. You can demonstrate the problem by simply doing this:
string childDir("\\LongChildDirectoryName");
string dir("foo");
The CreateDirectory call will then get the path foo\LongChildDirectoryName, and if foo doesn't exist, you get ERROR_PATH_NOT_FOUND. The fix is simply to add this before the while loop:
CreateDirectory(dir.c_str(), NULL);
You also need to move the length check after the strings have been concatenated, not before. Using the "\\?\" syntax Alex suggested would also be a good idea.
To use longer paths you need to use the "wide" version of CreateFile(), CreateFileW().
See this MSDN article on the topic:
HANDLE WINAPI CreateFile(
__in LPCTSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
);
lpFileName [in]
The name of the file or device to be created or opened.
In the ANSI version of this function, the name is limited to MAX_PATH characters.
To extend this limit to 32,767 wide characters, call the Unicode version of the
function and prepend "\\?\" to the path. For more information, see Naming Files,
Paths, and Namespaces.

DWORD and DWORD_PTR on 64 bit machine

There are few *_PTR types added to the Windows API in order to support Win64's 64bit addressing.
SetItemData(int nIndex,DWORD_PTR dwItemData)
This API works for both 64 and 32 bit machines when I pass second parameter as DWORD.
I want to know, if this particular API will fail on 64 bit machine, if I pass the second parameter as DWORD. How can I test the fail scenario?
Thanks,
Nikhil
The function will not fail if you pass a DWORD, because it fits into a DWORD_PTR. A pointer, however, is guaranteed to fit into a DWORD_PTR but not into a DWORD on 64-bit platforms.
Thus, this code is correct:
int *before_ptr = new int;
yourListBox.SetItemData(index, (DWORD_PTR) before_ptr);
int *after_ptr = (int *) yourListBox.GetItemData(index);
ASSERT(before_ptr == after_ptr); // Succeeds.
delete after_ptr; // Works.
But this code is wrong and will silently truncate the pointer to its lower 32 bits:
int *before_ptr = new int;
yourListBox.SetItemData(index, (DWORD) before_ptr);
int *after_ptr = (int *) yourListBox.GetItemData(index);
ASSERT(before_ptr == after_ptr); // Fails.
delete after_ptr; // Undefined behavior, might corrupt the heap.

Resources