#if defined(_WIN32) && !defined(WDL_WIN32_UTF8_NO_UI_IMPL) #include #include #endif #include "win32_utf8.h" #include "wdltypes.h" #include "wdlutf8.h" #ifdef _WIN32 #if !defined(WDL_NO_SUPPORT_UTF8) #ifdef __cplusplus extern "C" { #endif #ifndef WDL_UTF8_MAXFNLEN #define WDL_UTF8_MAXFNLEN 2048 #endif #define MBTOWIDE(symbase, src) \ int symbase##_size; \ WCHAR symbase##_buf[1024]; \ WCHAR *symbase = (symbase##_size=MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,src,-1,NULL,0)) >= 1000 ? (WCHAR *)malloc(symbase##_size * sizeof(WCHAR) + 24) : symbase##_buf; \ int symbase##_ok = symbase ? (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,src,-1,symbase,symbase##_size < 1 ? 1024 : symbase##_size)) : 0 #define MBTOWIDE_FREE(symbase) if (symbase != symbase##_buf) free(symbase) #define WIDETOMB_ALLOC(symbase, length) \ WCHAR symbase##_buf[1024]; \ size_t symbase##_size = sizeof(symbase##_buf); \ WCHAR *symbase = (length) > 1000 ? (WCHAR *)malloc(symbase##_size = (sizeof(WCHAR)*(length) + 10)) : symbase##_buf #define WIDETOMB_FREE(symbase) if (symbase != symbase##_buf) free(symbase) BOOL WDL_HasUTF8(const char *_str) { return WDL_DetectUTF8(_str) > 0; } static BOOL WDL_HasUTF8_FILENAME(const char *_str) { return WDL_DetectUTF8(_str) > 0 || (_str && strlen(_str)>=256); } static void wdl_utf8_correctlongpath(WCHAR *buf) { const WCHAR *insert; WCHAR *wr; int skip = 0; if (!buf || !buf[0] || wcslen(buf) < 256) return; if (buf[1] == ':') insert=L"\\\\?\\"; else if (buf[0] == '\\' && buf[1] == '\\') { insert = L"\\\\?\\UNC\\"; skip=2; } else return; wr = buf + wcslen(insert); memmove(wr, buf + skip, (wcslen(buf+skip)+1)*2); memmove(buf,insert,wcslen(insert)*2); while (*wr) { if (*wr == '/') *wr = '\\'; wr++; } } #ifdef AND_IS_NOT_WIN9X #undef AND_IS_NOT_WIN9X #endif #ifdef IS_NOT_WIN9X_AND #undef IS_NOT_WIN9X_AND #endif #ifdef WDL_SUPPORT_WIN9X #define IS_NOT_WIN9X_AND (GetVersion() < 0x80000000) && #define AND_IS_NOT_WIN9X && (GetVersion() < 0x80000000) #else #define AND_IS_NOT_WIN9X #define IS_NOT_WIN9X_AND #endif static ATOM s_combobox_atom; #define WDL_UTF8_OLDPROCPROP "WDLUTF8OldProc" int GetWindowTextUTF8(HWND hWnd, LPTSTR lpString, int nMaxCount) { if (WDL_NOT_NORMALLY(!lpString || nMaxCount < 1)) return 0; if (WDL_NOT_NORMALLY(hWnd == NULL)) { *lpString = 0; return 0; } if (nMaxCount>0 AND_IS_NOT_WIN9X) { int alloc_size=nMaxCount; LPARAM restore_wndproc = 0; // if a hooked combo box, and has an edit child, ask it directly if (s_combobox_atom && s_combobox_atom == GetClassWord(hWnd,GCW_ATOM) && GetProp(hWnd,WDL_UTF8_OLDPROCPROP)) { HWND h2=FindWindowEx(hWnd,NULL,"Edit",NULL); if (h2) { LPARAM resp = (LPARAM) GetProp(h2,WDL_UTF8_OLDPROCPROP); if (resp) restore_wndproc = SetWindowLongPtr(h2,GWLP_WNDPROC,resp); hWnd=h2; } else { // get via selection int sel = (int) SendMessage(hWnd,CB_GETCURSEL,0,0); if (sel>=0) { int len = (int) SendMessage(hWnd,CB_GETLBTEXTLEN,sel,0); char *p = lpString; if (len > nMaxCount-1) { p = (char*)calloc(len+1,1); len = nMaxCount-1; } lpString[0]=0; if (p) { SendMessage(hWnd,CB_GETLBTEXT,sel,(LPARAM)p); if (p!=lpString) { memcpy(lpString,p,len); lpString[len]=0; free(p); } return len; } } } } // prevent large values of nMaxCount from allocating memory unless the underlying text is big too if (alloc_size > 512) { int l=GetWindowTextLengthW(hWnd); if (l>=0 && l < 512) alloc_size=1000; } { WIDETOMB_ALLOC(wbuf, alloc_size); if (wbuf) { lpString[0]=0; if (GetWindowTextW(hWnd,wbuf,(int) (wbuf_size/sizeof(WCHAR)))) { if (!WideCharToMultiByte(CP_UTF8,0,wbuf,-1,lpString,nMaxCount,NULL,NULL)) lpString[nMaxCount-1]=0; } WIDETOMB_FREE(wbuf); if (restore_wndproc) SetWindowLongPtr(hWnd,GWLP_WNDPROC,restore_wndproc); return (int)strlen(lpString); } } if (restore_wndproc) SetWindowLongPtr(hWnd,GWLP_WNDPROC,restore_wndproc); } return GetWindowTextA(hWnd,lpString,nMaxCount); } UINT GetDlgItemTextUTF8(HWND hDlg, int nIDDlgItem, LPTSTR lpString, int nMaxCount) { HWND h = GetDlgItem(hDlg,nIDDlgItem); if (WDL_NORMALLY(h!=NULL)) return GetWindowTextUTF8(h,lpString,nMaxCount); if (lpString && nMaxCount > 0) *lpString = 0; return 0; } BOOL SetDlgItemTextUTF8(HWND hDlg, int nIDDlgItem, LPCTSTR lpString) { HWND h = GetDlgItem(hDlg,nIDDlgItem); if (WDL_NOT_NORMALLY(!h)) return FALSE; #ifdef _DEBUG if (WDL_NOT_NORMALLY(!lpString)) return FALSE; #endif if (WDL_HasUTF8(lpString) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,lpString); if (wbuf_ok) { BOOL rv = SetWindowTextW(h, wbuf); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } return SetWindowTextA(h, lpString); } static LRESULT WINAPI __forceUnicodeWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_SETTEXT && lParam) { MBTOWIDE(wbuf,(const char *)lParam); if (wbuf_ok) { LRESULT rv = DefWindowProcW(hwnd, uMsg, wParam, (LPARAM)wbuf); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } return DefWindowProc(hwnd, uMsg, wParam, lParam); } BOOL SetWindowTextUTF8(HWND hwnd, LPCTSTR str) { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!hwnd || !str)) return FALSE; #endif if (WDL_HasUTF8(str) AND_IS_NOT_WIN9X) { DWORD pid; if (GetWindowThreadProcessId(hwnd,&pid) == GetCurrentThreadId() && pid == GetCurrentProcessId() && !IsWindowUnicode(hwnd) && !(GetWindowLong(hwnd,GWL_STYLE)&WS_CHILD) ) { LPARAM tmp = SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LPARAM)__forceUnicodeWndProc); BOOL rv = SetWindowTextA(hwnd, str); SetWindowLongPtr(hwnd, GWLP_WNDPROC, tmp); return rv; } else { MBTOWIDE(wbuf,str); if (wbuf_ok) { BOOL rv = SetWindowTextW(hwnd, wbuf); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } } return SetWindowTextA(hwnd,str); } int MessageBoxUTF8(HWND hwnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT fl) { if ((WDL_HasUTF8(lpText)||WDL_HasUTF8(lpCaption)) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,lpText); if (wbuf_ok) { MBTOWIDE(wcap,lpCaption?lpCaption:""); if (wcap_ok) { int ret=MessageBoxW(hwnd,wbuf,lpCaption?wcap:NULL,fl); MBTOWIDE_FREE(wcap); MBTOWIDE_FREE(wbuf); return ret; } MBTOWIDE_FREE(wbuf); } } return MessageBoxA(hwnd,lpText,lpCaption,fl); } UINT DragQueryFileUTF8(HDROP hDrop, UINT idx, char *buf, UINT bufsz) { if (buf && bufsz && idx!=-1 AND_IS_NOT_WIN9X) { const UINT reqsz = DragQueryFileW(hDrop,idx,NULL,0); WIDETOMB_ALLOC(wbuf, reqsz+32); if (wbuf) { UINT rv=DragQueryFileW(hDrop,idx,wbuf,(int)(wbuf_size/sizeof(WCHAR))); if (rv) { if (!WideCharToMultiByte(CP_UTF8,0,wbuf,-1,buf,bufsz,NULL,NULL)) buf[bufsz-1]=0; } WIDETOMB_FREE(wbuf); return rv; } } return DragQueryFileA(hDrop,idx,buf,bufsz); } WCHAR *WDL_UTF8ToWC(const char *buf, BOOL doublenull, int minsize, DWORD *sizeout) { if (doublenull) { int sz=1; const char *p = (const char *)buf; WCHAR *pout,*ret; while (*p) { int a=MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,p,-1,NULL,0); int sp=(int)strlen(p)+1; if (a < sp)a=sp; // in case it needs to be ansi mapped sz+=a; p+=sp; } if (sz < minsize) sz=minsize; pout = (WCHAR *) malloc(sizeof(WCHAR)*(sz+4)); if (!pout) return NULL; ret=pout; p = (const char *)buf; while (*p) { int a; *pout=0; a = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,p,-1,pout,(int) (sz-(pout-ret))); if (!a) { pout[0]=0; a=MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,p,-1,pout,(int) (sz-(pout-ret))); } pout += a; p+=strlen(p)+1; } *pout=0; pout[1]=0; if (sizeout) *sizeout=sz; return ret; } else { int srclen = (int)strlen(buf)+1; int size=MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,buf,srclen,NULL,0); if (size < srclen)size=srclen; // for ansi code page if (size1) { int a=MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,buf,srclen,outbuf, size); if (!a) { outbuf[0]=0; a=MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,buf,srclen,outbuf,size); } } if (sizeout) *sizeout = size; return outbuf; } } } #ifndef WDL_WIN32_UTF8_NO_UI_IMPL static BOOL GetOpenSaveFileNameUTF8(LPOPENFILENAME lpofn, BOOL save) { OPENFILENAMEW tmp={sizeof(tmp),lpofn->hwndOwner,lpofn->hInstance,}; BOOL ret; // allocate, convert input if (lpofn->lpstrFilter) tmp.lpstrFilter = WDL_UTF8ToWC(lpofn->lpstrFilter,TRUE,0,0); tmp.nFilterIndex = lpofn->nFilterIndex ; if (lpofn->lpstrFile) tmp.lpstrFile = WDL_UTF8ToWC(lpofn->lpstrFile,FALSE,lpofn->nMaxFile,&tmp.nMaxFile); if (lpofn->lpstrFileTitle) tmp.lpstrFileTitle = WDL_UTF8ToWC(lpofn->lpstrFileTitle,FALSE,lpofn->nMaxFileTitle,&tmp.nMaxFileTitle); if (lpofn->lpstrInitialDir) tmp.lpstrInitialDir = WDL_UTF8ToWC(lpofn->lpstrInitialDir,0,0,0); if (lpofn->lpstrTitle) tmp.lpstrTitle = WDL_UTF8ToWC(lpofn->lpstrTitle,0,0,0); if (lpofn->lpstrDefExt) tmp.lpstrDefExt = WDL_UTF8ToWC(lpofn->lpstrDefExt,0,0,0); tmp.Flags = lpofn->Flags; tmp.lCustData = lpofn->lCustData; tmp.lpfnHook = lpofn->lpfnHook; tmp.lpTemplateName = (const WCHAR *)lpofn->lpTemplateName ; ret=save ? GetSaveFileNameW(&tmp) : GetOpenFileNameW(&tmp); // free, convert output if (ret && lpofn->lpstrFile && tmp.lpstrFile) { if ((tmp.Flags & OFN_ALLOWMULTISELECT) && tmp.lpstrFile[wcslen(tmp.lpstrFile)+1]) { char *op = lpofn->lpstrFile; WCHAR *ip = tmp.lpstrFile; while (*ip) { const int bcount = WideCharToMultiByte(CP_UTF8,0,ip,-1,NULL,0,NULL,NULL); const int maxout=lpofn->nMaxFile - 2 - (int)(op - lpofn->lpstrFile); if (maxout < 2+bcount) break; op += WideCharToMultiByte(CP_UTF8,0,ip,-1,op,maxout,NULL,NULL); ip += wcslen(ip)+1; } *op=0; } else { int len = WideCharToMultiByte(CP_UTF8,0,tmp.lpstrFile,-1,lpofn->lpstrFile,lpofn->nMaxFile-1,NULL,NULL); if (len == 0 && GetLastError()==ERROR_INSUFFICIENT_BUFFER) len = lpofn->nMaxFile-2; lpofn->lpstrFile[len]=0; if (!len) { lpofn->lpstrFile[len+1]=0; ret=0; } } // convert } lpofn->nFileOffset = tmp.nFileOffset ; lpofn->nFileExtension = tmp.nFileExtension; lpofn->lCustData = tmp.lCustData; free((WCHAR *)tmp.lpstrFilter); free((WCHAR *)tmp.lpstrFile); free((WCHAR *)tmp.lpstrFileTitle); free((WCHAR *)tmp.lpstrInitialDir); free((WCHAR *)tmp.lpstrTitle); free((WCHAR *)tmp.lpstrDefExt ); lpofn->nFilterIndex = tmp.nFilterIndex ; return ret; } BOOL GetOpenFileNameUTF8(LPOPENFILENAME lpofn) { #ifdef WDL_SUPPORT_WIN9X if (GetVersion()&0x80000000) return GetOpenFileNameA(lpofn); #endif return GetOpenSaveFileNameUTF8(lpofn,FALSE); } BOOL GetSaveFileNameUTF8(LPOPENFILENAME lpofn) { #ifdef WDL_SUPPORT_WIN9X if (GetVersion()&0x80000000) return GetSaveFileNameA(lpofn); #endif return GetOpenSaveFileNameUTF8(lpofn,TRUE); } BOOL SHGetSpecialFolderPathUTF8(HWND hwndOwner, LPTSTR lpszPath, int pszPathLen, int csidl, BOOL create) { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!lpszPath)) return 0; #endif if (lpszPath AND_IS_NOT_WIN9X) { WCHAR tmp[4096]; if (SHGetSpecialFolderPathW(hwndOwner,tmp,csidl,create)) { return WideCharToMultiByte(CP_UTF8,0,tmp,-1,lpszPath,pszPathLen,NULL,NULL) > 0; } } return SHGetSpecialFolderPathA(hwndOwner,lpszPath,csidl,create); } #if _MSC_VER > 1700 && defined(_WIN64) BOOL SHGetPathFromIDListUTF8(const struct _ITEMIDLIST __unaligned *pidl, LPSTR pszPath, int pszPathLen) #else BOOL SHGetPathFromIDListUTF8(const struct _ITEMIDLIST *pidl, LPSTR pszPath, int pszPathLen) #endif { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!pszPath)) return FALSE; #endif if (pszPath AND_IS_NOT_WIN9X) { const int alloc_sz = pszPathLen < 4096 ? 4096 : pszPathLen; WIDETOMB_ALLOC(wfn,alloc_sz); if (wfn) { BOOL b = FALSE; if (SHGetPathFromIDListW(pidl,wfn)) { b = WideCharToMultiByte(CP_UTF8,0,wfn,-1,pszPath,pszPathLen,NULL,NULL) > 0; } WIDETOMB_FREE(wfn); return b; } } return SHGetPathFromIDListA(pidl,pszPath); } struct _ITEMIDLIST *SHBrowseForFolderUTF8(struct _browseinfoA *bi) { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!bi)) return NULL; #endif if (bi && (WDL_HasUTF8(bi->pszDisplayName) || WDL_HasUTF8(bi->lpszTitle)) AND_IS_NOT_WIN9X) { MBTOWIDE(wfn,bi->pszDisplayName); if (wfn_ok) { MBTOWIDE(wtxt,bi->lpszTitle); if (wtxt_ok) { BROWSEINFOW biw ={ bi->hwndOwner,bi->pidlRoot,wfn,wtxt,bi->ulFlags,bi->lpfn,(LPARAM)bi->lParam,bi->iImage }; LPITEMIDLIST idlist = SHBrowseForFolderW(&biw); MBTOWIDE_FREE(wfn); MBTOWIDE_FREE(wtxt); return (struct _ITEMIDLIST *) idlist; } MBTOWIDE_FREE(wtxt); } MBTOWIDE_FREE(wfn); } return (struct _ITEMIDLIST *)SHBrowseForFolderA(bi); } int WDL_UTF8_SendBFFM_SETSEL(HWND hwnd, const char *str) { if (IS_NOT_WIN9X_AND WDL_HasUTF8(str)) { MBTOWIDE(wc, str); if (wc_ok) { int r=(int)SendMessage(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)wc); MBTOWIDE_FREE(wc); return r; } MBTOWIDE_FREE(wc); } return (int) SendMessage(hwnd, BFFM_SETSELECTIONA, 1, (LPARAM)str); } #endif BOOL SetCurrentDirectoryUTF8(LPCTSTR path) { if (WDL_HasUTF8_FILENAME(path) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,path); if (wbuf_ok) wdl_utf8_correctlongpath(wbuf); if (wbuf_ok) { BOOL rv=SetCurrentDirectoryW(wbuf); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } return SetCurrentDirectoryA(path); } BOOL RemoveDirectoryUTF8(LPCTSTR path) { if (WDL_HasUTF8_FILENAME(path) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,path); if (wbuf_ok) wdl_utf8_correctlongpath(wbuf); if (wbuf_ok) { BOOL rv=RemoveDirectoryW(wbuf); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } return RemoveDirectoryA(path); } HINSTANCE LoadLibraryUTF8(LPCTSTR path) { if (WDL_HasUTF8_FILENAME(path) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,path); if (wbuf_ok) wdl_utf8_correctlongpath(wbuf); if (wbuf_ok) { HINSTANCE rv=LoadLibraryW(wbuf); if (rv) { MBTOWIDE_FREE(wbuf); return rv; } } MBTOWIDE_FREE(wbuf); } return LoadLibraryA(path); } BOOL CreateDirectoryUTF8(LPCTSTR path, LPSECURITY_ATTRIBUTES attr) { if (WDL_HasUTF8_FILENAME(path) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,path); if (wbuf_ok) wdl_utf8_correctlongpath(wbuf); if (wbuf_ok) { BOOL rv=CreateDirectoryW(wbuf,attr); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } return CreateDirectoryA(path,attr); } BOOL DeleteFileUTF8(LPCTSTR path) { if (WDL_HasUTF8_FILENAME(path) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,path); if (wbuf_ok) wdl_utf8_correctlongpath(wbuf); if (wbuf_ok) { BOOL rv=DeleteFileW(wbuf); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } return DeleteFileA(path); } BOOL MoveFileUTF8(LPCTSTR existfn, LPCTSTR newfn) { if ((WDL_HasUTF8_FILENAME(existfn)||WDL_HasUTF8_FILENAME(newfn)) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,existfn); if (wbuf_ok) wdl_utf8_correctlongpath(wbuf); if (wbuf_ok) { MBTOWIDE(wbuf2,newfn); if (wbuf2_ok) wdl_utf8_correctlongpath(wbuf2); if (wbuf2_ok) { int rv=MoveFileW(wbuf,wbuf2); MBTOWIDE_FREE(wbuf2); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf2); } MBTOWIDE_FREE(wbuf); } return MoveFileA(existfn,newfn); } BOOL CopyFileUTF8(LPCTSTR existfn, LPCTSTR newfn, BOOL fie) { if ((WDL_HasUTF8_FILENAME(existfn)||WDL_HasUTF8_FILENAME(newfn)) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,existfn); if (wbuf_ok) wdl_utf8_correctlongpath(wbuf); if (wbuf_ok) { MBTOWIDE(wbuf2,newfn); if (wbuf2_ok) wdl_utf8_correctlongpath(wbuf2); if (wbuf2_ok) { int rv=CopyFileW(wbuf,wbuf2,fie); MBTOWIDE_FREE(wbuf2); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf2); } MBTOWIDE_FREE(wbuf); } return CopyFileA(existfn,newfn,fie); } DWORD GetModuleFileNameUTF8(HMODULE hModule, LPTSTR lpBuffer, DWORD nBufferLength) { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!lpBuffer||!nBufferLength)) return 0; #endif if (lpBuffer && nBufferLength > 1 AND_IS_NOT_WIN9X) { WCHAR wbuf[WDL_UTF8_MAXFNLEN]; wbuf[0]=0; if (GetModuleFileNameW(hModule,wbuf,WDL_UTF8_MAXFNLEN) && wbuf[0]) { int rv=WideCharToMultiByte(CP_UTF8,0,wbuf,-1,lpBuffer,nBufferLength,NULL,NULL); if (rv) return rv; } } return GetModuleFileNameA(hModule,lpBuffer,nBufferLength); } DWORD GetCurrentDirectoryUTF8(DWORD nBufferLength, LPTSTR lpBuffer) { if (lpBuffer && nBufferLength > 1 AND_IS_NOT_WIN9X) { WCHAR wbuf[WDL_UTF8_MAXFNLEN]; wbuf[0]=0; if (GetCurrentDirectoryW(WDL_UTF8_MAXFNLEN,wbuf) && wbuf[0]) { int rv=WideCharToMultiByte(CP_UTF8,0,wbuf,-1,lpBuffer,nBufferLength,NULL,NULL); if (rv) return rv; } } return GetCurrentDirectoryA(nBufferLength,lpBuffer); } HANDLE CreateFileUTF8(LPCTSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile) { if (WDL_HasUTF8_FILENAME(lpFileName) AND_IS_NOT_WIN9X) { HANDLE h = INVALID_HANDLE_VALUE; MBTOWIDE(wstr, lpFileName); if (wstr_ok) wdl_utf8_correctlongpath(wstr); if (wstr_ok) h = CreateFileW(wstr,dwDesiredAccess,dwShareMode,lpSecurityAttributes,dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile); MBTOWIDE_FREE(wstr); if (h != INVALID_HANDLE_VALUE) return h; } return CreateFileA(lpFileName,dwDesiredAccess,dwShareMode,lpSecurityAttributes,dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile); } int DrawTextUTF8(HDC hdc, LPCTSTR str, int nc, LPRECT lpRect, UINT format) { WDL_ASSERT((format & DT_SINGLELINE) || !(format & (DT_BOTTOM|DT_VCENTER))); // if DT_BOTTOM or DT_VCENTER used, must have DT_SINGLELINE if (WDL_HasUTF8(str) AND_IS_NOT_WIN9X) { if (nc<0) nc=(int)strlen(str); { MBTOWIDE(wstr, str); if (wstr_ok) { int rv=DrawTextW(hdc,wstr,-1,lpRect,format);; MBTOWIDE_FREE(wstr); return rv; } MBTOWIDE_FREE(wstr); } } return DrawTextA(hdc,str,nc,lpRect,format); } BOOL InsertMenuUTF8(HMENU hMenu, UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, LPCTSTR str) { if (!(uFlags&(MF_BITMAP|MF_SEPARATOR)) && str && WDL_HasUTF8(str) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,str); if (wbuf_ok) { BOOL rv=InsertMenuW(hMenu,uPosition,uFlags,uIDNewItem,wbuf); MBTOWIDE_FREE(wbuf); return rv; } } return InsertMenuA(hMenu,uPosition,uFlags,uIDNewItem,str); } BOOL InsertMenuItemUTF8( HMENU hMenu,UINT uItem, BOOL fByPosition, LPMENUITEMINFO lpmii) { if (!lpmii) return FALSE; if ((lpmii->fMask & MIIM_TYPE) && (lpmii->fType&(MFT_SEPARATOR|MFT_STRING|MFT_BITMAP)) == MFT_STRING && lpmii->dwTypeData && WDL_HasUTF8(lpmii->dwTypeData) AND_IS_NOT_WIN9X) { BOOL rv; MENUITEMINFOW tmp = *(MENUITEMINFOW*)lpmii; MBTOWIDE(wbuf,lpmii->dwTypeData); if (wbuf_ok) { tmp.cbSize=sizeof(tmp); tmp.dwTypeData = wbuf; rv=InsertMenuItemW(hMenu,uItem,fByPosition,&tmp); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } return InsertMenuItemA(hMenu,uItem,fByPosition,lpmii); } BOOL SetMenuItemInfoUTF8( HMENU hMenu,UINT uItem, BOOL fByPosition, LPMENUITEMINFO lpmii) { if (!lpmii) return FALSE; if ((lpmii->fMask & MIIM_TYPE) && (lpmii->fType&(MFT_SEPARATOR|MFT_STRING|MFT_BITMAP)) == MFT_STRING && lpmii->dwTypeData && WDL_HasUTF8(lpmii->dwTypeData) AND_IS_NOT_WIN9X) { BOOL rv; MENUITEMINFOW tmp = *(MENUITEMINFOW*)lpmii; MBTOWIDE(wbuf,lpmii->dwTypeData); if (wbuf_ok) { tmp.cbSize=sizeof(tmp); tmp.dwTypeData = wbuf; rv=SetMenuItemInfoW(hMenu,uItem,fByPosition,&tmp); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } return SetMenuItemInfoA(hMenu,uItem,fByPosition,lpmii); } BOOL GetMenuItemInfoUTF8( HMENU hMenu,UINT uItem, BOOL fByPosition, LPMENUITEMINFO lpmii) { if (!lpmii) return FALSE; if ((lpmii->fMask & MIIM_TYPE) && lpmii->dwTypeData && lpmii->cch AND_IS_NOT_WIN9X) { MENUITEMINFOW tmp = *(MENUITEMINFOW*)lpmii; WIDETOMB_ALLOC(wbuf,lpmii->cch); if (wbuf) { BOOL rv; char *otd=lpmii->dwTypeData; int osz=lpmii->cbSize; tmp.cbSize=sizeof(tmp); tmp.dwTypeData = wbuf; tmp.cch = (UINT)(wbuf_size/sizeof(WCHAR)); rv=GetMenuItemInfoW(hMenu,uItem,fByPosition,&tmp); if (rv && (tmp.fType&(MFT_SEPARATOR|MFT_STRING|MFT_BITMAP)) == MFT_STRING) { if (!WideCharToMultiByte(CP_UTF8,0,wbuf,-1,lpmii->dwTypeData,lpmii->cch,NULL,NULL)) { lpmii->dwTypeData[lpmii->cch-1]=0; } *lpmii = *(MENUITEMINFO*)&tmp; // copy results lpmii->cbSize=osz; // restore old stuff lpmii->dwTypeData = otd; } else rv=0; WIDETOMB_FREE(wbuf); if (rv)return rv; } } return GetMenuItemInfoA(hMenu,uItem,fByPosition,lpmii); } FILE *fopenUTF8(const char *filename, const char *mode) { if (WDL_HasUTF8_FILENAME(filename) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,filename); if (wbuf_ok) wdl_utf8_correctlongpath(wbuf); if (wbuf_ok) { FILE *rv; WCHAR tb[32]; tb[0]=0; MultiByteToWideChar(CP_UTF8,0,mode,-1,tb,32); rv=tb[0] ? _wfopen(wbuf,tb) : NULL; MBTOWIDE_FREE(wbuf); if (rv) return rv; } } #ifdef fopen #undef fopen #endif return fopen(filename,mode); #define fopen fopenUTF8 } int statUTF8(const char *filename, struct stat *buffer) { if (WDL_HasUTF8_FILENAME(filename) AND_IS_NOT_WIN9X) { MBTOWIDE(wbuf,filename); if (wbuf_ok) wdl_utf8_correctlongpath(wbuf); if (wbuf_ok) { int rv; rv=_wstat(wbuf,(struct _stat*)buffer); MBTOWIDE_FREE(wbuf); if (!rv) return rv; } else { MBTOWIDE_FREE(wbuf); } } return _stat(filename,(struct _stat*)buffer); } LPSTR GetCommandParametersUTF8() { char *buf; int szneeded; LPWSTR w=GetCommandLineW(); if (!w) return NULL; szneeded = WideCharToMultiByte(CP_UTF8,0,w,-1,NULL,0,NULL,NULL); if (szneeded<1) return NULL; buf = (char *)malloc(szneeded+10); if (!buf) return NULL; if (WideCharToMultiByte(CP_UTF8,0,w,-1,buf,szneeded+9,NULL,NULL)<1) return NULL; while (*buf == ' ') buf++; if (*buf == '\"') { buf++; while (*buf && *buf != '\"') buf++; } else { while (*buf && *buf != ' ') buf++; } if (*buf) buf++; while (*buf == ' ') buf++; if (*buf) return buf; return NULL; } int GetKeyNameTextUTF8(LONG lParam, LPTSTR lpString, int nMaxCount) { if (!lpString) return 0; if (nMaxCount>0 AND_IS_NOT_WIN9X) { WIDETOMB_ALLOC(wbuf, nMaxCount); if (wbuf) { const int v = GetKeyNameTextW(lParam,wbuf,(int) (wbuf_size/sizeof(WCHAR))); if (v) { lpString[0]=0; if (!WideCharToMultiByte(CP_UTF8,0,wbuf,-1,lpString,nMaxCount,NULL,NULL)) lpString[nMaxCount-1]=0; } WIDETOMB_FREE(wbuf); return v ? (int)strlen(lpString) : 0; } } return GetKeyNameTextA(lParam,lpString,nMaxCount); } HINSTANCE ShellExecuteUTF8(HWND hwnd, LPCTSTR lpOp, LPCTSTR lpFile, LPCTSTR lpParm, LPCTSTR lpDir, INT nShowCmd) { // wdl_utf8_correctlongpath? if (IS_NOT_WIN9X_AND (WDL_HasUTF8(lpOp)||WDL_HasUTF8(lpFile)||WDL_HasUTF8(lpParm)||WDL_HasUTF8(lpDir))) { DWORD sz; WCHAR *p1=lpOp ? WDL_UTF8ToWC(lpOp,0,0,&sz) : NULL; WCHAR *p2=lpFile ? WDL_UTF8ToWC(lpFile,0,0,&sz) : NULL; WCHAR *p3=lpParm ? WDL_UTF8ToWC(lpParm,0,0,&sz) : NULL; WCHAR *p4=lpDir ? WDL_UTF8ToWC(lpDir,0,0,&sz) : NULL; HINSTANCE rv= p2 ? ShellExecuteW(hwnd,p1,p2,p3,p4,nShowCmd) : NULL; free(p1); free(p2); free(p3); free(p4); return rv; } return ShellExecuteA(hwnd,lpOp,lpFile,lpParm,lpDir,nShowCmd); } BOOL GetUserNameUTF8(LPTSTR lpString, LPDWORD nMaxCount) { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!lpString||!nMaxCount)) return FALSE; #endif if (IS_NOT_WIN9X_AND lpString && nMaxCount) { WIDETOMB_ALLOC(wtmp,*nMaxCount); if (wtmp) { DWORD sz=(DWORD)(wtmp_size/sizeof(WCHAR)); BOOL r = GetUserNameW(wtmp, &sz); if (r && (!*nMaxCount || (!WideCharToMultiByte(CP_UTF8,0,wtmp,-1,lpString,*nMaxCount,NULL,NULL) && GetLastError()==ERROR_INSUFFICIENT_BUFFER))) { if (*nMaxCount>0) lpString[*nMaxCount-1]=0; *nMaxCount=(int)wcslen(wtmp)+1; r=FALSE; } else { *nMaxCount=sz; } WIDETOMB_FREE(wtmp); return r; } } return GetUserNameA(lpString, nMaxCount); } BOOL GetComputerNameUTF8(LPTSTR lpString, LPDWORD nMaxCount) { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!lpString||!nMaxCount)) return 0; #endif if (IS_NOT_WIN9X_AND lpString && nMaxCount) { WIDETOMB_ALLOC(wtmp,*nMaxCount); if (wtmp) { DWORD sz=(DWORD)(wtmp_size/sizeof(WCHAR)); BOOL r = GetComputerNameW(wtmp, &sz); if (r && (!*nMaxCount || (!WideCharToMultiByte(CP_UTF8,0,wtmp,-1,lpString,*nMaxCount,NULL,NULL) && GetLastError()==ERROR_INSUFFICIENT_BUFFER))) { if (*nMaxCount>0) lpString[*nMaxCount-1]=0; *nMaxCount=(int)wcslen(wtmp)+1; r=FALSE; } else { *nMaxCount=sz; } WIDETOMB_FREE(wtmp); return r; } } return GetComputerNameA(lpString, nMaxCount); } #define MBTOWIDE_NULLOK(symbase, src) \ int symbase##_size; \ WCHAR symbase##_buf[256]; \ WCHAR *symbase = (src)==NULL ? NULL : ((symbase##_size=MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,src,-1,NULL,0)) >= 248 ? (WCHAR *)malloc(symbase##_size * sizeof(WCHAR) + 10) : symbase##_buf); \ int symbase##_ok = symbase ? (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,src,-1,symbase,symbase##_size < 1 ? 256 : symbase##_size)) : (src)==NULL // these only bother using Wide versions if the filename has wide chars // (for now) #define PROFILESTR_COMMON_BEGIN(ret_type) \ if (IS_NOT_WIN9X_AND fnStr && WDL_HasUTF8(fnStr)) \ { \ BOOL do_rv = 0; \ ret_type rv = 0; \ MBTOWIDE(wfn,fnStr); \ MBTOWIDE_NULLOK(wapp,appStr); \ MBTOWIDE_NULLOK(wkey,keyStr); \ if (wfn_ok && wapp_ok && wkey_ok) { #define PROFILESTR_COMMON_END } /* wfn_ok etc */ \ MBTOWIDE_FREE(wfn); \ MBTOWIDE_FREE(wapp); \ MBTOWIDE_FREE(wkey); \ if (do_rv) return rv; \ } /* if has utf8 etc */ \ UINT GetPrivateProfileIntUTF8(LPCTSTR appStr, LPCTSTR keyStr, INT def, LPCTSTR fnStr) { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!fnStr || !keyStr || !appStr)) return 0; #endif PROFILESTR_COMMON_BEGIN(UINT) rv = GetPrivateProfileIntW(wapp,wkey,def,wfn); do_rv = 1; PROFILESTR_COMMON_END return GetPrivateProfileIntA(appStr,keyStr,def,fnStr); } DWORD GetPrivateProfileStringUTF8(LPCTSTR appStr, LPCTSTR keyStr, LPCTSTR defStr, LPTSTR retStr, DWORD nSize, LPCTSTR fnStr) { PROFILESTR_COMMON_BEGIN(DWORD) MBTOWIDE_NULLOK(wdef, defStr); WIDETOMB_ALLOC(buf, nSize); if (wdef_ok && buf) { const DWORD nullsz = (!wapp || !wkey) ? 2 : 1; rv = GetPrivateProfileStringW(wapp,wkey,wdef,buf,(DWORD) (buf_size / sizeof(WCHAR)),wfn); if (nSize<=nullsz) { memset(retStr,0,nSize); rv=0; } else { // rv does not include null character(s) if (rv>0) rv = WideCharToMultiByte(CP_UTF8,0,buf,rv,retStr,nSize-nullsz,NULL,NULL); if (rv > nSize-nullsz) rv=nSize-nullsz; memset(retStr + rv,0,nullsz); } do_rv = 1; } MBTOWIDE_FREE(wdef); WIDETOMB_FREE(buf); PROFILESTR_COMMON_END return GetPrivateProfileStringA(appStr,keyStr,defStr,retStr,nSize,fnStr); } BOOL WritePrivateProfileStringUTF8(LPCTSTR appStr, LPCTSTR keyStr, LPCTSTR str, LPCTSTR fnStr) { PROFILESTR_COMMON_BEGIN(BOOL) MBTOWIDE_NULLOK(wval, str); if (wval_ok) { rv = WritePrivateProfileStringW(wapp,wkey,wval,wfn); do_rv = 1; } MBTOWIDE_FREE(wval); PROFILESTR_COMMON_END return WritePrivateProfileStringA(appStr,keyStr,str,fnStr); } BOOL GetPrivateProfileStructUTF8(LPCTSTR appStr, LPCTSTR keyStr, LPVOID pStruct, UINT uSize, LPCTSTR fnStr) { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!fnStr || !keyStr || !appStr)) return 0; #endif PROFILESTR_COMMON_BEGIN(BOOL) rv = GetPrivateProfileStructW(wapp,wkey,pStruct,uSize,wfn); do_rv = 1; PROFILESTR_COMMON_END return GetPrivateProfileStructA(appStr,keyStr,pStruct,uSize,fnStr); } BOOL WritePrivateProfileStructUTF8(LPCTSTR appStr, LPCTSTR keyStr, LPVOID pStruct, UINT uSize, LPCTSTR fnStr) { #ifdef _DEBUG if (WDL_NOT_NORMALLY(!fnStr || !keyStr || !appStr)) return 0; #endif PROFILESTR_COMMON_BEGIN(BOOL) rv = WritePrivateProfileStructW(wapp,wkey,pStruct,uSize,wfn); do_rv = 1; PROFILESTR_COMMON_END return WritePrivateProfileStructA(appStr,keyStr,pStruct,uSize,fnStr); } #undef PROFILESTR_COMMON_BEGIN #undef PROFILESTR_COMMON_END BOOL CreateProcessUTF8(LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, // pointer to new environment block LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) { // wdl_utf8_correctlongpath? // special case ver if (IS_NOT_WIN9X_AND ( WDL_HasUTF8(lpApplicationName) || WDL_HasUTF8(lpCommandLine) || WDL_HasUTF8(lpCurrentDirectory) ) ) { MBTOWIDE_NULLOK(appn, lpApplicationName); MBTOWIDE_NULLOK(cmdl, lpCommandLine); MBTOWIDE_NULLOK(curd, lpCurrentDirectory); if (appn_ok && cmdl_ok && curd_ok) { BOOL rv; WCHAR *free1=NULL, *free2=NULL; char *save1=NULL, *save2=NULL; if (lpStartupInfo && lpStartupInfo->cb >= sizeof(STARTUPINFO)) { if (lpStartupInfo->lpDesktop) lpStartupInfo->lpDesktop = (char *) (free1 = WDL_UTF8ToWC(save1 = lpStartupInfo->lpDesktop,FALSE,0,NULL)); if (lpStartupInfo->lpTitle) lpStartupInfo->lpTitle = (char*) (free2 = WDL_UTF8ToWC(save2 = lpStartupInfo->lpTitle,FALSE,0,NULL)); } rv=CreateProcessW(appn,cmdl,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags, lpEnvironment,curd,(STARTUPINFOW*)lpStartupInfo,lpProcessInformation); if (lpStartupInfo && lpStartupInfo->cb >= sizeof(STARTUPINFO)) { lpStartupInfo->lpDesktop = save1; lpStartupInfo->lpTitle = save2; free(free1); free(free2); } MBTOWIDE_FREE(appn); MBTOWIDE_FREE(cmdl); MBTOWIDE_FREE(curd); return rv; } MBTOWIDE_FREE(appn); MBTOWIDE_FREE(cmdl); MBTOWIDE_FREE(curd); } return CreateProcessA(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation); } #if (defined(WDL_WIN32_UTF8_IMPL_NOTSTATIC) || defined(WDL_WIN32_UTF8_IMPL_STATICHOOKS)) && !defined(WDL_WIN32_UTF8_NO_UI_IMPL) static LRESULT WINAPI cb_newProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { WNDPROC oldproc = (WNDPROC)GetProp(hwnd,WDL_UTF8_OLDPROCPROP); if (!oldproc) return 0; if (msg==WM_NCDESTROY) { SetWindowLongPtr(hwnd, GWLP_WNDPROC,(INT_PTR)oldproc); RemoveProp(hwnd,WDL_UTF8_OLDPROCPROP); RemoveProp(hwnd,WDL_UTF8_OLDPROCPROP "W"); } else if (msg == CB_ADDSTRING || msg == CB_INSERTSTRING || msg == CB_FINDSTRINGEXACT || msg == CB_FINDSTRING || msg == LB_ADDSTRING || msg == LB_INSERTSTRING) { char *str=(char*)lParam; if (lParam && WDL_HasUTF8(str)) { MBTOWIDE(wbuf,str); if (wbuf_ok) { WNDPROC oldprocW = (WNDPROC)GetProp(hwnd,WDL_UTF8_OLDPROCPROP "W"); LRESULT rv=CallWindowProcW(oldprocW ? oldprocW : oldproc,hwnd,msg,wParam,(LPARAM)wbuf); MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } } else if ((msg == CB_GETLBTEXT || msg == LB_GETTEXTUTF8) && lParam) { WNDPROC oldprocW = (WNDPROC)GetProp(hwnd,WDL_UTF8_OLDPROCPROP "W"); LRESULT l = CallWindowProcW(oldprocW ? oldprocW : oldproc,hwnd,msg == CB_GETLBTEXT ? CB_GETLBTEXTLEN : LB_GETTEXTLEN,wParam,0); if (l != CB_ERR) { WIDETOMB_ALLOC(tmp,l+1); if (tmp) { LRESULT rv=CallWindowProcW(oldprocW ? oldprocW : oldproc,hwnd,msg & ~0x8000,wParam,(LPARAM)tmp); if (rv>=0) { *(char *)lParam=0; rv=WideCharToMultiByte(CP_UTF8,0,tmp,-1,(char *)lParam,((int)l)*4 + 32,NULL,NULL); if (rv>0) rv--; } WIDETOMB_FREE(tmp); return rv; } } } else if (msg == CB_GETLBTEXTLEN || msg == LB_GETTEXTLENUTF8) { WNDPROC oldprocW = (WNDPROC)GetProp(hwnd,WDL_UTF8_OLDPROCPROP "W"); return CallWindowProcW(oldprocW ? oldprocW : oldproc,hwnd,msg & ~0x8000,wParam,lParam) * 4 + 32; // make sure caller allocates a lot extra } return CallWindowProc(oldproc,hwnd,msg,wParam,lParam); } static int compareUTF8ToFilteredASCII(const char *utf, const char *ascii) { for (;;) { unsigned char c1 = (unsigned char)*ascii++; int c2; if (!*utf || !c1) return *utf || c1; utf += wdl_utf8_parsechar(utf, &c2); if (c1 != c2) { if (c2 < 128) return 1; // if not UTF-8 character, strings differ if (c1 != '?') return 1; // if UTF-8 and ASCII is not ?, strings differ } } } static LRESULT WINAPI cbedit_newProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { WNDPROC oldproc = (WNDPROC)GetProp(hwnd,WDL_UTF8_OLDPROCPROP); if (!oldproc) return 0; if (msg==WM_NCDESTROY) { SetWindowLongPtr(hwnd, GWLP_WNDPROC,(INT_PTR)oldproc); RemoveProp(hwnd,WDL_UTF8_OLDPROCPROP); RemoveProp(hwnd,WDL_UTF8_OLDPROCPROP "W"); } else if (msg == WM_SETTEXT && lParam && *(const char *)lParam) { WNDPROC oldproc2 = (WNDPROC)GetProp(hwnd,WDL_UTF8_OLDPROCPROP "W"); HWND par = GetParent(hwnd); int sel = (int) SendMessage(par,CB_GETCURSEL,0,0); if (sel>=0) { const int len = (int) SendMessage(par,CB_GETLBTEXTLEN,sel,0); char tmp[1024], *p = (len+1) <= sizeof(tmp) ? tmp : (char*)calloc(len+1,1); if (p) { SendMessage(par,CB_GETLBTEXT,sel,(LPARAM)p); if (WDL_DetectUTF8(p)>0 && !compareUTF8ToFilteredASCII(p,(const char *)lParam)) { MBTOWIDE(wbuf,p); if (wbuf_ok) { LRESULT ret = CallWindowProcW(oldproc2 ? oldproc2 : oldproc,hwnd,msg,wParam,(LPARAM)wbuf); MBTOWIDE_FREE(wbuf); if (p != tmp) free(p); return ret; } MBTOWIDE_FREE(wbuf); } if (p != tmp) free(p); } } } return CallWindowProc(oldproc,hwnd,msg,wParam,lParam); } void WDL_UTF8_HookListBox(HWND h) { if (!h|| #ifdef WDL_SUPPORT_WIN9X GetVersion()>=0x80000000|| #endif GetProp(h,WDL_UTF8_OLDPROCPROP)) return; SetProp(h,WDL_UTF8_OLDPROCPROP "W",(HANDLE)GetWindowLongPtrW(h,GWLP_WNDPROC)); SetProp(h,WDL_UTF8_OLDPROCPROP,(HANDLE)SetWindowLongPtr(h,GWLP_WNDPROC,(INT_PTR)cb_newProc)); } void WDL_UTF8_HookComboBox(HWND h) { WDL_UTF8_HookListBox(h); if (h && !s_combobox_atom) s_combobox_atom = (ATOM)GetClassWord(h,GCW_ATOM); if (h) { h = FindWindowEx(h,NULL,"Edit",NULL); if (h && !GetProp(h,WDL_UTF8_OLDPROCPROP)) { SetProp(h,WDL_UTF8_OLDPROCPROP "W",(HANDLE)GetWindowLongPtrW(h,GWLP_WNDPROC)); SetProp(h,WDL_UTF8_OLDPROCPROP,(HANDLE)SetWindowLongPtr(h,GWLP_WNDPROC,(INT_PTR)cbedit_newProc)); } } } static LRESULT WINAPI tc_newProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { WNDPROC oldproc = (WNDPROC)GetProp(hwnd,WDL_UTF8_OLDPROCPROP); if (!oldproc) return 0; if (msg==WM_NCDESTROY) { SetWindowLongPtr(hwnd, GWLP_WNDPROC,(INT_PTR)oldproc); RemoveProp(hwnd,WDL_UTF8_OLDPROCPROP); } else if (msg == TCM_INSERTITEMA) { LPTCITEM pItem = (LPTCITEM) lParam; char *str; if (pItem && (str=pItem->pszText) && (pItem->mask&TCIF_TEXT) && WDL_HasUTF8(str)) { MBTOWIDE(wbuf,str); if (wbuf_ok) { LRESULT rv; pItem->pszText=(char*)wbuf; // set new buffer rv=CallWindowProc(oldproc,hwnd,TCM_INSERTITEMW,wParam,lParam); pItem->pszText = str; // restore old pointer MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } } return CallWindowProc(oldproc,hwnd,msg,wParam,lParam); } static LRESULT WINAPI tv_newProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { WNDPROC oldproc = (WNDPROC)GetProp(hwnd,WDL_UTF8_OLDPROCPROP); if (!oldproc) return 0; if (msg==WM_NCDESTROY) { SetWindowLongPtr(hwnd, GWLP_WNDPROC,(INT_PTR)oldproc); RemoveProp(hwnd,WDL_UTF8_OLDPROCPROP); } else if (msg == TVM_INSERTITEMA || msg == TVM_SETITEMA) { LPTVITEM pItem = msg == TVM_INSERTITEMA ? &((LPTVINSERTSTRUCT)lParam)->item : (LPTVITEM) lParam; char *str; if (pItem && (str=pItem->pszText) && (pItem->mask&TVIF_TEXT) && WDL_HasUTF8(str)) { MBTOWIDE(wbuf,str); if (wbuf_ok) { LRESULT rv; pItem->pszText=(char*)wbuf; // set new buffer rv=CallWindowProc(oldproc,hwnd,msg == TVM_INSERTITEMA ? TVM_INSERTITEMW : TVM_SETITEMW,wParam,lParam); pItem->pszText = str; // restore old pointer MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } } else if (msg==TVM_GETITEMA) { LPTVITEM pItem = (LPTVITEM) lParam; char *obuf; if (pItem && (pItem->mask & TVIF_TEXT) && (obuf=pItem->pszText) && pItem->cchTextMax > 3) { WIDETOMB_ALLOC(wbuf,pItem->cchTextMax); if (wbuf) { LRESULT rv; int oldsz=pItem->cchTextMax; *wbuf=0; *obuf=0; pItem->cchTextMax=(int) (wbuf_size/sizeof(WCHAR)); pItem->pszText = (char *)wbuf; rv=CallWindowProc(oldproc,hwnd,TVM_GETITEMW,wParam,lParam); if (!WideCharToMultiByte(CP_UTF8,0,wbuf,-1,obuf,oldsz,NULL,NULL)) obuf[oldsz-1]=0; pItem->cchTextMax=oldsz; pItem->pszText=obuf; WIDETOMB_FREE(wbuf); if (obuf[0]) return rv; } } } return CallWindowProc(oldproc,hwnd,msg,wParam,lParam); } struct lv_tmpbuf_state { WCHAR *buf; int buf_sz; }; static LRESULT WINAPI lv_newProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { WNDPROC oldproc = (WNDPROC)GetProp(hwnd,WDL_UTF8_OLDPROCPROP); if (!oldproc) return 0; if (msg==WM_NCDESTROY) { struct lv_tmpbuf_state *buf = (struct lv_tmpbuf_state *)GetProp(hwnd,WDL_UTF8_OLDPROCPROP "B"); if (buf) { free(buf->buf); free(buf); } RemoveProp(hwnd,WDL_UTF8_OLDPROCPROP "B"); SetWindowLongPtr(hwnd, GWLP_WNDPROC,(INT_PTR)oldproc); RemoveProp(hwnd,WDL_UTF8_OLDPROCPROP); } else if (msg == LVM_INSERTCOLUMNA || msg==LVM_SETCOLUMNA) { LPLVCOLUMNA pCol = (LPLVCOLUMNA) lParam; char *str; if (pCol && (str=pCol->pszText) && (pCol->mask & LVCF_TEXT) && WDL_HasUTF8(str)) { MBTOWIDE(wbuf,str); if (wbuf_ok) { LRESULT rv; pCol->pszText=(char*)wbuf; // set new buffer rv=CallWindowProc(oldproc,hwnd,msg==LVM_INSERTCOLUMNA?LVM_INSERTCOLUMNW:LVM_SETCOLUMNW,wParam,lParam); pCol->pszText = str; // restore old pointer MBTOWIDE_FREE(wbuf); return rv; } } } else if (msg == LVM_INSERTITEMA || msg == LVM_SETITEMA || msg == LVM_SETITEMTEXTA) { LPLVITEMA pItem = (LPLVITEMA) lParam; char *str; if (pItem && pItem->pszText != LPSTR_TEXTCALLBACK && (str=pItem->pszText) && (msg==LVM_SETITEMTEXTA || (pItem->mask&LVIF_TEXT)) && WDL_HasUTF8(str)) { MBTOWIDE(wbuf,str); if (wbuf_ok) { LRESULT rv; pItem->pszText=(char*)wbuf; // set new buffer rv=CallWindowProc(oldproc,hwnd,msg == LVM_INSERTITEMA ? LVM_INSERTITEMW : msg == LVM_SETITEMA ? LVM_SETITEMW : LVM_SETITEMTEXTW,wParam,lParam); pItem->pszText = str; // restore old pointer MBTOWIDE_FREE(wbuf); return rv; } MBTOWIDE_FREE(wbuf); } } else if (msg==LVM_GETITEMA||msg==LVM_GETITEMTEXTA) { LPLVITEMA pItem = (LPLVITEMA) lParam; char *obuf; if (pItem && (msg == LVM_GETITEMTEXTA || (pItem->mask & LVIF_TEXT)) && (obuf=pItem->pszText) && pItem->cchTextMax > 3) { WIDETOMB_ALLOC(wbuf,pItem->cchTextMax); if (wbuf) { LRESULT rv; int oldsz=pItem->cchTextMax; *wbuf=0; *obuf=0; pItem->cchTextMax=(int) (wbuf_size/sizeof(WCHAR)); pItem->pszText = (char *)wbuf; rv=CallWindowProc(oldproc,hwnd,msg==LVM_GETITEMTEXTA ? LVM_GETITEMTEXTW : LVM_GETITEMW,wParam,lParam); if (!WideCharToMultiByte(CP_UTF8,0,wbuf,-1,obuf,oldsz,NULL,NULL)) obuf[oldsz-1]=0; pItem->cchTextMax=oldsz; pItem->pszText=obuf; WIDETOMB_FREE(wbuf); if (obuf[0]) return rv; } } } return CallWindowProc(oldproc,hwnd,msg,wParam,lParam); } void WDL_UTF8_HookListView(HWND h) { if (!h|| #ifdef WDL_SUPPORT_WIN9X GetVersion()>=0x80000000|| #endif GetProp(h,WDL_UTF8_OLDPROCPROP)) return; SetProp(h,WDL_UTF8_OLDPROCPROP,(HANDLE)SetWindowLongPtr(h,GWLP_WNDPROC,(INT_PTR)lv_newProc)); SetProp(h,WDL_UTF8_OLDPROCPROP "B", (HANDLE)calloc(sizeof(struct lv_tmpbuf_state),1)); } void WDL_UTF8_HookTreeView(HWND h) { if (!h|| #ifdef WDL_SUPPORT_WIN9X GetVersion()>=0x80000000|| #endif GetProp(h,WDL_UTF8_OLDPROCPROP)) return; SetProp(h,WDL_UTF8_OLDPROCPROP,(HANDLE)SetWindowLongPtr(h,GWLP_WNDPROC,(INT_PTR)tv_newProc)); } void WDL_UTF8_HookTabCtrl(HWND h) { if (!h|| #ifdef WDL_SUPPORT_WIN9X GetVersion()>=0x80000000|| #endif GetProp(h,WDL_UTF8_OLDPROCPROP)) return; SetProp(h,WDL_UTF8_OLDPROCPROP,(HANDLE)SetWindowLongPtr(h,GWLP_WNDPROC,(INT_PTR)tc_newProc)); } void WDL_UTF8_ListViewConvertDispInfoToW(void *_di) { NMLVDISPINFO *di = (NMLVDISPINFO *)_di; if (di && (di->item.mask & LVIF_TEXT) && di->item.pszText && di->item.cchTextMax>0) { static struct lv_tmpbuf_state s_buf; const char *src = (const char *)di->item.pszText; const size_t src_sz = strlen(src); struct lv_tmpbuf_state *sb = (struct lv_tmpbuf_state *)GetProp(di->hdr.hwndFrom,WDL_UTF8_OLDPROCPROP "B"); if (WDL_NOT_NORMALLY(!sb)) sb = &s_buf; // if the caller forgot to call HookListView... if (!sb->buf || sb->buf_sz < src_sz) { const int newsz = (int) wdl_min(src_sz * 2 + 256, 0x7fffFFFF); if (!sb->buf || sb->buf_sz < newsz) { free(sb->buf); sb->buf = (WCHAR *)malloc((sb->buf_sz = newsz) * sizeof(WCHAR)); } } if (WDL_NOT_NORMALLY(!sb->buf)) { di->item.pszText = (char*)L""; return; } di->item.pszText = (char*)sb->buf; if (!MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,src,-1,sb->buf,sb->buf_sz)) { if (WDL_NOT_NORMALLY(GetLastError()==ERROR_INSUFFICIENT_BUFFER)) { sb->buf[sb->buf_sz-1] = 0; } else { if (!MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,src,-1,sb->buf,sb->buf_sz)) sb->buf[sb->buf_sz-1] = 0; } } } } #endif #ifdef __cplusplus }; #endif #endif #endif //_WIN32