How to detour the main instance of a function? - winapi

I'm trying to detour ::DrawText() (and other draw text functions) for an application that has a lot of DLLs, some of which also use those functions.
I would have thought that if I detoured the main function using DetourFindFunction(), this would capture all cases from all functions in all DLLs, such that I could solve this question as there is text being displayed on the window.
Unfortunately, either CDHtmalDialog is somehow getting around the detour, or it is using some other function to draw the text on the window.
Could someone confirm that if I were to do this:
int (WINAPI *pDrawTextExW)(
_In_ HDC hdc,
_Inout_ LPWSTR lpchText,
_In_ int cchText,
_Inout_ LPRECT lprc,
_In_ UINT dwDTFormat,
_In_ LPDRAWTEXTPARAMS lpDTParams
) = 0;
int WINAPI MyDrawTextExW(
_In_ HDC hdc,
_Inout_ LPWSTR lpchText,
_In_ int cchText,
_Inout_ LPRECT lprc,
_In_ UINT dwDTFormat,
_In_ LPDRAWTEXTPARAMS lpDTParams
)
{
return (*pDrawTextExW)(hdc, lpchText, cchText, lprc, dwDTFormat, lpDTParams);
}
CCalcDrillDownDlg::CCalcDrillDownDlg(/* bunch of parameters */, CWnd *pParent)
: CDHtmlDialog(CCalcDrillDownDlg::IDD, 0, pParent)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
pDrawTextExW = decltype(pDrawTextExW)(DetourFindFunction("user32.dll", "DrawTextExW"));
DetourAttach(&(PVOID&)pDrawTextExW, MyDrawTextExW);
if (DetourTransactionCommit() == NO_ERROR)
OutputDebugString("DrawTextExW() detoured successfully\n");
for each of DrawTextA, DrawTextW, DrawTextExA, DrawTextExW that if CDHtmlDialog were to use one of these functions to draw the text with, it would get detoured? And perhaps someone would know how that class outputs text on the window's DC?
One funny thing that I did notice is that DrawTextExW() is getting detoured, trying to print the OK text on a button that is actually not displayed on the window. Not sure what that's about.
> cv32.dll!MyDrawTextExW(HDC__ * hdc=0x940111a2, wchar_t * lpchText=0x04925128, int cchText=2, tagRECT * lprc=0x012eb314, unsigned int dwDTFormat=1048613, tagDRAWTEXTPARAMS * lpDTParams=0x00000000) Line 4186 C++
uxtheme.dll!CTextDraw::DrawTextW() Unknown
uxtheme.dll!DrawThemeText() Unknown
comctl32.dll!Button_DrawThemed() Unknown
comctl32.dll!Button_DrawPush() Unknown
comctl32.dll!Button_PaintImpl() Unknown
comctl32.dll!Button_WndProc() Unknown
user32.dll!__InternalCallWinProc#20() Unknown
user32.dll!UserCallWinProcCheckWow() Unknown
user32.dll!DispatchClientMessage() Unknown
user32.dll!___fnDWORD#4() Unknown
ntdll.dll!_KiUserCallbackDispatcher#12() Unknown
user32.dll!_DispatchMessageA#4() Unknown
mfc120d.dll!AfxInternalPumpMessage() Line 181 C++
mfc120d.dll!CWinThread::PumpMessage() Line 900 C++
mfc120d.dll!AfxPumpMessage() Line 190 C++
mfc120d.dll!CWnd::RunModalLoop(unsigned long dwFlags=4) Line 4644 C++
mfc120d.dll!CWnd::CreateRunDlgIndirect(const DLGTEMPLATE * lpDialogTemplate=0x7216cc28, CWnd * pParentWnd=0x012ecd60, HINSTANCE__ * hInst=0x6f730000) Line 470 C++
mfc120d.dll!CDialog::DoModal() Line 633 C++

Related

Basic Win32 C programming

