Пример #1
0
WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len)
{
	LRESULT n;
	WCHAR *text;

	n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
	if (len != NULL)
		*len = n;
	// WM_GETTEXTLENGTH does not include the null terminator
	text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]");
	// note the comparison: the size includes the null terminator, but the return does not
	if (GetWindowTextW(hwnd, text, n + 1) != n) {
		logLastError(L"error getting window text");
		// on error, return an empty string to be safe
		*text = L'\0';
		if (len != NULL)
			*len = 0;
	}
	return text;
}
Пример #2
0
HWND uiWindowsEnsureCreateControlHWND(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, HINSTANCE hInstance, LPVOID lpParam, BOOL useStandardControlFont)
{
	HWND hwnd;

	// don't let using the arrow keys in a uiRadioButtons leave the radio buttons
	if ((dwStyle & WS_TABSTOP) != 0)
		dwStyle |= WS_GROUP;
	hwnd = CreateWindowExW(dwExStyle,
		lpClassName, lpWindowName,
		dwStyle | WS_CHILD | WS_VISIBLE,
		0, 0,
		// use a nonzero initial size just in case some control breaks with a zero initial size
		100, 100,
		utilWindow, NULL, hInstance, lpParam);
	if (hwnd == NULL)
		logLastError("error creating window in uiWindowsUtilCreateControlHWND()");
	if (useStandardControlFont)
		SendMessageW(hwnd, WM_SETFONT, (WPARAM) hMessageFont, (LPARAM) TRUE);
	return hwnd;
}
Пример #3
0
uiGroup *uiNewGroup(const char *text)
{
	uiGroup *g;
	WCHAR *wtext;

	uiWindowsNewControl(uiGroup, g);

	wtext = toUTF16(text);
	g->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CONTROLPARENT,
		L"button", wtext,
		BS_GROUPBOX,
		hInstance, NULL,
		TRUE);
	uiFree(wtext);

	if (SetWindowSubclass(g->hwnd, groupSubProc, 0, (DWORD_PTR) g) == FALSE)
		logLastError(L"error subclassing groupbox to handle parent messages");

	return g;
}
Пример #4
0
/*
Windows doesn't natively support mouse crossing events.

TrackMouseEvent() (and its comctl32.dll wrapper _TrackMouseEvent()) both allow for a window to receive the WM_MOUSELEAVE message when the mouse leaves the client area. There's no equivalent WM_MOUSEENTER because it can be simulated (https://blogs.msdn.microsoft.com/oldnewthing/20031013-00/?p=42193).

Unfortunately, WM_MOUSELEAVE does not get generated while the mouse is captured. We need to capture for drag behavior to work properly, so this isn't going to mix well.

So what we do:
- on WM_MOUSEMOVE, if we don't have the capture, start tracking
	- this will handle the case of the capture being released while still in the area
- on WM_MOUSELEAVE, mark that we are no longer tracking
	- Windows has already done the work of that for us; it's just a flag we use for the next part
- when starting capture, stop tracking if we are tracking
- if capturing, manually check if the pointer is in the client rect on each area event
*/
static void track(uiArea *a, BOOL tracking)
{
	TRACKMOUSEEVENT tm;

	// do nothing if there's no change
	if (a->tracking && tracking)
		return;
	if (!a->tracking && !tracking)
		return;

	a->tracking = tracking;
	ZeroMemory(&tm, sizeof (TRACKMOUSEEVENT));
	tm.cbSize = sizeof (TRACKMOUSEEVENT);
	tm.dwFlags = TME_LEAVE;
	if (!a->tracking)
		tm.dwFlags |= TME_CANCEL;
	tm.hwndTrack = a->hwnd;
	if (_TrackMouseEvent(&tm) == 0)
		logLastError(L"error setting up mouse tracking");
}
Пример #5
0
HRESULT uiprivTableFinishEditingText(uiTable *t)
{
	uiprivTableColumnParams *p;
	uiTableValue *value;
	char *text;

	if (t->edit == NULL)
		return S_OK;
	text = uiWindowsWindowText(t->edit);
	value = uiNewTableValueString(text);
	uiFreeText(text);
	p = (*(t->columns))[t->editedSubitem];
	uiprivTableModelSetCellValue(t->model, t->editedItem, p->textModelColumn, value);
	uiFreeTableValue(value);
	// always refresh the value in case the model rejected it
	if (SendMessageW(t->hwnd, LVM_UPDATE, (WPARAM) (t->editedItem), 0) == (LRESULT) (-1)) {
		logLastError(L"LVM_UPDATE");
		return E_FAIL;
	}
	return uiprivTableAbortEditingText(t);
}
Пример #6
0
static void wheelscroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam)
{
	int delta;
	int lines;
	UINT scrollAmount;

	delta = GET_WHEEL_DELTA_WPARAM(wParam);
	if (SystemParametersInfoW(p->wheelSPIAction, 0, &scrollAmount, 0) == 0)
		// TODO use scrollAmount == 3 (for both v and h) instead?
		logLastError(L"error getting area wheel scroll amount");
	if (scrollAmount == WHEEL_PAGESCROLL)
		scrollAmount = p->pagesize;
	if (scrollAmount == 0)		// no mouse wheel scrolling (or t->pagesize == 0)
		return;
	// the rest of this is basically http://blogs.msdn.com/b/oldnewthing/archive/2003/08/07/54615.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/08/11/54624.aspx
	// see those pages for information on subtleties
	delta += *(p->wheelCarry);
	lines = delta * ((int) scrollAmount) / WHEEL_DELTA;
	*(p->wheelCarry) = delta - lines * WHEEL_DELTA / ((int) scrollAmount);
	scrollby(a, which, p, -lines);
}
Пример #7
0
static void appendMenuItem(HMENU menu, uiMenuItem *item)
{
	UINT uFlags;

	uFlags = MF_SEPARATOR;
	if (item->type != typeSeparator) {
		uFlags = MF_STRING;
		if (item->disabled)
			uFlags |= MF_DISABLED | MF_GRAYED;
		if (item->checked)
			uFlags |= MF_CHECKED;
	}
	if (AppendMenuW(menu, uFlags, item->id, item->name) == 0)
		logLastError(L"error appending menu item");

	if (item->len >= item->cap) {
		item->cap += grow;
		item->hmenus = (HMENU *) uiRealloc(item->hmenus, item->cap * sizeof (HMENU), "HMENU[]");
	}
	item->hmenus[item->len] = menu;
	item->len++;
}
Пример #8
0
void uiMain(void)
{
	MSG msg;
	int res;
	HWND active, focus;

	for (;;) {
		SetLastError(0);
		res = GetMessageW(&msg, NULL, 0, 0);
		if (res < 0)
			logLastError("error calling GetMessage() in uiMain()");
		if (res == 0)		// WM_QUIT
			break;
		active = GetActiveWindow();
		if (active == NULL) {
			msgloop_else(&msg);
			continue;
		}

		// bit of logic involved here:
		// we don't want dialog messages passed into Areas, so we don't call IsDialogMessageW() there
		// as for Tabs, we can't have both WS_TABSTOP and WS_EX_CONTROLPARENT set at the same time, so we hotswap the two styles to get the behavior we want
		focus = GetFocus();
		if (focus != NULL) {
			switch (windowClassOf(focus, L"TODO Area not yet implemented", NULL)) {
			case 0:		// uiArea
//				msgloop_area(active, focus, &msg);
				continue;
			}
			// else fall through
		}

		if (IsDialogMessage(active, &msg) != 0)
			continue;
		msgloop_else(&msg);
	}
}
Пример #9
0
uiWindowsSizing *uiWindowsNewSizing(HWND hwnd)
{
	uiWindowsSizing *d;
	HDC dc;
	HFONT prevfont;
	TEXTMETRICW tm;
	SIZE size;

	d = uiNew(uiWindowsSizing);

	dc = GetDC(hwnd);
	if (dc == NULL)
		logLastError("error getting DC in uiWindowsNewSizing()");
	prevfont = (HFONT) SelectObject(dc, hMessageFont);
	if (prevfont == NULL)
		logLastError("error loading control font into device context in uiWindowsNewSizing()");

	ZeroMemory(&tm, sizeof (TEXTMETRICW));
	if (GetTextMetricsW(dc, &tm) == 0)
		logLastError("error getting text metrics in uiWindowsNewSizing()");
	if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0)
		logLastError("error getting text extent point in uiWindowsNewSizing()");

	d->BaseX = (int) ((size.cx / 26 + 1) / 2);
	d->BaseY = (int) tm.tmHeight;
	d->InternalLeading = tm.tmInternalLeading;

	if (SelectObject(dc, prevfont) != hMessageFont)
		logLastError("error restoring previous font into device context in uiWindowsSizing()");
	if (ReleaseDC(hwnd, dc) == 0)
		logLastError("error releasing DC in uiWindowsSizing()");

	d->XPadding = uiWindowsDlgUnitsToX(winXPadding, d->BaseX);
	d->YPadding = uiWindowsDlgUnitsToY(winYPadding, d->BaseY);

	return d;
}
Пример #10
0
static void areaMouseEvent(uiArea *a, uintmax_t down, uintmax_t  up, WPARAM wParam, LPARAM lParam)
{
	uiAreaMouseEvent me;
	uintmax_t button;
	RECT r;

	me.X = GET_X_LPARAM(lParam);
	me.Y = GET_Y_LPARAM(lParam);

	if (GetClientRect(a->hwnd, &r) == 0)
		logLastError("error getting client rect of area in areaMouseEvent()");
	me.ClientWidth = r.right - r.left;
	me.ClientHeight = r.bottom - r.top;
	me.HScrollPos = a->hscrollpos;
	me.VScrollPos = a->vscrollpos;

	me.Down = down;
	me.Up = up;
	me.Count = 0;
	if (me.Down != 0)
		// GetMessageTime() returns LONG and GetDoubleClckTime() returns UINT, which are int32 and uint32, respectively, but we don't need to worry about the signedness because for the same bit widths and two's complement arithmetic, s1-s2 == u1-u2 if bits(s1)==bits(s2) and bits(u1)==bits(u2) (and Windows requires two's complement: http://blogs.msdn.com/b/oldnewthing/archive/2005/05/27/422551.aspx)
		// signedness isn't much of an issue for these calls anyway because http://stackoverflow.com/questions/24022225/what-are-the-sign-extension-rules-for-calling-windows-api-functions-stdcall-t and that we're only using unsigned values (think back to how you (didn't) handle signedness in assembly language) AND because of the above AND because the statistics below (time interval and width/height) really don't make sense if negative
		me.Count = clickCounterClick(&(a->cc), me.Down,
			me.X, me.Y,
			GetMessageTime(), GetDoubleClickTime(),
			GetSystemMetrics(SM_CXDOUBLECLK) / 2,
			GetSystemMetrics(SM_CYDOUBLECLK) / 2);

	// though wparam will contain control and shift state, let's just one function to get modifiers for both keyboard and mouse events; it'll work the same anyway since we have to do this for alt and windows key (super)
	me.Modifiers = getModifiers();

	button = me.Down;
	if (button == 0)
		button = me.Up;
	me.Held1To64 = 0;
	if (button != 1 && (wParam & MK_LBUTTON) != 0)
		me.Held1To64 |= 1 << 0;
	if (button != 2 && (wParam & MK_MBUTTON) != 0)
		me.Held1To64 |= 1 << 1;
	if (button != 3 && (wParam & MK_RBUTTON) != 0)
		me.Held1To64 |= 1 << 2;
	if (button != 4 && (wParam & MK_XBUTTON1) != 0)
		me.Held1To64 |= 1 << 3;
	if (button != 5 && (wParam & MK_XBUTTON2) != 0)
		me.Held1To64 |= 1 << 4;

	// on Windows, we have to capture on drag ourselves
	if (me.Down != 0 && !a->capturing) {
		SetCapture(a->hwnd);
		a->capturing = TRUE;
	}
	// only release capture when all buttons released
	if (me.Up != 0 && a->capturing && me.Held1To64 == 0) {
		// unset flag first as ReleaseCapture() sends WM_CAPTURECHANGED
		a->capturing = FALSE;
		if (ReleaseCapture() == 0)
			logLastError("error releasing capture on drag in areaMouseEvent()");
	}

	(*(a->ah->MouseEvent))(a->ah, a, &me);
}
Пример #11
0
static void endColorDialog(struct colorDialog *c, INT_PTR code)
{
	if (EndDialog(c->hwnd, code) == 0)
		logLastError(L"error ending color dialog");
	uiFree(c);
}
Пример #12
0
void setWindowInsertAfter(HWND hwnd, HWND insertAfter)
{
	if (SetWindowPos(hwnd, insertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE) == 0)
		logLastError("error reordering window in setWindowInsertAfter()");
}
Пример #13
0
int
main(int argc, char *argv[])
{
    if (argc < 3) {
        fprintf(stderr,
                "usage:\n"
                "  inject <dllname.dll> <command> [args] ...\n"
                "  inject <dllname.dll> <process-id>\n"
                "  inject <dllname.dll> !<process-name>\n"
        );
        return 1;
    }

    BOOL bAttach = FALSE;
    DWORD dwProcessId = ~0;
    if (isNumber(argv[2])) {
        dwProcessId = atol(argv[2]);
        bAttach = TRUE;
    } else if (argv[2][0] == '!') {
        const char *szProcessName = &argv[2][1];
        if (!getProcessIdByName(szProcessName, &dwProcessId)) {
            fprintf(stderr, "error: failed to find process %s\n", szProcessName);
            return 1;
        }
        bAttach = TRUE;
        fprintf(stderr, "dwProcessId = %lu\n", dwProcessId);
    }

    HANDLE hSemaphore = NULL;
    const char *szDll = argv[1];
    if (!USE_SHARED_MEM) {
        SetEnvironmentVariableA("INJECT_DLL", szDll);
    } else {
        hSemaphore = CreateSemaphore(NULL, 1, 1, "inject_semaphore");
        if (hSemaphore == NULL) {
            fprintf(stderr, "error: failed to create semaphore\n");
            return 1;
        }

        DWORD dwWait = WaitForSingleObject(hSemaphore, 0);
        if (dwWait == WAIT_TIMEOUT) {
            fprintf(stderr, "info: waiting for another inject instance to finish\n");
            dwWait = WaitForSingleObject(hSemaphore, INFINITE);
        }
        if (dwWait != WAIT_OBJECT_0) {
            fprintf(stderr, "error: failed to enter semaphore gate\n");
            return 1;
        }

        SetSharedMem(szDll);
    }

    BOOL bAttachDwm = FALSE;
    PROCESS_INFORMATION processInfo;
    HANDLE hProcess;
    if (bAttach) {
        BOOL bRet;
        HANDLE hToken   = NULL;
        bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
        if (!bRet) {
            fprintf(stderr, "error: OpenProcessToken returned %u\n", (unsigned)bRet);
            return 1;
        }

        LUID Luid;
        bRet = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid);
        if (!bRet) {
            fprintf(stderr, "error: LookupPrivilegeValue returned %u\n", (unsigned)bRet);
            return 1;
        }

        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = Luid;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof tp, NULL, NULL);
        if (!bRet) {
            fprintf(stderr, "error: AdjustTokenPrivileges returned %u\n", (unsigned)bRet);
            return 1;
        }

        DWORD dwDesiredAccess =
            PROCESS_CREATE_THREAD |
            PROCESS_QUERY_INFORMATION |
            PROCESS_QUERY_LIMITED_INFORMATION |
            PROCESS_VM_OPERATION |
            PROCESS_VM_WRITE |
            PROCESS_VM_READ |
            PROCESS_TERMINATE;
        hProcess = OpenProcess(
            dwDesiredAccess,
            FALSE /* bInheritHandle */,
            dwProcessId);
        if (!hProcess) {
            logLastError("failed to open process");
            return 1;
        }

        char szProcess[MAX_PATH];
        DWORD dwRet = GetModuleFileNameEx(hProcess, 0, szProcess, sizeof szProcess);
        assert(dwRet);
        if (dwRet &&
            stricmp(getBaseName(szProcess), "dwm.exe") == 0) {
            bAttachDwm = TRUE;
        }
    } else {
        std::string commandLine;
        char sep = 0;
        for (int i = 2; i < argc; ++i) {
            const char *arg = argv[i];

            if (sep) {
                commandLine.push_back(sep);
            }

            if (needsQuote(arg)) {
                quoteArg(commandLine, arg);
            } else {
                commandLine.append(arg);
            }

            sep = ' ';
        }

        STARTUPINFO startupInfo;
        memset(&startupInfo, 0, sizeof startupInfo);
        startupInfo.cb = sizeof startupInfo;

        // Create the process in suspended state
        if (!CreateProcessA(
               NULL,
               const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
               0, // process attributes
               0, // thread attributes
               TRUE, // inherit handles
               CREATE_SUSPENDED,
               NULL, // environment
               NULL, // current directory
               &startupInfo,
               &processInfo)) {
            DWORD dwLastError = GetLastError();
            fprintf(stderr, "error: failed to execute %s (%lu)\n",
                    commandLine.c_str(), dwLastError);
            if (dwLastError == ERROR_ELEVATION_REQUIRED) {
                fprintf(stderr, "error: target program requires elevated priviledges and must be started from an Administrator Command Prompt, or UAC must be disabled\n");
            }
            return 1;
        }

        hProcess = processInfo.hProcess;
    }

    /*
     * XXX: Mixed architecture don't quite work.  See also
     * http://www.corsix.org/content/dll-injection-and-wow64
     */
    {
        typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL);
        PFNISWOW64PROCESS pfnIsWow64Process;
        pfnIsWow64Process = (PFNISWOW64PROCESS)
            GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
        if (pfnIsWow64Process) {
            BOOL isParentWow64 = FALSE;
            BOOL isChildWow64 = FALSE;
            if (pfnIsWow64Process(GetCurrentProcess(), &isParentWow64) &&
                pfnIsWow64Process(hProcess, &isChildWow64) &&
                isParentWow64 != isChildWow64) {
                fprintf(stderr, "error: binaries mismatch: you need to use the "
#ifdef _WIN64
                        "32-bits"
#else
                        "64-bits"
#endif
                        " apitrace binaries to trace this application\n");
                TerminateProcess(hProcess, 1);
                return 1;
            }
        }
    }

    if (bAttachDwm && IsWindows8OrGreater()) {
        // Switch to Microsoft Basic Display Driver before injecting, so that
        // we don't trace with it.
        devconDisable(DEVCON_CLASS_DISPLAY);
        Sleep(1000);
    }

    const char *szDllName;
    szDllName = "injectee.dll";

    char szDllPath[MAX_PATH];
    GetModuleFileNameA(NULL, szDllPath, sizeof szDllPath);
    getDirName(szDllPath);
    strncat(szDllPath, szDllName, sizeof szDllPath - strlen(szDllPath) - 1);

