reactos/rosapps/smartpdf/baseutils/win_util.c
Klemens Friedl c0ff78a908 two linking issues fixed
* _wstr_dup
* _FT_Get_X11_Font_Format (with a work-around)

one weird mingw linking issue remains:
* _WinMain@16


trunk/reactos/lib/3rdparty/mingw/main.c:73: undefined reference to `_WinMain@16'

svn path=/trunk/; revision=29315
2007-09-30 15:43:34 +00:00

464 lines
11 KiB
C

/* Written by Krzysztof Kowalczyk (http://blog.kowalczyk.info)
The author disclaims copyright to this source code. */
#include "base_util.h"
#include "win_util.h"
#include "tstr_util.h"
#ifdef _WIN32_WCE
#include <aygshell.h>
#include <Shlobj.h>
#endif
// Hmm, why have to redefine here (?!)
#ifdef __GNUC__
#define LVM_GETSELECTIONMARK (LVM_FIRST+66)
#define ListView_GetSelectionMark(w) (INT)SNDMSG((w),LVM_GETSELECTIONMARK,0,0)
#endif
int rect_dx(RECT *r)
{
int dx = r->right - r->left;
assert(dx >= 0);
return dx;
}
int rect_dy(RECT *r)
{
int dy = r->bottom - r->top;
assert(dy >= 0);
return dy;
}
void rect_set(RECT *r, int x, int y, int dx, int dy)
{
r->left = x;
r->top = y;
r->right = x + dx;
r->bottom = y + dy;
}
void win_set_font(HWND hwnd, HFONT font)
{
SendMessage(hwnd, WM_SETFONT, (WPARAM)font, 0);
}
int win_get_text_len(HWND hwnd)
{
return (int)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
}
void win_set_text(HWND hwnd, const TCHAR *txt)
{
SendMessage(hwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)txt);
}
/* return a text in edit control represented by hwnd
return NULL in case of error (couldn't allocate memory)
caller needs to free() the text */
TCHAR *win_get_text(HWND hwnd)
{
int cchTxtLen = win_get_text_len(hwnd);
TCHAR * txt = (TCHAR*)malloc((cchTxtLen+1)*sizeof(TCHAR));
if (NULL == txt)
return NULL;
SendMessage(hwnd, WM_GETTEXT, cchTxtLen + 1, (LPARAM)txt);
txt[cchTxtLen] = 0;
return txt;
}
void win_edit_set_selection(HWND hwnd, DWORD selStart, DWORD selEnd)
{
SendMessage(hwnd, EM_SETSEL, (WPARAM)selStart, (WPARAM)selEnd);
}
void win_edit_select_all(HWND hwnd)
{
win_edit_set_selection(hwnd, 0, -1);
}
LRESULT lv_delete_all_items(HWND hwnd)
{
return SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
}
LRESULT lv_set_items_count(HWND hwnd, int items_count)
{
#ifdef __GNUC__
ListView_SetItemCount(hwnd, items_count);
#else
return ListView_SetItemCount(hwnd, items_count);
#endif
}
int lv_get_items_count(HWND hwnd)
{
LRESULT count = ListView_GetItemCount(hwnd);
if (LB_ERR == count)
return 0;
return (int)count;
}
LRESULT lv_insert_column(HWND hwnd, int col, LVCOLUMN *lvc)
{
return SendMessage(hwnd, LVM_INSERTCOLUMN, col, (LPARAM)lvc);
}
LRESULT lv_set_column(HWND hwnd, int col, LVCOLUMN *lvc)
{
return SendMessage(hwnd, LVM_SETCOLUMN, col, (LPARAM)lvc);
}
LRESULT lv_set_column_dx(HWND hwnd, int col, int dx)
{
return ListView_SetColumnWidth(hwnd, col, dx);
}
LRESULT lv_insert_item(HWND hwnd, int row, LVITEM *lvi)
{
lvi->iItem = row;
lvi->iSubItem = 0;
return SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)lvi);
}
LRESULT lb_delete_string(HWND hwnd, int pos)
{
return SendMessage(hwnd, LB_DELETESTRING, pos, 0);
}
LRESULT lb_delete_all_items(HWND hwnd)
{
#if 1
LRESULT remaining_count;
for (;;) {
remaining_count = lb_delete_string(hwnd, 0);
if ((LB_ERR == remaining_count) || (0 == remaining_count))
break;
}
return 0;
#else
LRESULT count;
int i;
count = lb_get_items_count(hwnd);
if (LB_ERR == count)
return LB_ERR;
for (i=count-1; i--; i>=0) {
lb_delete_string(hwnd, i);
}
assert(0 == lb_get_items_count(hwnd);
#endif
}
#if 0
LRESULT lb_set_items_count(HWND hwnd, int items_count)
{
return SendMessage(hwnd, LB_SETCOUNT, items_count, 0);
}
#endif
LRESULT lb_get_items_count(HWND hwnd)
{
return SendMessage(hwnd, LB_GETCOUNT, 0, 0);
}
LRESULT lb_insert_item_text(HWND hwnd, int row, const TCHAR *txt)
{
return SendMessage(hwnd, LB_INSERTSTRING, (WPARAM)row, (LPARAM)txt);
}
LRESULT lb_append_string_no_sort(HWND hwnd, const TCHAR *txt)
{
return lb_insert_item_text(hwnd, -1, txt);
}
/* lb_get_selection and lb_set_selection only work for single-selection listbox */
LRESULT lb_get_selection(HWND hwnd)
{
return SendMessage(hwnd, LB_GETCURSEL, 0, 0);
}
LRESULT lb_set_selection(HWND hwnd, int item)
{
assert(item >= 0);
return SendMessage(hwnd, LB_SETCURSEL, (WPARAM)item, 0);
}
LRESULT lv_insert_item_text(HWND hwnd, int row, const TCHAR *txt)
{
LVITEM lvi = {0};
assert(txt);
if (!txt)
return -1; /* means failure */
lvi.mask = LVIF_TEXT;
lvi.pszText = (LPTSTR)txt;
return lv_insert_item(hwnd, row, &lvi);
}
/* Returns a selected item or -1 if no selection.
Assumes that the list is single-sel */
int lv_get_selection_pos(HWND hwnd)
{
int selection;
int selected_count = ListView_GetSelectedCount(hwnd);
assert(selected_count <= 1);
if (0 == selected_count)
return -1;
selection = ListView_GetSelectionMark(hwnd);
return selection;
}
int font_get_dy_from_dc(HDC hdc, HFONT font)
{
TEXTMETRIC tm;
HFONT font_prev;
int font_dy;
font_prev = (HFONT)SelectObject(hdc, font);
GetTextMetrics(hdc, &tm);
font_dy = tm.tmAscent + tm.tmDescent;
SelectObject(hdc, font_prev);
return font_dy;
}
int font_get_dy(HWND hwnd, HFONT font)
{
HDC hdc;
int font_dy = 0;
hdc = GetDC(hwnd);
if (hdc)
font_dy = font_get_dy_from_dc(hdc, font);
ReleaseDC(hwnd, hdc);
return font_dy;
}
#ifdef _WIN32_WCE
/* see http://pocketpcdn.com/articles/wordcompletion.html for details
edit boxes on pocket pc by default have spelling suggestion/completion.
Sometimes we want/need to disable that and this is a function to do it. */
void sip_completion_disable(void)
{
SIPINFO info;
SHSipInfo(SPI_GETSIPINFO, 0, &info, 0);
info.fdwFlags |= SIPF_DISABLECOMPLETION;
SHSipInfo(SPI_SETSIPINFO, 0, &info, 0);
}
void sip_completion_enable(void)
{
SIPINFO info;
SHSipInfo(SPI_GETSIPINFO, 0, &info, 0);
info.fdwFlags &= ~SIPF_DISABLECOMPLETION;
SHSipInfo(SPI_SETSIPINFO, 0, &info, 0);
}
#endif
void launch_url(const TCHAR *url)
{
SHELLEXECUTEINFO sei;
BOOL res;
if (NULL == url)
return;
ZeroMemory(&sei, sizeof(sei));
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_FLAG_NO_UI;
sei.lpVerb = TEXT("open");
sei.lpFile = url;
sei.nShow = SW_SHOWNORMAL;
res = ShellExecuteEx(&sei);
return;
}
/* On windows those are defined as:
#define CSIDL_PROGRAMS 0x0002
#define CSIDL_PERSONAL 0x0005
#define CSIDL_APPDATA 0x001a
see shlobj.h for more */
#ifdef CSIDL_APPDATA
/* this doesn't seem to be defined on sm 2002 */
#define SPECIAL_FOLDER_PATH CSIDL_APPDATA
#endif
#ifdef CSIDL_PERSONAL
/* this is defined on sm 2002 and goes to "\My Documents".
Not sure if I should use it */
#ifndef SPECIAL_FOLDER_PATH
#define SPECIAL_FOLDER_PATH CSIDL_PERSONAL
#endif
#endif
/* see http://www.opennetcf.org/Forums/post.asp?method=TopicQuote&TOPIC_ID=95&FORUM_ID=12
for more possibilities
return false on failure, true if ok. Even if returns false, it'll return root ("\")
directory so that clients can ignore failures from this function
*/
TCHAR *get_app_data_folder_path(BOOL f_create)
{
#ifdef SPECIAL_FOLDER_PATH
BOOL f_ok;
TCHAR path[MAX_PATH];
f_ok = SHGetSpecialFolderPath(NULL, path, SPECIAL_FOLDER_PATH, f_create);
if (f_ok)
return tstr_dup(path);
else
return tstr_dup(_T(""));
#else
/* if all else fails, just use root ("\") directory */
return (TCHAR*)str_dup(_T("")); /* @note: mingw doesn't support tstr_dup */
#endif
}
void screen_get_dx_dy(int *dx_out, int *dy_out)
{
if (dx_out)
*dx_out = GetSystemMetrics(SM_CXSCREEN);
if (dy_out)
*dy_out = GetSystemMetrics(SM_CYSCREEN);
}
int screen_get_dx(void)
{
return (int)GetSystemMetrics(SM_CXSCREEN);
}
int screen_get_dy(void)
{
return (int)GetSystemMetrics(SM_CYSCREEN);
}
int screen_get_menu_dy(void)
{
return GetSystemMetrics(SM_CYMENU);
}
int screen_get_caption_dy(void)
{
return GetSystemMetrics(SM_CYCAPTION);
}
/* given a string id 'strId' from resources, get the string in a dynamically
allocated string.
Returns the string or NULL if error.
Caller needs to free() the string.
TODO: string is limited to BUF_CCH_SIZE. Could do it better by dynamically
allocating more memory if needed */
#define BUF_CCH_SIZE 256
TCHAR *load_string_dup(int str_id)
{
TCHAR buf[BUF_CCH_SIZE] = {0};
LoadString(NULL, str_id, buf, BUF_CCH_SIZE);
if (0 == tstr_len(buf))
{
assert(0);
return NULL;
}
return (TCHAR*)str_dup(buf); /* @note: mingw doesn't support tstr_dup */
}
const TCHAR *load_string(int str_id)
{
int res;
const TCHAR *str;
/* little-known hack: when lpBuffer is NULL, LoadString() returns
a pointer to a string, that can be cast to TCHAR * (LPCTSTR)
requires -n option to RC (resource compiler)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcesdk40/html/cerefLoadString.asp */
res = LoadString(NULL, str_id, NULL, 0);
if (0 == res)
return NULL;
str = (const TCHAR*)res;
return str;
}
// A helper to set a string, null-terminated 'keyValue' for a given 'keyName'
// in 'keyPath'/'keyClass'
// if 'keyName' is NULL then we set the default value for 'keyPath'
// Returns false if there was any error (can be ignored)
int regkey_set_str(HKEY key_class, TCHAR *key_path, TCHAR *key_name, TCHAR *key_value)
{
HKEY hkey = NULL;
DWORD size = 0;
BOOL f_ok;
if (ERROR_SUCCESS != RegCreateKeyEx(key_class, key_path, 0, NULL, 0, 0, NULL, &hkey, NULL))
return FALSE;
f_ok = TRUE;
size = (DWORD)(tstr_len(key_value)*sizeof(TCHAR));
if (ERROR_SUCCESS != RegSetValueEx(hkey, key_name, 0, REG_SZ, (LPBYTE)key_value, size))
f_ok = FALSE;
RegCloseKey(hkey);
return f_ok;
}
int regkey_set_dword(HKEY key_class, TCHAR *key_path, TCHAR *key_name, DWORD key_value)
{
HKEY hkey = NULL;
DWORD size = 0;
BOOL f_ok;
if (ERROR_SUCCESS != RegCreateKeyEx(key_class, key_path, 0, NULL, 0, 0, NULL, &hkey, NULL))
return FALSE;
f_ok = TRUE;
size = sizeof(DWORD);
if (ERROR_SUCCESS != RegSetValueEx(hkey, key_name, 0, REG_DWORD, (LPBYTE)&key_value, size))
f_ok = FALSE;
RegCloseKey(hkey);
return f_ok;
}
static void rect_client_to_screen(RECT *r, HWND hwnd)
{
POINT p1 = {r->left, r->top};
POINT p2 = {r->right, r->bottom};
ClientToScreen(hwnd, &p1);
ClientToScreen(hwnd, &p2);
r->left = p1.x;
r->top = p1.y;
r->right = p2.x;
r->bottom = p2.y;
}
void paint_round_rect_around_hwnd(HDC hdc, HWND hwnd_edit_parent, HWND hwnd_edit, COLORREF col)
{
RECT r;
HBRUSH br;
HBRUSH br_prev;
HPEN pen;
HPEN pen_prev;
GetClientRect(hwnd_edit, &r);
br = CreateSolidBrush(col);
if (!br) return;
pen = CreatePen(PS_SOLID, 1, col);
pen_prev = SelectObject(hdc, pen);
br_prev = SelectObject(hdc, br);
rect_client_to_screen(&r, hwnd_edit_parent);
/* TODO: the roundness value should probably be calculated from the dy of the rect */
/* TODO: total hack: I manually adjust rectangle to values that fit g_hwnd_edit, as
found by experimentation. My mapping of coordinates isn't right (I think I need
mapping from window to window but even then it wouldn't explain -3 for y axis */
RoundRect(hdc, r.left+4, r.top-3, r.right+12, r.bottom-3, 8, 8);
if (br_prev)
SelectObject(hdc, br_prev);
if (pen_prev)
SelectObject(hdc, pen_prev);
DeleteObject(pen);
DeleteObject(br);
}