windows-nt/Source/XPSP1/NT/base/mvdm/wow32/wres16.c
2020-09-26 16:20:57 +08:00

686 lines
20 KiB
C

/*++
*
* WOW v1.0
*
* Copyright (c) 1991, Microsoft Corporation
*
* WRES16.C
* WOW32 16-bit resource support
*
* History:
* Created 11-Mar-1991 by Jeff Parsons (jeffpar)
--*/
#include "precomp.h"
#pragma hdrstop
//
// BUGBUG: moved macros from mvdm.h and wo32.h
// as they are not what they appear to be.
// Watch out these macros increment the pointer arguments!!!!
// 02-Feb-1994 Jonle
//
#define VALIDPUT(p) ((UINT)p>65535)
#define PUTWORD(p,w) {if (VALIDPUT(p)) *(PWORD)p=w; ((PWORD)p)++; }
#define PUTDWORD(p,d) {if (VALIDPUT(p)) *(PDWORD)p=d;((PDWORD)p)++;}
#define PUTUDWORD(p,d) {if (VALIDPUT(p)) *(DWORD UNALIGNED *)p=d;((DWORD UNALIGNED *)p)++;}
#define GETWORD(pb) (*((UNALIGNED WORD *)pb)++)
#define GETDWORD(pb) (*((UNALIGNED DWORD *)pb)++)
#define ADVGET(p,i) {(UINT)p+=i;}
#define ADVPUT(p,i) {(UINT)p+=i;}
#define ALIGNWORD(p) {(UINT)p+=( ((UINT)p)&(sizeof(WORD)-1));}
#define ALIGNDWORD(p) {(UINT)p+=(-((INT)p)&(sizeof(DWORD)-1));}
MODNAME(wres16.c);
PRES presFirst; // pointer to first RES entry
#ifdef DEBUG
typedef struct _RTINFO { /* rt */
LPSTR lpType; // predefined resource type
PSZ pszName; // name of type
} RTINFO, *PRTINFO;
RTINFO artInfo[] = {
{RT_CURSOR, "CURSOR"},
{RT_BITMAP, "BITMAP"},
{RT_ICON, "ICON"},
{RT_MENU, "MENU"},
{RT_DIALOG, "DIALOG"},
{RT_STRING, "STRING"},
{RT_FONTDIR, "FONTDIR"},
{RT_FONT, "FONT"},
{RT_ACCELERATOR, "ACCELERATOR"},
{RT_RCDATA, "RCDATA"},
{RT_MESSAGETABLE,"MESSAGETABLE"},
{RT_GROUP_CURSOR,"CURSOR DIRECTORY"},
{RT_GROUP_ICON, "ICON DIRECTORY"},
};
PSZ GetResourceType(LPSZ lpszType)
{
INT i;
register PRTINFO prt;
if (HIWORD(lpszType) != 0)
return lpszType;
for (prt=artInfo,i=NUMEL(artInfo); i>0; i--,prt++)
if (prt->lpType == lpszType)
return prt->pszName;
return "UNKNOWN";
}
#endif
/* Resource management functions
*/
PRES AddRes16(HMOD16 hmod16, WORD wExeVer, HRESI16 hresinfo16, LPSZ lpszType)
{
register PRES pres;
if (pres = malloc_w(sizeof(RES))) {
// Initialize the structure
pres->hmod16 = hmod16;
pres->wExeVer = wExeVer;
pres->flState = 0;
pres->hresinfo16 = hresinfo16;
pres->hresdata16 = 0;
pres->lpszResType = lpszType;
pres->pbResData = NULL;
// And then link it in
pres->presNext = presFirst;
presFirst = pres;
return pres;
}
return NULL;
}
VOID FreeRes16(PRES presFree)
{
register PRES pres, presPrev;
presPrev = (PRES)(&presFirst);
while (pres = presPrev->presNext) {
if (pres == presFree)
break;
presPrev = pres;
}
// Changed from WOW32ASSERT by cmjones 11/3/97
// This might be a bogus warning in that USER32!SplFreeResource() calls
// W32FreeResource() twice on certain types of resources. The Warning
// might be raised on the 2nd call after the resource was just freed.
// The only known occurances are at the start of the Winstone '94
// Quattro Pro test. This can safely be ignored if you see SplFreeResource
// in the stack dump.
WOW32WARNMSG((pres),("WOW::FreeRes16:Possible lost resource.\n"));
if (pres) {
presPrev->presNext = pres->presNext;
if (pres->pbResData)
UnlockResource16(pres);
free_w(pres);
}
}
VOID DestroyRes16(HMOD16 hmod16)
{
register PRES pres, presPrev;
presPrev = (PRES)(&presFirst);
while (pres = presPrev->presNext) {
if (pres->hmod16 == hmod16) {
LOGDEBUG(5,("Freeing resource info for current terminating task\n"));
// Now basically do a FreeRes16
presPrev->presNext = pres->presNext;
if (pres->pbResData)
UnlockResource16(pres);
free_w(pres);
} else {
presPrev = pres;
}
}
}
PRES FindResource16(HMOD16 hmod16, LPSZ lpszName, LPSZ lpszType)
{
INT cb;
PRES pres = NULL;
VPVOID vp=0;
PARM16 Parm16;
VPSZ vpszName = 0, vpszType = 0;
WORD wExpWinVer;
if (HIWORD(lpszName) == 0) {
vpszName = (VPSZ)lpszName;
LOGDEBUG(5,(" Finding resource %lx, type %s(%lx)\n",
lpszName, GetResourceType(lpszType), lpszType));
} else {
#ifdef FE_SB
if (CURRENTPTD()->dwWOWCompatFlagsFE & WOWCF_FE_ARIRANG20_PRNDLG) {
/*
* In case of Korean Arirang2.0 word processor, it use wrong dialog ID
* for Print or Print setup dialog. See dialog box ID on awpfont.dll.
*/
if (!WOW32_strcmp(lpszName, "PRINTDLGTEMP"))
vpszName = (VPSZ) 2;
else if(!WOW32_strcmp(lpszName, "PRNSETUPDLGTEMP"))
vpszName = (VPSZ) 1;
else goto NOT_ARIRANG20;
} else { // original code
NOT_ARIRANG20:
#endif
cb = strlen(lpszName)+1;
if (vpszName = GlobalAllocLock16(GMEM_MOVEABLE, cb, NULL))
putstr16(vpszName, lpszName, cb);
LOGDEBUG(5,(" Finding resource \"%s\", type %s(%lx)\n",
lpszName, GetResourceType(lpszType), lpszType));
#ifdef FE_SB
}
#endif
}
if (vpszName) {
if (HIWORD(lpszType) == 0) { // predefined resource
vpszType = (VPSZ)lpszType; // no doubt from MAKEINTRESOURCE
} else {
cb = strlen(lpszType)+1;
if (vpszType = GlobalAllocLock16(GMEM_MOVEABLE, cb, NULL)) {
putstr16(vpszType, lpszType, cb);
}
}
if (vpszType) {
Parm16.WndProc.wParam = hmod16;
Parm16.WndProc.lParam = vpszName;
Parm16.WndProc.wMsg = LOWORD(vpszType);
Parm16.WndProc.hwnd = HIWORD(vpszType);
CallBack16(RET_FINDRESOURCE, &Parm16, 0, &vp);
wExpWinVer = LOWORD(Parm16.WndProc.lParam);
if (HIWORD(vpszType))
GlobalUnlockFree16(vpszType);
}
if (HIWORD(vpszName))
GlobalUnlockFree16(vpszName);
}
if ((HRESI16)vp) {
pres = AddRes16(hmod16,wExpWinVer,(HRESI16)vp, lpszType);
}
return pres;
}
PRES LoadResource16(HMOD16 hmod16, PRES pres)
{
VPVOID vp=0;
PARM16 Parm16;
DBG_UNREFERENCED_PARAMETER(hmod16);
WOW32ASSERT(pres && hmod16 == pres->hmod16);
Parm16.WndProc.wParam = pres->hmod16;
Parm16.WndProc.lParam = pres->hresinfo16;
CallBack16(RET_LOADRESOURCE, &Parm16, 0, &vp);
if (pres->hresdata16 = (HRESD16)vp)
return pres;
// BUGBUG -- On a LoadResource failure, WIN32 is not required to do a
// corresponding FreeResource, so our RES structure will hang around until
// task termination clean-up (which may be OK) -JTP
return NULL;
}
BOOL FreeResource16(PRES pres)
{
VPVOID vp=0;
PARM16 Parm16;
WOW32ASSERT(pres);
Parm16.WndProc.wParam = pres->hresdata16;
CallBack16(RET_FREERESOURCE, &Parm16, 0, &vp);
FreeRes16(pres);
return (BOOL)vp;
}
LPBYTE LockResource16(register PRES pres)
{
DWORD cb, cb16;
VPVOID vp=0;
PARM16 Parm16;
WOW32ASSERT(pres);
Parm16.WndProc.wParam = pres->hresdata16;
CallBack16(RET_LOCKRESOURCE, &Parm16, 0, &vp);
if (vp) {
// Get size of 16-bit resource
cb16 = Parm16.WndProc.lParam;
LOGDEBUG(5,(" Locking/converting resource type %s(%lx)\n",
GetResourceType(pres->lpszResType), pres->lpszResType));
// Handle known resource types here
if (pres->lpszResType) {
switch((INT)pres->lpszResType) {
case (INT)RT_MENU:
// cb = ConvertMenu16(pres->wExeVer, NULL, vp, cb, cb16);
cb = cb16 * sizeof(WCHAR); // see SizeofResource16
if (cb && (pres->pbResData = malloc_w(cb)))
ConvertMenu16(pres->wExeVer, pres->pbResData, vp, cb, cb16);
return pres->pbResData;
case (INT)RT_DIALOG:
// cb = ConvertDialog16(NULL, vp, cb, cb16);
cb = cb16 * sizeof(WCHAR); // see SizeofResource16
if (cb && (pres->pbResData = malloc_w(cb)))
ConvertDialog16(pres->pbResData, vp, cb, cb16);
return pres->pbResData;
case (INT)RT_ACCELERATOR:
WOW32ASSERT(FALSE); // never should we come here.
return NULL;
// case (INT)RT_GROUP_CURSOR:
// case (INT)RT_GROUP_ICON:
// GETOPTPTR(vp, 0, lp);
// return lp;
}
}
// If we're still here, get desperate and return a simple 32-bit alias
GETVDMPTR(vp, cb16, pres->pbResData);
pres->flState |= RES_ALIASPTR;
return pres->pbResData;
}
// If we're still here, nothing worked
return NULL;
}
BOOL UnlockResource16(PRES pres)
{
VPVOID vp=0;
PARM16 Parm16;
WOW32ASSERT(pres);
Parm16.WndProc.wParam = pres->hresdata16;
CallBack16(RET_UNLOCKRESOURCE, &Parm16, 0, &vp);
if (pres->pbResData && !(pres->flState & RES_ALIASPTR))
free_w(pres->pbResData);
pres->pbResData = NULL;
pres->flState &= ~RES_ALIASPTR;
return (BOOL)vp;
}
DWORD SizeofResource16(HMOD16 hmod16, PRES pres)
{
VPVOID vp=0;
DWORD cbData;
PARM16 Parm16;
DBG_UNREFERENCED_PARAMETER(hmod16);
WOW32ASSERT(pres && hmod16 == pres->hmod16);
Parm16.WndProc.wParam = pres->hmod16;
Parm16.WndProc.lParam = pres->hresinfo16;
CallBack16(RET_SIZEOFRESOURCE, &Parm16, 0, &vp);
cbData = (DWORD)vp;
/*
* Adjust the size of the resource if they are different
* between NT and Windows
*/
// Handle known resource types here
if (pres->lpszResType) {
switch((INT)pres->lpszResType) {
case (INT)RT_MENU:
case (INT)RT_DIALOG:
// If we need an exact count then we would have to enable this code
// but currently the count is only used in USER to alloc enough space
// in the client\server transition windows.
// WARNING - if this code is re-enabled you must also change LockResource16
// CallBack16(RET_LOADRESOURCE, &Parm16, 0, &vpResLoad);
// CallBack16(RET_LOCKRESOURCE, vpResLoad, 0, &vp);
// if ((INT)pres->lpszResType == RT_MENU)
// cbData = (DWORD)ConvertMenu16(pres->wExeVer, NULL, vp, cbData);
// else
// cbData = (DWORD)ConvertDialog16(NULL, vp, cbData);
// CallBack16(RET_UNLOCKRESOURCE, &Parm16, 0, &vp);
cbData = (DWORD)((DWORD)vp * sizeof(WCHAR));
break;
case (INT)RT_STRING:
cbData = (DWORD)((DWORD)vp * sizeof(WCHAR));
break;
}
}
return cbData;
}
/*
* ConvertMenu16
*
* If pmenu32 is NULL then its just a size query
*
* Returns the number of bytes in the CONVERTED menu
*/
DWORD ConvertMenu16(WORD wExeVer, PBYTE pmenu32, VPBYTE vpmenu16, DWORD cb, DWORD cb16)
{
WORD wVer, wOffset;
PBYTE pmenu16, pmenu16Save;
PBYTE pmenu32T = pmenu32;
pmenu16 = GETVDMPTR(vpmenu16, cb16, pmenu16Save);
wVer = 0;
if (wExeVer >= 0x300)
wVer = GETWORD(pmenu16);
PUTWORD(pmenu32, wVer); // transfer versionNumber
wOffset = 0;
if (wExeVer >= 0x300)
wOffset = GETWORD(pmenu16);
PUTWORD(pmenu32, wOffset); // transfer offset
ADVGET(pmenu16, wOffset); // and advance by offset
ADVPUT(pmenu32, wOffset);
ALIGNWORD(pmenu32); // this is the DIFFERENCE for WIN32
cb = pmenu32 - pmenu32T; // pmenu32 will == 4 for size queries
cb += ConvertMenuItems16(wExeVer, &pmenu32, &pmenu16, vpmenu16+(pmenu16 - pmenu16Save));
FREEVDMPTR(pmenu16Save);
RETURN(cb);
}
/*
* ConvertMenuItems16
*
* Returns the number of bytes in the CONVERTED menu
* Note: This can be called with ppmenu32==4 which means the caller is looking
* for the size to allocate for the 32-bit menu structure.
*/
DWORD ConvertMenuItems16(WORD wExeVer, PPBYTE ppmenu32, PPBYTE ppmenu16, VPBYTE vpmenu16)
{
INT cbAnsi;
DWORD cbTotal = 0;
UINT cbUni;
WORD wOption, wID;
PBYTE pmenu32 = *ppmenu32;
PBYTE pmenu16 = *ppmenu16;
PBYTE pmenu16T = pmenu16;
PBYTE pmenu32T = pmenu32;
do {
if (wExeVer < 0x300)
wOption = GETBYTE(pmenu16);
else
wOption = GETWORD(pmenu16);
PUTWORD(pmenu32, wOption); // transfer mtOption
if (!(wOption & MF_POPUP)) {
wID = GETWORD(pmenu16);
PUTWORD(pmenu32, wID); // transfer mtID
}
cbAnsi = strlen(pmenu16)+1;
// If this is an ownerdraw menu don't copy the ANSI memu string to
// Unicode. Put a 16:16 pointer into the 32-bit resource which
// points to menu string instead. User will place this pointer in
// MEASUREITEMSTRUCT->itemData before sending WM_MEASUREITEM. If it's a
// NULL string User will place a NULL in MEASUREITEMSTRUCT->itemData.
// Chess Master and Mavis Beacon Teaches Typing depend on this.
if ((wOption & MFT_OWNERDRAW) && *pmenu16) {
if (VALIDPUT(pmenu32)) {
*(DWORD UNALIGNED *)pmenu32 = vpmenu16 + (pmenu16 - pmenu16T);
}
cbUni = sizeof(DWORD);
}
else {
if (VALIDPUT(pmenu32)) {
RtlMultiByteToUnicodeN((LPWSTR)pmenu32, MAXULONG, (PULONG)&cbUni, pmenu16, cbAnsi);
}
else {
cbUni = cbAnsi * sizeof(WCHAR);
}
}
ADVGET(pmenu16, cbAnsi);
ADVPUT(pmenu32, cbUni);
ALIGNWORD(pmenu32); // this is the DIFFERENCE for WIN32
if (wOption & MF_POPUP)
cbTotal += ConvertMenuItems16(wExeVer, &pmenu32, &pmenu16, vpmenu16+(pmenu16 - pmenu16T));
} while (!(wOption & MF_END));
*ppmenu32 = pmenu32;
*ppmenu16 = pmenu16;
return (pmenu32 - pmenu32T);
}
DWORD ConvertDialog16(PBYTE pdlg32, VPBYTE vpdlg16, DWORD cb, DWORD cb16)
{
BYTE b;
WORD w;
DWORD dwStyle;
INT i, cItems;
UINT cbAnsi;
UINT cbUni;
PBYTE pdlg16, pdlg16Save;
PBYTE pdlg32T = pdlg32;
pdlg16 = GETVDMPTR(vpdlg16, cb16, pdlg16Save);
dwStyle = GETDWORD(pdlg16);
PUTDWORD(pdlg32, dwStyle); // transfer style
PUTDWORD(pdlg32, 0); // Add NEW extended style
cItems = GETBYTE(pdlg16);
PUTWORD(pdlg32, (WORD)cItems); // stretch count to WORD for WIN32
for (i=0; i<4; i++) {
w = GETWORD(pdlg16);
PUTWORD(pdlg32, w); // transfer x & y, then cx & cy
}
//
// the next three fields are all strings (possibly null)
// menuname, classname, captiontext
// the Menu string can be encoded as ff nn mm which
// means that the menu id is ordinal mmnn
//
for (i=0; i<3; i++) {
if (i==0 && *pdlg16 == 0xFF) { // special encoding of szMenuName
GETBYTE(pdlg16); // advance past the ff byte
PUTWORD(pdlg32, 0xffff); // copy the f word
w = GETWORD(pdlg16); // get the menu ordinal
PUTWORD(pdlg32, w); // transfer it
} else { // ordinary string
cbAnsi = strlen(pdlg16)+1;
if (VALIDPUT(pdlg32)) {
RtlMultiByteToUnicodeN((LPWSTR)pdlg32, MAXULONG, (PULONG)&cbUni, pdlg16, cbAnsi);
} else {
cbUni = cbAnsi * sizeof(WCHAR);
}
ADVGET(pdlg16, cbAnsi);
ADVPUT(pdlg32, cbUni);
ALIGNWORD(pdlg32); // fix next field alignment for WIN32
}
}
if (dwStyle & DS_SETFONT) {
w = GETWORD(pdlg16);
PUTWORD(pdlg32, w); // transfer cPoints
cbAnsi = strlen(pdlg16)+1; // then szTypeFace
if (VALIDPUT(pdlg32)) {
RtlMultiByteToUnicodeN((LPWSTR)pdlg32, MAXULONG, (PULONG)&cbUni, pdlg16, cbAnsi);
#ifdef FE_SB
// orignal source should be fixed.
// We can't convert right Unicode string from Broken FaceName
// string.
// Converted Unicode String should be NULL terminated.
// 1994.11.12 V-HIDEKK
if( cbUni && ((LPWSTR)pdlg32)[cbUni/sizeof(WCHAR)-1] ){
LOGDEBUG(0,(" ConvertDialog16: WARNING: BAD FaceName String\n End of Unicode String (%04x)\n", ((LPWSTR)pdlg32)[cbUni/2-1]));
((LPWSTR)pdlg32)[cbUni/sizeof(WCHAR)-1] = 0;
}
#endif // FE_SB
} else {
cbUni = cbAnsi * sizeof(WCHAR);
}
ADVGET(pdlg16, cbAnsi);
ADVPUT(pdlg32, cbUni);
}
while (cItems--) {
ALIGNDWORD(pdlg32); // items start on DWORD boundaries
PUTDWORD(pdlg32, FETCHDWORD(*(PDWORD)(pdlg16+sizeof(WORD)*5)));
PUTDWORD(pdlg32, 0); // Add NEW extended style
for (i=0; i<5; i++) {
w = GETWORD(pdlg16);
PUTWORD(pdlg32, w); // transfer x & y, then cx & cy, then id
}
ADVGET(pdlg16, sizeof(DWORD)); // skip style, which we already copied
//
// get the class name could be string or encoded value
// win16 encoding scheme: class is 1 byte with bit 0x80 set,
// this byte == predefined class
// win32 encoding: a word of ffff, followed by class (word)
//
if (*pdlg16 & 0x80) {
PUTWORD(pdlg32, 0xFFFF); // NEW encoding marker 0xFFFF
b = GETBYTE(pdlg16); // special encoding for predefined class
PUTWORD(pdlg32, (WORD)b);
} else {
cbAnsi = strlen(pdlg16)+1;
if (VALIDPUT(pdlg32)) { // transfer szClass
RtlMultiByteToUnicodeN((LPWSTR)pdlg32, MAXULONG, (PULONG)&cbUni, pdlg16, cbAnsi);
} else {
cbUni = cbAnsi * sizeof(WCHAR);
}
ADVGET(pdlg16, cbAnsi);
ADVPUT(pdlg32, cbUni);
}
ALIGNWORD(pdlg32); // fix next field alignment for WIN32
//
// transfer the item text
//
if (*pdlg16 == 0xFF) { // special encoding
GETBYTE(pdlg16);
PUTWORD(pdlg32, 0xFFFF);
w = GETWORD(pdlg16);
PUTWORD(pdlg32, w);
} else {
cbAnsi = strlen(pdlg16)+1;
if (VALIDPUT(pdlg32)) { // otherwise, just transfer szText
RtlMultiByteToUnicodeN((LPWSTR)pdlg32, MAXULONG, (PULONG)&cbUni, pdlg16, cbAnsi);
} else {
cbUni = cbAnsi * sizeof(WCHAR);
}
ADVGET(pdlg16, cbAnsi);
ADVPUT(pdlg32, cbUni);
}
ALIGNWORD(pdlg32); // fix next field alignment for WIN32
//
// transfer the create params
//
b = GETBYTE(pdlg16);
//
// If the template has create params, we're going to get tricky.
// When USER sends the WM_CREATE message to a control with
// createparams, lParam points to the CREATESTRUCT, which
// contains lpCreateParams. lpCreateParams needs to point
// to the createparams in the DLGTEMPLATE. In order to
// accomplish this, we store a 16:16 pointer to the 16-bit
// DLGTEMPLATE's createparams in the 32-bit DLGTEMPLATE's
// createparams. In other words, whenever the count of
// bytes of createparams is nonzero (b != 0), we put 4
// bytes of createparams in the 32-bit DLGTEMPLATE that
// happen to be a 16:16 pointer to the createparams in
// the 16-bit DLGTEMPLATE.
//
// The other half of this magic is accomplished in USERSRV's
// xxxServerCreateDialog, which special-cases the creation
// of controls in a WOW dialog box. USERSRV will pass the
// DWORD pointed to by lpCreateParams instead of lpCreateParams
// to CreateWindow. This DWORD is the 16:16 pointer to the
// 16-bit DLGTEMPLATE's createparams.
//
// DaveHart 14-Mar-93
//
if (b != 0) {
// store 32-bit createparams size (room for 16:16 ptr)
PUTWORD(pdlg32, sizeof(pdlg16));
//ALIGNDWORD(pdlg32);
// store 16:16 pointer in 32-bit createparams
PUTUDWORD(pdlg32, (DWORD)vpdlg16 + (DWORD)(pdlg16 - pdlg16Save));
// point pdlg16 past createparams
ADVGET(pdlg16, b);
} else {
// there are no createparams, store size of zero.
PUTWORD(pdlg32, 0);
//ALIGNDWORD(pdlg32);
}
}
FREEVDMPTR(pdlg16Save);
RETURN(pdlg32 - pdlg32T);
}