#if 1
    if (!injectDll(hProcess, szDllPath)) {
        TerminateProcess(hProcess, 1);
        return 1;
    }
#endif

    DWORD exitCode;

    if (bAttach) {
        if (bAttachDwm) {
            restartDwmComposition(hProcess);
        }

        exitCode = 0;
    } else {
        // Start main process thread
        ResumeThread(processInfo.hThread);

        // Wait for it to finish
        WaitForSingleObject(hProcess, INFINITE);

        if (pSharedMem && !pSharedMem->bReplaced) {
            fprintf(stderr, "warning: %s was never used: application probably does not use this API\n", szDll);
        }

        exitCode = ~0;
        GetExitCodeProcess(hProcess, &exitCode);

        CloseHandle(processInfo.hThread);
    }

    CloseHandle(hProcess);

    if (hSemaphore) {
        ReleaseSemaphore(hSemaphore, 1, NULL);
        CloseHandle(hSemaphore);
    }

    return (int)exitCode;
}
Пример #14
0
// Force DWM process to recreate all its Direct3D objects.
static void
restartDwmComposition(HANDLE hProcess)
{
    HRESULT hr;

    HMODULE hModule = LoadLibraryA("dwmapi");
    assert(hModule);
    if (!hModule) {
        return;
    }

    typedef HRESULT (WINAPI *PFNDWMISCOMPOSITIONENABLED)(BOOL *pfEnabled);
    PFNDWMISCOMPOSITIONENABLED pfnDwmIsCompositionEnabled = (PFNDWMISCOMPOSITIONENABLED)GetProcAddress(hModule, "DwmIsCompositionEnabled");
    assert(pfnDwmIsCompositionEnabled);
    if (!pfnDwmIsCompositionEnabled) {
        return;
    }

    typedef HRESULT (WINAPI *PFNDWMENABLECOMPOSITION)(UINT uCompositionAction);
    PFNDWMENABLECOMPOSITION pfnDwmEnableComposition = (PFNDWMENABLECOMPOSITION)GetProcAddress(hModule, "DwmEnableComposition");
    assert(pfnDwmEnableComposition);
    if (!pfnDwmEnableComposition) {
        return;
    }


    BOOL bIsWindows8OrGreater = IsWindows8OrGreater();
    if (bIsWindows8OrGreater) {
        // Windows 8 ignores DwmEnableComposition(DWM_EC_DISABLECOMPOSITION).
        // It is however possible to force DWM to restart by restarting the
        // display device via the devcon utility 
        devconEnable(DEVCON_CLASS_DISPLAY);
    } else {

        BOOL fEnabled = FALSE;
        hr = pfnDwmIsCompositionEnabled(&fEnabled);
        if (FAILED(hr) || !fEnabled) {
            return;
        }

        fprintf(stderr, "info: restarting DWM composition\n");

        hr = pfnDwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
        assert(SUCCEEDED(hr));
        if (FAILED(hr)) {
            return;
        }

        Sleep(1000/30);

        hr = pfnDwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
        assert(SUCCEEDED(hr));
        (void)hr;
    }

    fprintf(stderr, "Press any key when finished tracing\n");
    getchar();

    DWORD dwExitCode;
    if (GetExitCodeProcess(hProcess, &dwExitCode) &&
        dwExitCode != STILL_ACTIVE) {
        // DWM process has already terminated
        return;
    }

    fprintf(stderr, "info: restarting DWM process\n");
    if (bIsWindows8OrGreater) {
        // From Windows 8 onwards DWM no longer runs as a service.  We just
        // kill it and winlogon parent process will respawn it.
        if (!TerminateProcess(hProcess, 0)) {
            logLastError("failed to terminate DWM process");
        }
    } else {
        hr = pfnDwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
        assert(SUCCEEDED(hr));

        restartService("uxsms");
    }
}
Пример #15
0
static HRESULT drawButtonPart(HRESULT hr, struct drawState *s)
{
	uiTableValue *value;
	WCHAR *wstr;
	bool enabled;
	HTHEME theme;
	RECT r;
	TEXTMETRICW tm;

	if (hr != S_OK)
		return hr;
	if (s->p->buttonModelColumn == -1)
		return S_OK;

	value = uiprivTableModelCellValue(s->model, s->iItem, s->p->buttonModelColumn);
	wstr = toUTF16(uiTableValueString(value));
	uiFreeTableValue(value);
	enabled = uiprivTableModelCellEditable(s->model, s->iItem, s->p->buttonClickableModelColumn);

	theme = OpenThemeData(s->t->hwnd, L"button");

	if (GetTextMetricsW(s->dc, &tm) == 0) {
		logLastError(L"GetTextMetricsW()");
		hr = E_FAIL;
		goto fail;
	}
	r = s->m->subitemBounds;

	if (theme != NULL) {
		int state;

		state = PBS_NORMAL;
		if (!enabled)
			state = PBS_DISABLED;
		hr = DrawThemeBackground(theme, s->dc,
			BP_PUSHBUTTON, state,
			&r, NULL);
		if (hr != S_OK) {
			logHRESULT(L"DrawThemeBackground()", hr);
			goto fail;
		}
		// TODO DT_EDITCONTROL?
		// TODO DT_PATH_ELLIPSIS DT_WORD_ELLIPSIS instead of DT_END_ELLIPSIS? a middle-ellipsis option would be ideal here
		// TODO is there a theme property we can get instead of hardcoding these flags? if not, make these flags a macro
		hr = DrawThemeText(theme, s->dc,
			BP_PUSHBUTTON, state,
			wstr, -1,
			DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX, 0,
			&r);
		if (hr != S_OK) {
			logHRESULT(L"DrawThemeText()", hr);
			goto fail;
		}
	} else {
		UINT state;
		HBRUSH color, prevColor;
		int prevBkMode;

		// TODO check errors
		// TODO explain why we're not doing this in the themed case (it has to do with extra transparent pixels)
		InflateRect(&r, -1, -1);
		state = DFCS_BUTTONPUSH;
		if (!enabled)
			state |= DFCS_INACTIVE;
		if (DrawFrameControl(s->dc, &r, DFC_BUTTON, state) == 0) {
			logLastError(L"DrawFrameControl()");
			hr = E_FAIL;
			goto fail;
		}
		color = GetSysColorBrush(COLOR_BTNTEXT);
		// TODO check errors for these two
		prevColor = (HBRUSH) SelectObject(s->dc, color);
		prevBkMode = SetBkMode(s->dc, TRANSPARENT);
		// TODO DT_EDITCONTROL?
		// TODO DT_PATH_ELLIPSIS DT_WORD_ELLIPSIS instead of DT_END_ELLIPSIS? a middle-ellipsis option would be ideal here
		if (DrawTextW(s->dc, wstr, -1, &r, DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX) == 0) {
			logLastError(L"DrawTextW()");
			hr = E_FAIL;
			goto fail;
		}
		// TODO check errors for these two
		SetBkMode(s->dc, prevBkMode);
		SelectObject(s->dc, prevColor);
	}

	hr = S_OK;
fail:
	// TODO check errors
	if (theme != NULL)
		CloseThemeData(theme);
	uiprivFree(wstr);
	return hr;
}
Пример #16
0
static void cbSetItemData(HWND cb, WPARAM item, LPARAM data)
{
	if (SendMessageW(cb, CB_SETITEMDATA, item, data) == (LRESULT) CB_ERR)
		logLastError(L"error setting combobox item data");
}
Пример #17
0
void setWindowText(HWND hwnd, WCHAR *wtext)
{
	if (SetWindowTextW(hwnd, wtext) == 0)
		logLastError(L"error setting window text");
}
Пример #18
0
HRESULT uiprivTableHandleNM_CLICK(uiTable *t, NMITEMACTIVATE *nm, LRESULT *lResult)
{
	LVHITTESTINFO ht;
	uiprivTableColumnParams *p;
	int modelColumn, editableColumn;
	bool text, checkbox;
	uiTableValue *value;
	int checked, editable;
	HRESULT hr;

	ZeroMemory(&ht, sizeof (LVHITTESTINFO));
	ht.pt = nm->ptAction;
	if (SendMessageW(t->hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM) (&ht)) == (LRESULT) (-1))
		goto done;

	modelColumn = -1;
	editableColumn = -1;
	text = false;
	checkbox = false;
	p = (*(t->columns))[ht.iSubItem];
	if (p->textModelColumn != -1) {
		modelColumn = p->textModelColumn;
		editableColumn = p->textEditableModelColumn;
		text = true;
	} else if (p->checkboxModelColumn != -1) {
		modelColumn = p->checkboxModelColumn;
		editableColumn = p->checkboxEditableModelColumn;
		checkbox = true;
	} else if (p->buttonModelColumn != -1) {
		modelColumn = p->buttonModelColumn;
		editableColumn = p->buttonClickableModelColumn;
	}
	if (modelColumn == -1)
		goto done;

	if (text && t->inDoubleClickTimer)
		// don't even ask for info if it's too soon to edit text
		goto done;

	if (!uiprivTableModelCellEditable(t->model, ht.iItem, editableColumn))
		goto done;

	if (text) {
		hr = openEditControl(t, ht.iItem, ht.iSubItem, p);
		if (hr != S_OK)
			return hr;
	} else if (checkbox) {
		if ((ht.flags & LVHT_ONITEMICON) == 0)
			goto done;
		value = uiprivTableModelCellValue(t->model, ht.iItem, modelColumn);
		checked = uiTableValueInt(value);
		uiFreeTableValue(value);
		value = uiNewTableValueInt(!checked);
		uiprivTableModelSetCellValue(t->model, ht.iItem, modelColumn, value);
		uiFreeTableValue(value);
	} else
		uiprivTableModelSetCellValue(t->model, ht.iItem, modelColumn, NULL);
	// always refresh the value in case the model rejected it
	if (SendMessageW(t->hwnd, LVM_UPDATE, (WPARAM) (ht.iItem), 0) == (LRESULT) (-1)) {
		logLastError(L"LVM_UPDATE");
		return E_FAIL;
	}

