My program's call to EnumWindows() returns FALSE and GetLastError() occasionally returns ERROR_ALREADY_EXISTS (#183, "Cannot create a file when that file already exists"). What does that error mean in that context?
Here is a code snippet:
static BOOL CALLBACK CollectTopLevelWindowsEnum(HWND hWnd, LPARAM lParam)
{
// This one is good
s_windows.push_back(hWnd);
return TRUE;
}
...
if (!EnumWindows(CollectTopLevelWindowsEnum, NULL)) {
DWORD lastError = GetLastError();
if (lastError != ERROR_SUCCESS) {
TRACE("EnumWindows failed: %d.\n", lastError);
}
}
Related
I want to extract some DropHandler code into a separate function, but have no idea how to do that while working with interface pointers or C++ in general. I want to get just the first item in DragEnter using a separate function.
HRESULT drop_handler::GetFirstItem(IDataObject* p_data_obj, IShellItemArray* items, IShellItem* first_item)
{
HRESULT hr = SHCreateShellItemArrayFromDataObject(p_data_obj, IID_PPV_ARGS(&items));
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
DWORD item_count;
items->GetCount(&item_count);
if (item_count != 1)
{
items->Release();
return E_INVALIDARG;
}
hr = items->GetItemAt(0, &first_item);
if (hr != ERROR_SUCCESS)
{
items->Release();
return E_INVALIDARG;
}
return ERROR_SUCCESS;
}
HRESULT drop_handler::DragEnter(IDataObject* p_data_obj, DWORD gtf_key_state, POINTL pt, DWORD* pdw_effect)
{
IShellItemArray* items = nullptr;
IShellItem* dragged_item = nullptr;
HRESULT hr = GetFirstItem(p_data_obj, items, dragged_item);
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
//...use dragged_item
This code attempt crashes Explorer big time. I'm not sure what kind of function signature and pointers I should be using to make it work.
Edit: Fixed answer per Anders
HRESULT drop_handler::GetFirstItem(IDataObject* p_data_obj, IShellItemArray*& items, IShellItem*& first_item)
{
HRESULT hr = SHCreateShellItemArrayFromDataObject(p_data_obj, IID_PPV_ARGS(&items));
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
DWORD item_count;
hr = items->GetCount(&item_count);
if (hr != ERROR_SUCCESS || item_count != 1)
{
items->Release();
return E_INVALIDARG;
}
hr = items->GetItemAt(0, &first_item);
if (hr != ERROR_SUCCESS)
{
items->Release();
return E_INVALIDARG;
}
return ERROR_SUCCESS;
}
HRESULT drop_handler::DragEnter(IDataObject* p_data_obj, DWORD gtf_key_state, POINTL pt, DWORD* pdw_effect)
{
IShellItemArray* items;
IShellItem* dragged_item;
HRESULT hr = GetFirstItem(p_data_obj, items, dragged_item);
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
//...use dragged_item
Your handling of IShellItemArray* and IShellItem* is wrong. GetFirstItem will free IShellItemArray* on failure but on success you will leak it and first_item will never be returned correctly. items and first_item in DragEnter will never be valid.
IShellItemArray* should probably be a local variable in GetFirstItem.
The IShellItem* first_item parameter needs to be IShellItem** first_item or IShellItem*& first_item so that the pointer value is returned correctly to the caller.
You never check the return value of GetCount.
Since you are having problems with pointers you might want to add some asserts to verify that your interface pointers are non-null before using them.
I am hooking the keys and writing them down to a file, everything works fine but when I make the console window hidden, I can not hook the keys and print to a file, how to get rid of this problem? Down below when I removed ShowWindow() function I am able to hook the keys but otherwise I am not. I see the process is still running on task manager by the way.
See my example code here:
KBDLLHOOKSTRUCT kbdSTRUCT;
int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE hprevious, LPSTR cmdline, int cmdshow ) {
HWND wnd;
wnd = GetConsoleWindow();
ShowWindow(wnd, FALSE);
HHOOK kbdHOOK;
kbdHOOK = SetWindowsHookEx(WH_KEYBOARD_LL, kbdProc, NULL, 0);
MSG msgg;
while(GetMessage(&msgg, NULL, 0, 0) > 0){
TranslateMessage(&msgg);
DispatchMessage(&msgg);
}
}
LRESULT CALLBACK kbdProc(int nCode, WPARAM wPar, LPARAM lPar){
if(nCode >= 0){
if(wPar == 256){
kbdSTRUCT = *(KBDLLHOOKSTRUCT *)lPar;
if(kbdSTRUCT.vkCode == 0x90){
//fprintf function here to write to a file
return CallNextHookEx(NULL, nCode, wPar, lPar);
}
}
}
}
Thank you so much
When using gcc, -mwindows will set the Windows subsystem, this way no console window will appear when entry point is WinMain
gcc myfile.c -mwindows -o myfile.exe
Use a global variable to store SetWindowsHookEx result and pass it kbdProc, use that in CallNextHookEx
#include <Windows.h>
#include <stdio.h>
HHOOK hhook = NULL;
LRESULT CALLBACK kbdProc(int nCode, WPARAM wPar, LPARAM lPar)
{
if(nCode >= 0) {
if(wPar == WM_KEYDOWN) { //or WM_KEYUP!
KBDLLHOOKSTRUCT *kb = (KBDLLHOOKSTRUCT*)lPar;
int c = kb->vkCode;
FILE *file = fopen("test", "a");
switch(c) {
case VK_NUMLOCK: fprintf(file, "VK_NUMLOCK\n"); break;
case VK_RETURN: fprintf(file, "\n"); break;
default: fprintf(file, "%c", c); break;
}
fclose(file);
}
}
return CallNextHookEx(hhook, nCode, wPar, lPar);
}
int APIENTRY WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int show)
{
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, kbdProc, NULL, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhook);
return 0;
}
Make sure to use the correct windows constants. For example ShowWindow(wnd, SW_HIDE) instead of ShowWindow(wnd, FALSE). WM_KEYUP instead of 256. Otherwise the code will be too confusing when you look at the next day. Other people will not understand it.
You need to examine the shift key in addition to VK_NUMLOCK to find upper/lower case letters ...
I've starting watching the handmade hero videos and I'm trying to make a win32 window but the CreateWindowEx() function keeps failing.
I checked the error code and I get 1407.
Code is below.
Thanks in advance.
#include <Windows.h>
LRESULT CALLBACK WindowProcedure(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
LRESULT result;
switch (uMsg)
{
case WM_ACTIVATEAPP:
{
OutputDebugStringA("The window is now active");
break;
}
case WM_SIZE:
{
OutputDebugStringA("The window is now being resized");
break;
}
case WM_CREATE:
{
OutputDebugStringA("The window has been created");
break;
}
default:
{
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
break;
}
}
return result;
};
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
WNDCLASS GameWindow;
GameWindow.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW;
GameWindow.lpfnWndProc = WindowProcedure;
GameWindow.hInstance = hInstance;
// HICON hIcon;
GameWindow.lpszClassName = "HandmadeHeroWindowClass";
RegisterClass(&GameWindow);
if (HWND GameWindowHandle = CreateWindowEx(
0,
GameWindow.lpszClassName,
"Handmade Hero",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
hInstance,
0
))
{
for (;;)
{
MSG message;
BOOL messageResult = GetMessage(&message, GameWindowHandle, 0, 0);
if (messageResult != 0)
{
DispatchMessage(&message);
}
else if (messageResult == 0)
{
break;
}
else
{
// ERROR
}
}
}
else
{
OutputDebugStringA("Couldn't create window");
}
DWORD error = GetLastError();
return 0;
};
Your window procedure returns an uninitialized variable in every path except for default:, this is undefined behavior and failure of window creation is entirely possible.
For WM_CREATE, the documentation says:
If an application processes this message, it should return zero to continue creation of the window.
As Michael noted in the comments, RegisterClass is failing. Same category of mistake, you're passing a WNDCLASS structure leaving most members uninitialized.
Thanks to Remy Lebeau for the answer, the problem was that my WNDCLASS had uninitialized values for all fields except those I changed, this caused the RegisterClass() to fail and consequently the CreateWindowEx() to fail.
I changed WNDCLASS declaration to this:
WNDCLASS GameWindow = {0};
Thanks to everyone who helped.
First of all some parts of the code are from Calling function in injected DLL but somewhere it doesn't work.
I have a question regarding DLL Injection: after I loaded the library into another process:
HANDLE InjectDLL(DWORD ProcessID, char *dllName)
{
HANDLE Proc;
char buf[50]={0};
LPVOID RemoteString, LoadLibAddy;
if(!ProcessID)
return NULL;
Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID);
if(!Proc)
{
sprintf(buf, "OpenProcess() failed: %d", GetLastError());
MessageBox(NULL, buf, "Loader", NULL);
return NULL;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(dllName), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Proc, (LPVOID)RemoteString, dllName, strlen(dllName), NULL);
HANDLE hThread = CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
if( hThread != 0 ) {
WaitForSingleObject( hThread, INFINITE );
GetExitCodeThread( hThread, ( LPDWORD )&hInjected );
CloseHandle( hThread );
}
CloseHandle(Proc);
return hThread != 0 ? Proc : NULL;
}
I wanted to call a function from inside that space:
void* GetPayloadExportAddr( LPCSTR lpPath, HMODULE hPayloadBase, LPCSTR lpFunctionName )
{
// Load payload in our own virtual address space
HMODULE hLoaded = LoadLibrary( lpPath );
if( hLoaded == NULL ) {
return NULL;
} else {
void* lpFunc = GetProcAddress( hLoaded, lpFunctionName );
DWORD dwOffset = (char*)lpFunc - (char*)hLoaded;
FreeLibrary( hLoaded );
return (void*)((DWORD)hPayloadBase + dwOffset);
}
}
BOOL InitPayload( HANDLE hProcess, LPCSTR lpPath, HMODULE hPayloadBase)
{
void* lpInit = GetPayloadExportAddr( lpPath, hPayloadBase, "Start" );
if( lpInit == NULL ) {
return FALSE;
}
else {
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)lpInit, (LPVOID) NULL, 0, NULL );
if( hThread == NULL ) {
return FALSE;
}
else {
CloseHandle( hThread );
}
}
return TRUE;
}
The GetPayloadExportAddr returns the Current Location from IDA (i guess that is the space where my function starts).
So the problem is at the InitPayload function when I try to create the new thread, it fails to do so and I don't know why.
My dll is the following:
extern "C"
{
__declspec(dllexport) void* Start(LPVOID param)
{
MessageBox(NULL, L"Start", L"Hello", MB_OK);
return NULL;
}
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
The thing is if I put the Start method at DLL_PROCESS_ATTACH it works, but otherwise it doesn't.
Your GetPayloadExportAddr() returns the address of the function in your local process. This address will not be the same in other processes if the base address of the module is different, which is common with DLL files which can be relocated if their PreferredImageBase is not available.
You should modify your GetPayloadExportAddr() function to return the offset. Then get the address of the module in the target process. Add these two together and that is the correct address for you to call in the target process.
Version 6.0 of the common controls (comctl32.dll) implements a new approach for subclassing controls that is not available on older versions of Windows. What is the best way to implement subclassing so that it works on systems that support either version of the common controls library?
First, there is an article on MSDN that discusses the changes that occured in subclassing controls between version 6.0 and prior that you should be familiar with.
The best way to maintain backwards compatibility is to create wrapper functions for subclassing controls. This will require you to dynamically load the functions that are required for subclassing controls on version 6 of comctl32.dll. Here is a rough example of how it can be done.
typedef BOOL (WINAPI *LPFN_SETWINDOWSUBCLASS)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
typedef LRESULT (WINAPI *LPFN_DEFSUBCLASSPROC)(HWND, UINT, WPARAM, LPARAM);
typedef BOOL (WINAPI *LPFN_REMOVEWINDOWSUBCLASS)(HWND, SUBCLASSPROC, UINT_PTR);
typedef BOOL (WINAPI *LPFN_INITCOMMONCONTROLSEX)(LPINITCOMMONCONTROLSEX);
typedef struct SubclassStruct {
WNDPROC Proc;
} SubclassStruct;
LPFN_SETWINDOWSUBCLASS SetWindowSubclassPtr = NULL;
LPFN_REMOVEWINDOWSUBCLASS RemoveWindowSubclassPtr = NULL;
LPFN_DEFSUBCLASSPROC DefSubclassProcPtr = NULL;
LPFN_INITCOMMONCONTROLSEX InitCommonControlsExPtr = NULL;
HMODULE ComCtlModule = NULL;
int Subclasser_Init(void)
{
INITCOMMONCONTROLSEX CommonCtrlEx = {0};
ComCtlModule = LoadLibrary("comctl32.dll");
if (ComCtlModule == NULL)
return FALSE;
SetWindowSubclassPtr = (LPFN_SETWINDOWSUBCLASS)GetProcAddress(ComCtlModule, "SetWindowSubclass");
RemoveWindowSubclassPtr = (LPFN_REMOVEWINDOWSUBCLASS)GetProcAddress(ComCtlModule, "RemoveWindowSubclass");
DefSubclassProcPtr = (LPFN_DEFSUBCLASSPROC)GetProcAddress(ComCtlModule, "DefSubclassProc");
InitCommonControlsExPtr = (LPFN_INITCOMMONCONTROLSEX)GetProcAddress(ComCtlModule, "InitCommonControlsEx");
if (InitCommonControlsExPtr != NULL)
{
CommonCtrlEx.dwSize = sizeof(CommonCtrlEx);
InitCommonControlsExPtr(&CommonCtrlEx);
}
return TRUE;
}
int Subclasser_Uninit(void)
{
if (ComCtlModule != NULL)
FreeLibrary(ComCtlModule);
return TRUE;
}
LRESULT CALLBACK Subclasser_SharedSubclassProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam, UINT_PTR SubclassId, DWORD_PTR RefData)
{
SubclassStruct *Subclass = (SubclassStruct *)SubclassId;
return CallWindowProc(Subclass->Proc, hWnd, Message, wParam, lParam);
}
int Subclasser_SetProc(HWND hWnd, WNDPROC Proc, WNDPROC *OriginalProc, void *Param)
{
SubclassStruct *Subclass = NULL;
int Result = TRUE;
SetLastError(0);
if (SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(UINT_PTR)Param) == 0)
{
if (GetLastError() > 0)
return FALSE;
}
if (SetWindowSubclassPtr!= NULL)
{
Subclass = (SubclassStruct*)malloc(sizeof(SubclassStruct));
Subclass->Proc = Proc;
*OriginalProc = (WNDPROC)Subclass;
Result = SetWindowSubclassPtr(hWnd, Subclasser_SharedSubclassProc, (UINT_PTR)Subclass, NULL);
}
else
{
*OriginalProc = (WNDPROC)(void *)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
SetLastError(0);
if (SetWindowLongPtr(hWnd, GWLP_WNDPROC, (__int3264)(intptr)Proc) == 0)
{
if (GetLastError() > 0)
Result = FALSE;
}
}
if (Result == FALSE)
return FALSE;
return TRUE;
}
int Subclasser_UnsetProc(HWND hWnd, WNDPROC Proc, WNDPROC *OriginalProc)
{
SubclassStruct *Subclass = NULL;
int Result = TRUE;
if (RemoveWindowSubclassPtr != NULL)
{
if (*OriginalProc != NULL)
{
Subclass = (SubclassStruct *)*OriginalProc;
Proc = Subclass->Proc;
}
Result = RemoveWindowSubclassPtr(hWnd, Subclasser_SharedSubclassProc, (UINT_PTR)Subclass);
free(Subclass);
}
else
{
SetLastError(0);
if (SetWindowLongPtr(hWnd, GWLP_WNDPROC, (__int3264)(UINT_PTR)*OriginalProc) == 0)
{
if (GetLastError() > 0)
Result = FALSE;
}
}
SetLastError(0);
if (SetWindowLongPtr(hWnd, GWLP_USERDATA, 0) == 0)
{
if (GetLastError() > 0)
Result = FALSE;
}
*OriginalProc = NULL;
if (Result == FALSE)
return FALSE;
return TRUE;
}
LRESULT Subclasser_DefProc(WNDPROC OriginalProc, HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
if (OriginalProc == NULL)
return DefWindowProc(hWnd, Message, wParam, lParam);
if (DefSubclassProcPtr != NULL)
return DefSubclassProcPtr(hWnd, Message, wParam, lParam);
return CallWindowProc(OriginalProc, hWnd, Message, wParam, lParam);
}
The only other example can be found in OpenJDK. The one disadvantage to it is that it uses the the WindowProc as the subclass ID which crashes if you are subclassing more than one control on a dialog with the same WindowProc function. In the example above, we allocate a new memory structure called SubclassStruct and pass it's address as the subclass ID which guarantees that each instance of the control you subclass will have a unique subclass ID.
If you are using the subclassing functions in multiple applications, some that use comctl32.dll < 6 and some that use comctl32.dll >= 6, you could detect which version of the common control library was loaded by getting comctl32.dll's file version information. This can be done through the use of GetModuleFileName and GetFileVersionInfo.
In addition, if you use SetWindowWord/GetWindowWord in the subclass callbacks with comctl32.dll 6.0, such as in the following Dr. Dobbs article on
Writing Windows Custom Controls, then you will need to use those code blocks conditionally when comctl32.dll < 6, because they will not work on version 6 or greater and will cause your application to crash.