win_util.c.svn-base
来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· SVN-BASE 代码 · 共 504 行
SVN-BASE
504 行
/* 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)#endifint 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_texta(HWND hwnd, const char *txt){ SendMessageA(hwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)txt);}void win_set_textw(HWND hwnd, const WCHAR *txt){ SendMessageW(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);}void lv_set_items_count(HWND hwnd, int items_count){ ListView_SetItemCount(hwnd, items_count);}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 0LRESULT lb_set_items_count(HWND hwnd, int items_count){ return SendMessage(hwnd, LB_SETCOUNT, items_count, 0);}#endifLRESULT 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_insert_item_textw(HWND hwnd, int row, const WCHAR *txt){ return SendMessageW(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);}LRESULT lb_append_stringw_no_sort(HWND hwnd, const WCHAR *txt){ return lb_insert_item_textw(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);}#endifvoid 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 tstr_dup(_T(""));#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);}/* Ensure that the rectangle is at least partially in the work area on a monitor. The rectangle is shifted into the work area if necessary. */void rect_shift_to_work_area(RECT *rect){ MONITORINFO mi; mi.cbSize = sizeof mi; GetMonitorInfo(MonitorFromRect(rect, MONITOR_DEFAULTTONEAREST), &mi); if (rect->bottom <= mi.rcWork.top) { /* Rectangle is too far above work area */ rect->bottom += mi.rcWork.top - rect->top; rect->top = mi.rcWork.top; } else if (rect->top >= mi.rcWork.bottom) { /* Rectangle is too far below */ rect->top -= rect->bottom - mi.rcWork.bottom; rect->bottom = mi.rcWork.bottom; } if (rect->right <= mi.rcWork.left) { /* Too far left */ rect->right += mi.rcWork.left - rect->left; rect->left = mi.rcWork.left; } else if (rect->left >= mi.rcWork.right) { /* Right */ rect->left -= rect->right - mi.rcWork.right; rect->right = mi.rcWork.right; }}/* 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 256TCHAR *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 tstr_dup(buf);}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);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?