done:
	*lResult = 0;
	return S_OK;
}
Пример #19
0
static BOOL
ejectDll(HANDLE hProcess, const char *szDllPath)
{
    /*
     * Enumerate all modules.
     */

    HMODULE *phModules = NULL;
    DWORD cb = sizeof *phModules *
#ifdef NDEBUG
        32
#else
        4
#endif
    ;
    DWORD cbNeeded = 0;
    while (true) {
        phModules = (HMODULE *)realloc(phModules, cb);
        if (!EnumProcessModules(hProcess, phModules, cb, &cbNeeded)) {
            logLastError("failed to enumerate modules in remote process");
            free(phModules);
            return FALSE;
        }

        if (cbNeeded < cb) {
            break;
        }

        cb *= 2;
    }

    DWORD cNumModules = cbNeeded / sizeof *phModules;

    /*
     * Search our DLL.
     */

    const char *szDllName = getBaseName(szDllPath);
    HMODULE hModule = NULL;
    for (unsigned i = 0; i < cNumModules; ++i) {
        char szModName[MAX_PATH];
        if (GetModuleFileNameExA(hProcess, phModules[i], szModName, ARRAY_SIZE(szModName))) {
            if (stricmp(getBaseName(szModName), szDllName) == 0) {
                hModule = phModules[i];
                break;
            }
        }
    }

    free(phModules);

    if (!hModule) {
        debugPrintf("inject: error: failed to find %s module in the remote process\n", szDllName);
        return FALSE;
    }

    PTHREAD_START_ROUTINE lpStartAddress =
        (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("KERNEL32"), "FreeLibrary");

    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, lpStartAddress, hModule, 0, NULL);
    if (!hThread) {
        logLastError("failed to create remote thread");
        return FALSE;
    }

    WaitForSingleObject(hThread, INFINITE);

    DWORD bRet = 0;
    GetExitCodeThread(hThread, &bRet);
    if (!bRet) {
        debugPrintf("inject: error: failed to unload %s from the remote process\n", szDllPath);
        return FALSE;
    }

    return TRUE;
}
Пример #20
0
static void areaMouseEvent(uiArea *a, uintmax_t down, uintmax_t  up, WPARAM wParam, LPARAM lParam)
{
	uiAreaMouseEvent me;
	uintmax_t button;
	POINT clientpt;
	RECT client;
	BOOL inClient;
	double xpix, ypix;

	if (a->capturing) {
		clientpt.x = GET_X_LPARAM(lParam);
		clientpt.y = GET_Y_LPARAM(lParam);
		if (GetClientRect(a->hwnd, &client) == 0)
			logLastError("TODO");
		inClient = PtInRect(&client, clientpt);
		if (inClient && !a->inside) {
			a->inside = TRUE;
			(*(a->ah->MouseCrossed))(a->ah, a, 0);
			clickCounterReset(&(a->cc));
		} else if (!inClient && a->inside) {
			a->inside = FALSE;
			(*(a->ah->MouseCrossed))(a->ah, a, 1);
			clickCounterReset(&(a->cc));
		}
	}

	xpix = (double) GET_X_LPARAM(lParam);
	ypix = (double) GET_Y_LPARAM(lParam);
	// these are in pixels; we need points
	pixelsToDIP(a, &xpix, &ypix);
	me.X = xpix;
	me.Y = ypix;
	if (a->scrolling) {
		me.X += a->hscrollpos;
		me.Y += a->vscrollpos;
	}

	loadAreaSize(a, NULL, &(me.AreaWidth), &(me.AreaHeight));

	me.Down = down;
	me.Up = up;
	me.Count = 0;
	if (me.Down != 0)
		// GetMessageTime() returns LONG and GetDoubleClckTime() returns UINT, which are int32 and uint32, respectively, but we don't need to worry about the signedness because for the same bit widths and two's complement arithmetic, s1-s2 == u1-u2 if bits(s1)==bits(s2) and bits(u1)==bits(u2) (and Windows requires two's complement: http://blogs.msdn.com/b/oldnewthing/archive/2005/05/27/422551.aspx)
		// signedness isn't much of an issue for these calls anyway because http://stackoverflow.com/questions/24022225/what-are-the-sign-extension-rules-for-calling-windows-api-functions-stdcall-t and that we're only using unsigned values (think back to how you (didn't) handle signedness in assembly language) AND because of the above AND because the statistics below (time interval and width/height) really don't make sense if negative
		me.Count = clickCounterClick(&(a->cc), me.Down,
			me.X, me.Y,
			GetMessageTime(), GetDoubleClickTime(),
			GetSystemMetrics(SM_CXDOUBLECLK) / 2,
			GetSystemMetrics(SM_CYDOUBLECLK) / 2);

	// though wparam will contain control and shift state, let's just one function to get modifiers for both keyboard and mouse events; it'll work the same anyway since we have to do this for alt and windows key (super)
	me.Modifiers = getModifiers();

	button = me.Down;
	if (button == 0)
		button = me.Up;
	me.Held1To64 = 0;
	if (button != 1 && (wParam & MK_LBUTTON) != 0)
		me.Held1To64 |= 1 << 0;
	if (button != 2 && (wParam & MK_MBUTTON) != 0)
		me.Held1To64 |= 1 << 1;
	if (button != 3 && (wParam & MK_RBUTTON) != 0)
		me.Held1To64 |= 1 << 2;
	if (button != 4 && (wParam & MK_XBUTTON1) != 0)
		me.Held1To64 |= 1 << 3;
	if (button != 5 && (wParam & MK_XBUTTON2) != 0)
		me.Held1To64 |= 1 << 4;

	// on Windows, we have to capture on drag ourselves
	if (me.Down != 0)
		capture(a, TRUE);
	// only release capture when all buttons released
	if (me.Up != 0 && me.Held1To64 == 0)
		capture(a, FALSE);

	(*(a->ah->MouseEvent))(a->ah, a, &me);
}
Пример #21
0
static void cbSetCurSel(HWND cb, WPARAM item)
{
	if (SendMessageW(cb, CB_SETCURSEL, item, 0) != (LRESULT) item)
		logLastError(L"error selecting combobox item");
}
Пример #22
0
void unregisterWindowClass(void)
{
	if (UnregisterClassW(windowClass, hInstance) == 0)
		logLastError(L"error unregistering uiWindow window class");
}
Пример #23
0
static HRESULT drawProgressBarPart(HRESULT hr, struct drawState *s)
{
	int progress;
	LONG indeterminatePos;
	HTHEME theme;
	RECT r;
	RECT rBorder, rFill[2];
	int i, nFill;
	TEXTMETRICW tm;
	int sysColor;

	if (hr != S_OK)
		return hr;
	if (s->p->progressBarModelColumn == -1)
		return S_OK;

	progress = uiprivTableProgress(s->t, s->iItem, s->iSubItem, s->p->progressBarModelColumn, &indeterminatePos);

	theme = OpenThemeData(s->t->hwnd, L"PROGRESS");

	if (GetTextMetricsW(s->dc, &tm) == 0) {
		logLastError(L"GetTextMetricsW()");
		hr = E_FAIL;
		goto fail;
	}
	r = s->m->subitemBounds;
	// this sets the height of the progressbar and vertically centers it in one fell swoop
	r.top += (r.bottom - tm.tmHeight - r.top) / 2;
	r.bottom = r.top + tm.tmHeight;

	// TODO check errors
	rBorder = r;
	InflateRect(&rBorder, -1, -1);
	if (theme != NULL) {
		RECT crect;

		hr = GetThemeBackgroundContentRect(theme, s->dc,
			PP_TRANSPARENTBAR, PBBS_NORMAL,
			&rBorder, &crect);
		if (hr != S_OK) {
			logHRESULT(L"GetThemeBackgroundContentRect()", hr);
			goto fail;
		}
		hr = DrawThemeBackground(theme, s->dc,
			PP_TRANSPARENTBAR, PBBS_NORMAL,
			&crect, NULL);
		if (hr != S_OK) {
			logHRESULT(L"DrawThemeBackground() border", hr);
			goto fail;
		}
	} else {
		HPEN pen, prevPen;
		HBRUSH brush, prevBrush;

		sysColor = COLOR_HIGHLIGHT;
		if (s->m->selected)
			sysColor = COLOR_HIGHLIGHTTEXT;

		// TODO check errors everywhere
		pen = CreatePen(PS_SOLID, 1, GetSysColor(sysColor));
		prevPen = (HPEN) SelectObject(s->dc, pen);
		brush = (HBRUSH) GetStockObject(NULL_BRUSH);
		prevBrush = (HBRUSH) SelectObject(s->dc, brush);
		Rectangle(s->dc, rBorder.left, rBorder.top, rBorder.right, rBorder.bottom);
		SelectObject(s->dc, prevBrush);
		SelectObject(s->dc, prevPen);
		DeleteObject(pen);
	}

	nFill = 1;
	rFill[0] = r;
	// TODO check error
	InflateRect(&rFill[0], -1, -1);
	if (progress != -1)
		rFill[0].right -= (rFill[0].right - rFill[0].left) * (100 - progress) / 100;
	else {
		LONG barWidth;
		LONG pieceWidth;

		// TODO explain all this
		// TODO this should really start the progressbar scrolling into view instead of already on screen when first set
		rFill[1] = rFill[0];		// save in case we need it
		barWidth = rFill[0].right - rFill[0].left;
		pieceWidth = barWidth / indeterminateSegments;
		rFill[0].left += indeterminatePos % barWidth;
		if ((rFill[0].left + pieceWidth) >= rFill[0].right) {
			// make this piece wrap back around
			nFill++;
			rFill[1].right = rFill[1].left + (pieceWidth - (rFill[0].right - rFill[0].left));
		} else
			rFill[0].right = rFill[0].left + pieceWidth;
	}
	for (i = 0; i < nFill; i++)
		if (theme != NULL) {
			hr = DrawThemeBackground(theme, s->dc,
				PP_FILL, PBFS_NORMAL,
				&rFill[i], NULL);
			if (hr != S_OK) {
				logHRESULT(L"DrawThemeBackground() fill", hr);
				goto fail;
			}
		} else
			// TODO check errors
			FillRect(s->dc, &rFill[i], GetSysColorBrush(sysColor));

	hr = S_OK;
fail:
	// TODO check errors
	if (theme != NULL)
		CloseThemeData(theme);
	return hr;
}