I'm trying to display the command line arguments.
This is my current code.
#include "windows.h"
int _stdcall WinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdline,
int nCmdShow )
{
MessageBox ( 0, lpszCmdLine,L"Title",0);
return ( 0 ) ;
}
I'm getting different characters in application.
What changes should I do in order to display the command line arguments in application window?
Since lpszCmdline is LPSTR, (ASCII, not UNICODE), the first option would be using the ASCII version of MessageBox(), but since UNICODE is the standard, I would suggest using the UNICODE version of win32 entry point. See the code below:
#include "windows.h"
int _stdcall wWinMain ( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpszCmdline,
int nCmdShow )
{
MessageBox ( 0, lpszCmdLine,L"Title",0);
return ( 0 ) ;
}
Further more, to convert the command line to an argv style array of strings, call the CommandLineToArgvW function.

Understanding: conversion from long_ptr to bool possible loss of data

I am fresh off from learning C++ and to learn winapi, I am doing the Forgers Win32 API tutorial.
Here is my code:
//MyControl.h
#pragma once
#include <windows.h>
#include "resource.h"
BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
BOOL BrushExists(HBRUSH hBrush);
-------------------------------------------------------
//MyControl.cpp
#include "MyControl.h"
HBRUSH g_hbrBackground = NULL;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
return (int)DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC)DlgProc);
}
BOOL BrushExists(HBRUSH hBrush) // I added this to better understand what is happening
{
if (hBrush)
return TRUE;
else
return FALSE;
}
BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_INITDIALOG:
{
g_hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
//... Other code skipped copy pasting ...
}
break;
case WM_COMMAND:
//... Other code skipped copy pasting ...
break;
case WM_CTLCOLORDLG:
return (LONG_PTR)g_hbrBackground; // Where casting happens
// return BrushExists(g_hbrBackground); // Tried this to understand things
break;
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(255, 255, 255));
SetBkMode(hdcStatic, TRANSPARENT);
return (LONG_PTR)g_hbrBackground; // Where casting happens
// return BrushExists(g_hbrBackground); // Tried this to understand things
}
break;
//... Other code skipped copy pasting ...
}
The code compiles and gives the warning: C4244: 'return': conversion from 'LONG_PTR' to 'BOOL', possible loss of data
The casting works and the dialog box is colored right as expected:
Black colored dialog.
My question: What happens in the background when HBRUSH is returned as a LONG_PTR from a function (DLGPROC) that returns BOOL? My assumption from reading C++ was that if the LONG_PTR is non-zero then the BOOL returned is TRUE and if LONG_PTR is zero then the BOOL returned is FALSE. To check this I created the function BOOL BrushExists(HBRUSH hBrush);// See code. Using this function to check for the HBRUSH and return TRUE, compiles without warnings and runs without error. But the coloring of the Dialog box does not happen:
Black color missing.
So my assumption is wrong. The LONG_PTR seems to be evaluated by the win32 API as a number instead of as a BOOL. Can someone explain to me how this is happening?
Note that it's BOOL and not bool. With the Windows SDK, BOOL is a typedef for int, which can store a 32-bit value - it's not a simple boolean that can only store true or false.
This is a kludge in the API basically. In 32 bit Windows, a brush handle fits in a 32 bit value, and even though it's ugly and potentially confusing, it's "safe" to return a brush handle cast as a BOOL (and you had to cast it, since that's what DialogProc was defined as returning).
Once Windows gained 64 bit support this situation obviously wasn't acceptable - in this example, brush handles (which are pointers) are 64 bits in size - casting them to a 32-bit type isn't safe.
Therefore, the definition of DialogProc was changed to return INT_PTR rather than BOOL. This is typedefed to 32-bits in x86 and 64-bits in x64. The example code you've used obviously pre-dates this change, but all new code should use the correct definition of DialogProc as returning INT_PTR.
BOOL is nothing but int typedef'd.
LONG_PTR may be either long int or __int64 - depending on platform chosen.
From header:
#ifdef _WIN64
typedef __int64 LONG_PTR;
#else
typedef long LONG_PTR;
#endif
You seem to be building the project as x64 compiler, and hence BOOL to LONG_PTR (essentially int to int64) is giving you warning.
Note that int and long are essentially same on Visual C++/Windows.

GetDlgCtrlID for top-level window with menu bar - return value

MSDN -> "GetDlgCtrlID function" -> Remarks:
"... Although GetDlgCtrlID may return a value if hwndCtl is a handle to a top-level window, top-level windows cannot have identifiers and such a return value is never valid."
It seems it is wrong information - "never valid".
At least for Win2k...Win8 this return value is just kernel pointer to hmenu(bar).
And my question is (primarily to MS insiders): why MSDN so inaccurate here?
(Screenshot: http://files.rsdn.ru/42164/gwl(-1)_tagwnd.png)
Upd (tagWND):
Also demo: http://files.rsdn.ru/42164/gwl(-1)_tagwnd.zip
It is not inaccurate. You create a top-level window with CreateWindowEx(). Which looks like this:
HWND WINAPI CreateWindowEx(
_In_ DWORD dwExStyle,
_In_opt_ LPCTSTR lpClassName,
_In_opt_ LPCTSTR lpWindowName,
_In_ DWORD dwStyle,
_In_ int x,
_In_ int y,
_In_ int nWidth,
_In_ int nHeight,
_In_opt_ HWND hWndParent,
_In_opt_ HMENU hMenu,
_In_opt_ HINSTANCE hInstance,
_In_opt_ LPVOID lpParam
);
Note how you don't specify the ID anywhere. But the fine print is in the description for the hMenu argument:
A handle to a menu, or specifies a child-window identifier, depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.
So you can have a menu OR a child ID. Overloaded, pretty common in the winapi, a child control can't have a menu and a toplevel window can't have a child ID. If you forge ahead and ignore this and call GetDlgCtrlID() on a toplevel window anyway then you will get back the value of the hMenu argument you specified in the create call. Well, today, always follow the api or you might get a rude surprise some day, you'd of course use GetMenu() instead.

Error 42: Symbol Undefined _CreateWindowW#44 when trying to register non existing windows function binding

I try to write simple show_window function but that which uses wide chars, there are no examples anywhere in D of that, only I could find windows creation that uses narrow-string and try now to rewrite that (I know bad english). So I'm failing even at proper registering unicode winapi bindings.
import core.runtime;
import core.sys.windows.windows;
import std.c.windows.windows;
pragma(lib, "gdi32.lib");
pragma(lib, "user32.lib");
struct WNDCLASSW { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCWSTR lpszMenuName; LPCWSTR lpszClassName; }
extern(Windows) HWND CreateWindowW(LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam );
extern(Windows)
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) {
HWND hWnd = CreateWindowW("wndClassName",
"window caption", WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, null, hInstance, null);
return 0;
}
and that produces:
Error 42: Symbol Undefined _CreateWindowW#44
Modern versions of Windows do not implement CreateWindow(). It is an ancient winapi function that dates from the 1980s and has been replaced by CreateWindowEx(). In the WinUser.h SDK header, CreateWindowW is a macro that actually calls CreateWindowExW(), passing 0 for the extra dwExStyle argument.
You must use CreateWindowExW() instead.

Basic Windows Programming question in VS2005

I created a win32 console application (without enable precompiled header option).
And now my source code as this, there is two compiler errors.
// AFormattingMsgBox.cpp : Defines the entry point for the console application.
//
#include <windows.h>
#include "stdafx.h"
//int _tmain(int argc, _TCHAR* argv[])
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
int cxScreen, cyScreen;
cxScreen = GetSystemMetrics(SM_CXSCREEN);
cyScreen = GetSystemMetrics(SM_CYSCREEN);
MessageBoxPrintf(TEXT("ScrnSize"), TEXT("The screen is %i pixels wide by %i pixels high."), cxScreen, cyScreen);
return 0;
}
int CDECL MessageBoxPrintf(TCHAR * szCaption, TCHAR * szFormat, int x, int y)
{
TCHAR szBuffer [1024];
va_list pArgList;
va_start(pArgList, szFormat);
_vsntprintf(szBuffer, sizeof(szBuffer) / sizeof(TCHAR),
szFormat, pArgList);
va_end(pArgList);
return MessageBox(NULL, szBuffer, szCaption, 0);
}
Compiler Errors.
error C3861: 'MessageBoxPrintf': identifier not found
error C2365: 'MessageBoxPrintf' : redefinition; previous definition was 'formerly
unknown identifier
How can I fix the errors. Thanks for your reading and replies.
Either put the function MessageBoxPrintf before the WinMain function or add a prototype before winMain. You add a prototype by entering the following line:
int CDECL MessageBoxPrintf(TCHAR * szCaption, TCHAR * szFormat, int x, int y);

Resources