Finally the answer I was looking for (not the one I was hoping for, but still :))). I understand I can't get FindResource to behave reliably and consistently on variety of setups. With or without SetThreadLocale.
But I'm not ready to give up yet!!! I'm stubborn like that... :)) Here's my solution:
/////////////////////////////////////////////////////////////////////////LPVOID LoadResourceEx( HINSTANCE hInstance, LPCTSTR lpType, LPCTSTR lpName, WORD wLanguage, HRSRC *phrsrc=NULL )
{
HRSRC hrsrc=FindResourceEx(hInstance,lpType,lpName,wLanguage);
if (!hrsrc) hrsrc=FindResource(hInstance,lpName,lpType);
if (!hrsrc) return NULL;
if (phrsrc) *phrsrc=hrsrc;
HGLOBAL hglb=LoadResource(hInstance,hrsrc);
if (!hglb) return NULL;
return LockResource(hglb);
}
/////////////////////////////////////////////////////////////////////////HACCEL LoadAcceleratorsEx( HINSTANCE hInstance, LPCTSTR lpTableName, WORD wLanguage )
{
HRSRC hrsrc;
LPVOID lpsz=LoadResourceEx(hInstance,RT_ACCELERATOR,lpTableName,wLanguage,&hrsrc);
if (!lpsz) return NULL;
struct ACCELTABLEENTRY {
WORD fFlags;
WORD wAnsi;
WORD wId;
WORD padding;
};
ACCELTABLEENTRY *src=(ACCELTABLEENTRY *)lpsz;
int n=SizeofResource(hInstance,hrsrc)/sizeof(ACCELTABLEENTRY);
ACCEL *dst=(ACCEL*)malloc(n*sizeof(ACCEL));
if (!dst) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
for (int i=0;i<n;i) {
dst[i].fVirt=src[i].fFlags&(FALT|FCONTROL|FNOINVERT|FSHIFT|FVIRTKEY);
dst[i].key=src[i].wAnsi;
dst[i].cmd=src[i].wId;
}
HACCEL hacc=CreateAcceleratorTable(dst,n);
free(dst);
return hacc;
}
/////////////////////////////////////////////////////////////////////////HMENU LoadMenuEx( HINSTANCE hInstance, LPCTSTR lpMenuName, WORD wLanguage )
{
LPVOID lpsz=LoadResourceEx(hInstance,RT_MENU,lpMenuName,wLanguage);
if (!lpsz) return NULL;
return LoadMenuIndirect(lpsz);
}
/////////////////////////////////////////////////////////////////////////INT_PTR DialogBoxParamEx( HINSTANCE hInstance, LPCTSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam, WORD wLanguage )
{
LPVOID lpsz=LoadResourceEx(hInstance,RT_DIALOG,lpTemplateName,wLanguage);
if (!lpsz) return -1;
return DialogBoxIndirectParam(hInstance,(DLGTEMPLATE*)lpsz,hWndParent,lpDialogFunc,dwInitParam);
}
/////////////////////////////////////////////////////////////////////////HWND CreateDialogParamEx( HINSTANCE hInstance, LPCTSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam, WORD wLanguage )
{
LPVOID lpsz=LoadResourceEx(hInstance,RT_DIALOG,lpTemplateName,wLanguage);
if (!lpsz) return NULL;
return CreateDialogIndirectParam(hInstance,(DLGTEMPLATE*)lpsz,hWndParent,lpDialogFunc,dwInitParam);
}
/////////////////////////////////////////////////////////////////////////INT_PTR DialogBoxEx( HINSTANCE hInstance, LPCTSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, WORD wLanguage )
{
return DialogBoxParamEx(hInstance,lpTemplateName,hWndParent,lpDialogFunc,0,wLanguage);
}
/////////////////////////////////////////////////////////////////////////HWND CreateDialogEx( HINSTANCE hInstance, LPCTSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, WORD wLanguage )
{
return CreateDialogParamEx(hInstance,lpTemplateName,hWndParent,lpDialogFunc,0,wLanguage);
}
/////////////////////////////////////////////////////////////////////////int LoadStringEx( HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage )
{
uID=16;
if (uID&~0xFFFFF) {
SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
return 0;
}
WORD *data=(WORD*)LoadResourceEx(hInstance,RT_STRING,MAKEINTRESOURCE(uID>>4),wLanguage);
if (!data) return 0;
int n=uID&15;
for (int i=0;i<n;i)
data=*data;
int len=*data;
if (len==0) return 0;
data;
#ifdef _UNICODE
if (len>nBufferMax-1) len=nBufferMax-1;
memcpy(lpBuffer,data,len*2);
lpBuffer[len]=0;
return len;
#else
int len2=WideCharToMultiByte(CP_ACP,0,data,len,NULL,NULL,0,NULL);
if (len2>nBufferMax-1) len2=nBufferMax-1;
WideCharToMultiByte(CP_ACP,0,data,len,lpBuffer,len2,0,NULL);
lpBuffer[len2]=0;
return len2;
#endif
}
/////////////////////////////////////////////////////////////////////////There can be similar functions for icons, cursors, bitmaps, etc. but I think they are less likely to change from language to language.