Files
tlib/oversampling/WDL/win32_utf8.c
2024-05-24 13:28:31 +02:00

1651 lines
44 KiB
C

#if defined(_WIN32) && !defined(WDL_WIN32_UTF8_NO_UI_IMPL)
#include <shlobj.h>
#include <commctrl.h>
#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 (size<minsize)size=minsize;
{
WCHAR *outbuf = (WCHAR *)malloc(sizeof(WCHAR)*(size+128));
if (!outbuf) return NULL;
*outbuf=0;
if (srclen>1)
{
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