/*++ * * WOW v1.0 * * Copyright (c) 1991, Microsoft Corporation * * WDIB.C * DIB.DRV support * * History: * 28-Apr-1994 Sudeep Bharati * Created. * --*/ #include "precomp.h" #pragma hdrstop #include "wowgdip.h" #include "wdib.h" #include "memapi.h" MODNAME(wdib.c); #define CJSCAN(width,planes,bits) ((((width)*(planes)*(bits)+31) & ~31) / 8) #define ABS(X) (((X) < 0 ) ? -(X) : (X)) BOOL W32CheckDibColorIndices(LPBITMAPINFOHEADER lpbmi); // VGA colors RGBQUAD rgbVGA[] = { // Blue Green Red 0x00, 0x00, 0x00, 0, // 0 ; black 0x00, 0x00, 0x80, 0, // 1 ; dark red 0x00, 0x80, 0x00, 0, // 2 ; dark green 0x00, 0x80, 0x80, 0, // 3 ; mustard 0x80, 0x00, 0x00, 0, // 4 ; dark blue 0x80, 0x00, 0x80, 0, // 5 ; purple 0x80, 0x80, 0x00, 0, // 6 ; dark turquoise 0xc0, 0xc0, 0xc0, 0, // 7 ; gray 0x80, 0x80, 0x80, 0, // 8 ; dark gray 0x00, 0x00, 0xff, 0, // 9 ; red 0x00, 0xff, 0x00, 0, // a ; green 0x00, 0xff, 0xff, 0, // b ; yellow 0xff, 0x00, 0x00, 0, // c ; blue 0xff, 0x00, 0xff, 0, // d ; magenta 0xff, 0xff, 0x00, 0, // e ; cyan 0xff, 0xff, 0xff, 0 // f ; white }; RGBQUAD rgb4[] = { 0xc0, 0xdc, 0xc0, 0, // 8 0xf0, 0xca, 0xa6, 0, // 9 0xf0, 0xfb, 0xff, 0, // 246 0xa4, 0xa0, 0xa0, 0 // 247 }; PDIBINFO pDibInfoHead = NULL; PDIBSECTIONINFO pDibSectionInfoHead = NULL; HDC W32HandleDibDrv (PVPVOID vpbmi16) { HDC hdcMem = NULL; HBITMAP hbm = NULL; PVOID pvBits, pvIntelBits; STACKBMI32 bmi32; LPBITMAPINFO lpbmi32; DWORD dwClrUsed,nSize,nAlignmentSpace; PBITMAPINFOHEADER16 pbmi16; INT nbmiSize,nBytesWritten; HANDLE hfile=NULL,hsec=NULL; ULONG RetVal,OriginalSelLimit,SelectorLimit,OriginalFlags; PARM16 Parm16; CHAR pchTempFile[MAX_PATH]; BOOL bRet = FALSE; PVPVOID vpBase16 = (PVPVOID) ((ULONG) vpbmi16 & 0xffff0000); if ((hdcMem = W32FindAndLockDibInfo((USHORT)HIWORD(vpbmi16))) != (HDC)NULL) { return hdcMem; } // First create a memory device context compatible to // the app's current screen if ((hdcMem = CreateCompatibleDC (NULL)) == NULL) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateCompatibleDC failed\n")); return NULL; } // Copy bmi16 to bmi32. DIB.DRV only supports DIB_RGB_COLORS lpbmi32 = CopyBMI16ToBMI32( vpbmi16, (LPBITMAPINFO)&bmi32, (WORD) DIB_RGB_COLORS); // this hack for Director 4.0 does essentially what WFW does // if this bitmap is 0 sized, just return an hDC for something simple if(bmi32.bmiHeader.biSizeImage == 0 && (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_DIBDRVIMAGESIZEZERO)) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv:Zero biSizeImage, returning memory DC!\n")); return hdcMem; } try { // Copy the wholething into a temp file. First get a temp file name if ((nSize = GetTempPath (MAX_PATH, pchTempFile)) == 0 || nSize >= MAX_PATH) goto hdd_err; if (GetTempFileName (pchTempFile, "DIB", 0, pchTempFile) == 0) goto hdd_err; if ((hfile = CreateFile (pchTempFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE), NULL)) == INVALID_HANDLE_VALUE) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateFile failed\n")); goto hdd_err; } // call back to get the size of the global object // associated with vpbmi16 Parm16.WndProc.wParam = HIWORD(vpbmi16); CallBack16(RET_GETDIBSIZE, &Parm16, 0, (PVPVOID)&SelectorLimit); Parm16.WndProc.wParam = HIWORD(vpbmi16); if (SelectorLimit == 0xffffffff || SelectorLimit == 0) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv Invalid Selector %x\n",HIWORD(vpbmi16))); goto hdd_err; } SelectorLimit++; OriginalSelLimit = SelectorLimit; CallBack16(RET_GETDIBFLAGS, &Parm16, 0, (PVPVOID)&OriginalFlags); if (OriginalFlags == 0x4) { //GA_DGROUP LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv GA_DGROUP Not Handled\n")); goto hdd_err; } GETVDMPTR(vpBase16, SelectorLimit, pbmi16); nbmiSize = GetBMI16Size(vpbmi16, (WORD) DIB_RGB_COLORS, &dwClrUsed); // Under NT CreateDIBSection will fail if the offset to the bits // is not dword aligned. So we may have to add some space at the top // of the section to get the offset correctly aligned. nAlignmentSpace = (nbmiSize+LOWORD(vpbmi16)) % 4; if (nAlignmentSpace) { if (WriteFile (hfile, pbmi16, nAlignmentSpace, &nBytesWritten, NULL) == FALSE || nBytesWritten != (INT) nAlignmentSpace) goto hdd_err; } // // detect a clinical case of bitedit screwing around dib.drv // // code below is using dib macros declared in wdib.h // namely: // DibNumColors - yields max number of colors in dib // DibColors - yields pointer to a dib color table // // Function W32CheckDibColorIndices checks to see if DIB color // table looks like a number (defined usually by biClrImportant) // of WORD indices in a sequential order (0, 1, 2, ...) // if this is the case, app is trying to use undocumented feature // of DIB.DRV that turns color matching off in this case. // Since we cannot enforce that rule, we approximate it by filling // color table by a number of known (and always same) entries // When blitting occurs, no color matching will be performed (when // both target and destination are of this very nature). // For no reason at all we fill color table with vga colors. // Sequential indices could have worked just as well. // // Modifications are made to memory pointed to by lpbmi32 if (W32CheckDibColorIndices((LPBITMAPINFOHEADER)lpbmi32)) { BYTE i; INT nColors; LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpbmi32; LPRGBQUAD lprgbq = (LPRGBQUAD)DibColors(lpbmi); nColors = DibNumColors(lpbmi); lpbmi->biClrImportant = nColors; switch (lpbmi->biBitCount) { case 1: lprgbq[0] = rgbVGA[0]; lprgbq[1] = rgbVGA[0x0f]; break; case 4: RtlCopyMemory(lprgbq, rgbVGA, sizeof(rgbVGA)); break; case 8: RtlCopyMemory(lprgbq, rgbVGA, 8*sizeof(RGBQUAD)); RtlCopyMemory(lprgbq+248, rgbVGA+8, 8*sizeof(RGBQUAD)); RtlCopyMemory(lprgbq+8, rgb4, 2*sizeof(RGBQUAD)); RtlCopyMemory(lprgbq+246, rgb4+2, 2*sizeof(RGBQUAD)); for (i = 10; i < 246; ++i) { lprgbq[i].rgbBlue = i; lprgbq[i].rgbGreen= 0; lprgbq[i].rgbRed = 0; lprgbq[i].rgbReserved = 0; } break; default: // this should never happen break; } } if (WriteFile (hfile, pbmi16, SelectorLimit, &nBytesWritten, NULL) == FALSE || nBytesWritten != (INT) SelectorLimit) goto hdd_err; if (SelectorLimit < 64*1024) { if (SetFilePointer (hfile, 64*1024+nAlignmentSpace, NULL, FILE_BEGIN) == -1) goto hdd_err; if (SetEndOfFile (hfile) == FALSE) goto hdd_err; SelectorLimit = 64*1024; } if ((hsec = CreateFileMapping (hfile, NULL, PAGE_READWRITE | SEC_COMMIT, 0, SelectorLimit+nAlignmentSpace, NULL)) == NULL) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateFileMapping Failed\n")); goto hdd_err; } // Now create the DIB section if ((hbm = CreateDIBSection (hdcMem, lpbmi32, DIB_RGB_COLORS, &pvBits, hsec, nAlignmentSpace + LOWORD(vpbmi16) + nbmiSize )) == NULL) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateDibSection Failed\n")); goto hdd_err; } FREEVDMPTR(pbmi16); if((pvBits = MapViewOfFile(hsec, FILE_MAP_WRITE, 0, 0, SelectorLimit+nAlignmentSpace)) == NULL) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv MapViewOfFile Failed\n")); goto hdd_err; } pvBits = (PVOID) ((ULONG)pvBits + nAlignmentSpace); SelectObject (hdcMem, hbm); GdiSetBatchLimit(1); #ifndef i386 if (!NT_SUCCESS(VdmAddVirtualMemory((ULONG)pvBits, (ULONG)SelectorLimit, (PULONG)&pvIntelBits))) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv VdmAddVirtualMemory failed\n")); goto hdd_err; } // On risc platforms, the intel base + the intel linear address // of the DIB section is not equal to the DIB section's process // address. This is because of the VdmAddVirtualMemory call // above. So here we zap the correct address into the flataddress // array. if (!VdmAddDescriptorMapping(HIWORD(vpbmi16), (USHORT) ((SelectorLimit+65535)/65536), (ULONG) pvIntelBits, (ULONG) pvBits)) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv VdmAddDescriptorMapping failed\n")); goto hdd_err; } #else pvIntelBits = pvBits; #endif // Finally set the selectors to the new DIB Parm16.WndProc.wParam = HIWORD(vpbmi16); Parm16.WndProc.lParam = (LONG)pvIntelBits; Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT Parm16.WndProc.hwnd = 1; // set so it's not randomly 0 CallBack16(RET_SETDIBSEL, &Parm16, 0, (PVPVOID)&RetVal); if (!RetVal) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv Callback set_sel_for_dib failed\n")); goto hdd_err; } // Store all the relevant information so that DeleteDC could // free all the resources later. if (W32AddDibInfo(hdcMem, hfile, hsec, nAlignmentSpace, pvBits, pvIntelBits, hbm, OriginalSelLimit, (USHORT)OriginalFlags, (USHORT)((HIWORD(vpbmi16)))) == FALSE) goto hdd_err; // Finally spit out the dump for debugging LOGDEBUG(6,("\t\tWOW::W32HandleDibDrv hdc=%04x nAlignment=%04x\n\t\tNewDib=%x OldDib=%04x:%04x DibSize=%x DibFlags=%x\n",hdcMem,nAlignmentSpace,pvBits,HIWORD(vpbmi16),LOWORD(vpbmi16),OriginalSelLimit,(USHORT)OriginalFlags)); bRet = TRUE; hdd_err:; } finally { if (!bRet) { if (hdcMem) { DeleteDC (hdcMem); hdcMem = NULL; } if (hfile) CloseHandle (hfile); if (hsec) CloseHandle (hsec); if (hbm) CloseHandle (hbm); } } return hdcMem; } BOOL W32AddDibInfo ( HDC hdcMem, HANDLE hfile, HANDLE hsec, ULONG nalignment, PVOID newdib, PVOID newIntelDib, HBITMAP hbm, ULONG dibsize, USHORT originaldibflags, USHORT originaldibsel ) { PDIBINFO pdi; if ((pdi = malloc_w (sizeof (DIBINFO))) == NULL) return FALSE; pdi->di_hdc = hdcMem; pdi->di_hfile = hfile; pdi->di_hsec = hsec; pdi->di_nalignment = nalignment; pdi->di_newdib = newdib; pdi->di_newIntelDib = newIntelDib; pdi->di_hbm = hbm; pdi->di_dibsize = dibsize; pdi->di_originaldibsel = originaldibsel; pdi->di_originaldibflags = originaldibflags; pdi->di_next = pDibInfoHead; pdi->di_lockcount = 1; pDibInfoHead = pdi; return TRUE; } BOOL W32FreeDibInfoHandle(PDIBINFO pdi, PDIBINFO pdiLast) { if (W32RestoreOldDib (pdi) == 0) { LOGDEBUG(LOG_ALWAYS,("\nWOW::W32RestoreDib failed\n")); return FALSE; } #ifndef i386 VdmRemoveVirtualMemory((ULONG)pdi->di_newIntelDib); #endif UnmapViewOfFile ((LPVOID)((ULONG)pdi->di_newdib - pdi->di_nalignment)); DeleteObject (pdi->di_hbm); CloseHandle (pdi->di_hsec); CloseHandle (pdi->di_hfile); DeleteDC(pdi->di_hdc); W32FreeDibInfo (pdi, pdiLast); return TRUE; } BOOL W32CheckAndFreeDibInfo (HDC hdc) { PDIBINFO pdi = pDibInfoHead,pdiLast=NULL; while (pdi) { if (pdi->di_hdc == hdc){ if (--pdi->di_lockcount) { // // This must be a releasedc within a nested call to createdc. // Just return, as this should be released again later. // LOGDEBUG(LOG_ALWAYS, ("\nW32CheckAndFreeDibInfo: lockcount!=0\n")); return TRUE; } return W32FreeDibInfoHandle(pdi, pdiLast); } pdiLast = pdi; pdi = pdi->di_next; } return FALSE; } VOID W32FreeDibInfo (PDIBINFO pdiCur, PDIBINFO pdiLast) { if (pdiLast == NULL) pDibInfoHead = pdiCur->di_next; else pdiLast->di_next = pdiCur->di_next; free_w (pdiCur); } ULONG W32RestoreOldDib (PDIBINFO pdi) { PARM16 Parm16; ULONG retval; // callback to allocate memory and copy the dib from dib section Parm16.WndProc.wParam = pdi->di_originaldibsel; Parm16.WndProc.lParam = (LONG) (pdi->di_newdib); Parm16.WndProc.wMsg = pdi->di_originaldibflags; CallBack16(RET_FREEDIBSEL, &Parm16, 0, (PVPVOID)&retval); return retval; } HDC W32FindAndLockDibInfo (USHORT sel) { PDIBINFO pdi = pDibInfoHead; while (pdi) { if (pdi->di_originaldibsel == sel){ pdi->di_lockcount++; return (pdi->di_hdc); } pdi = pdi->di_next; } return (HDC) NULL; } // // This function is called from krnl386 if GlobalReAlloc or GlobalFree is // trying to operate on memory which we suspect is dib-mapped. It finds // dib by original selector and restores it, thus allowing respective function // to succeede. Bitedit is the app that does globalrealloc before DeleteDC // // ULONG FASTCALL WK32FindAndReleaseDib(PVDMFRAME pvf) { USHORT sel; PFINDANDRELEASEDIB16 parg; PDIBINFO pdi; PDIBINFO pdiLast = NULL; // get the argument pointer, see wowkrnl.h GETARGPTR(pvf, sizeof(*parg), parg); // get selector from the handle sel = parg->hdib | (USHORT)0x01; // "convert to sel" // find this said sel in the dibinfo pdi = pDibInfoHead; while (pdi) { if (pdi->di_originaldibsel == sel) { // found ! this is what we are releasing or reallocating LOGDEBUG(LOG_ALWAYS, ("\nWOW: In FindAndReleaseDIB function %d\n", (DWORD)parg->wFunId)); // see if we need to nuke... if (--pdi->di_lockcount) { // the problem with lock count... LOGDEBUG(LOG_ALWAYS, ("\nWOW: FindAndReleaseDib failed (lock count!)\n")); return FALSE; } return W32FreeDibInfoHandle(pdi, pdiLast); } pdiLast = pdi; pdi = pdi->di_next; } return FALSE; } BOOL W32CheckDibColorIndices(LPBITMAPINFOHEADER lpbmi) { WORD i, nColors; LPWORD lpw = (LPWORD)DibColors(lpbmi); nColors = DibNumColors(lpbmi); if (lpbmi->biClrImportant) { nColors = min(nColors, (WORD)lpbmi->biClrImportant); } for (i = 0; i < nColors; ++i) { if (*lpw++ != i) { return FALSE; } } LOGDEBUG(LOG_ALWAYS, ("\nUndocumented Dib.Drv behaviour used\n")); return TRUE; } /******************************Public*Routine******************************\ * DIBSection specific calls * * History: * 04-May-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ ULONG cjBitmapBitsSize(CONST BITMAPINFO *pbmi) { // Check for PM-style DIB if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) { LPBITMAPCOREINFO pbmci; pbmci = (LPBITMAPCOREINFO)pbmi; return(CJSCAN(pbmci->bmciHeader.bcWidth,pbmci->bmciHeader.bcPlanes, pbmci->bmciHeader.bcBitCount) * pbmci->bmciHeader.bcHeight); } // not a core header if ((pbmi->bmiHeader.biCompression == BI_RGB) || (pbmi->bmiHeader.biCompression == BI_BITFIELDS)) { return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes, pbmi->bmiHeader.biBitCount) * ABS(pbmi->bmiHeader.biHeight)); } else { return(pbmi->bmiHeader.biSizeImage); } } ULONG FASTCALL WG32CreateDIBSection(PVDMFRAME pFrame) { ULONG ul = 0; STACKBMI32 bmi32; LPBITMAPINFO lpbmi32; HBITMAP hbm32; PVOID pv16, pvBits, pvIntelBits; PVPVOID vpbmi16; PVOID pvBits32; DWORD dwArg16; register PCREATEDIBSECTION16 parg16; GETARGPTR(pFrame, sizeof(CREATEDIBSECTION16), parg16); // this is performance hack so we don't generate extra code dwArg16 = FETCHDWORD(parg16->f4); // do it once here pv16 = (PVOID)GetPModeVDMPointer(dwArg16, sizeof(DWORD)); // aligned here! WOW32ASSERTMSG(((parg16->f5 == 0) && (parg16->f6 == 0)), ("WOW:WG32CreateDIBSection, hSection/dwOffset non-null\n")); vpbmi16 = (PVPVOID)FETCHDWORD(parg16->f2); lpbmi32 = CopyBMI16ToBMI32(vpbmi16, (LPBITMAPINFO)&bmi32, FETCHWORD(parg16->f3)); hbm32 = CreateDIBSection(HDC32(parg16->f1), lpbmi32, WORD32(parg16->f3), &pvBits, NULL, 0); if (hbm32 != 0) { PARM16 Parm16; PDIBSECTIONINFO pdi; ULONG SelectorLimit; SelectorLimit = (ULONG)cjBitmapBitsSize(lpbmi32); #ifndef i386 if (!NT_SUCCESS(VdmAddVirtualMemory((ULONG)pvBits, SelectorLimit, (PULONG)&pvIntelBits))) { LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection VdmAddVirtualMemory failed\n")); goto cds_err; } #else pvIntelBits = pvBits; #endif // Create a selector array for the bits backed by pvIntelBits Parm16.WndProc.wParam = (WORD)-1; // -1 => allocate selectors Parm16.WndProc.lParam = (LONG) pvIntelBits; // backing pointer Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT Parm16.WndProc.hwnd = (WORD)((SelectorLimit+65535)/65536);// selector count CallBack16(RET_SETDIBSEL, &Parm16, 0, (PVPVOID)&pvBits32); // 16:16 pointer is still valid as call above makes no difference if (pv16 != NULL) { *(UNALIGNED PVOID*)pv16 = pvBits32; } if (pvBits32 == NULL) { LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection, Callback set_sel_for_dib failed\n")); goto cds_err; } #ifndef i386 // okay, that was successful - map the descriptors properly if (!VdmAddDescriptorMapping(HIWORD(pvBits32), (USHORT) ((SelectorLimit+65535)/65536), (ULONG) pvIntelBits, (ULONG) pvBits)) { LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection VdmAddDescriptorMapping failed\n")); goto cds_err; } #endif LOGDEBUG(LOG_ALWAYS, ("\nWOW:CreateDIBSection: [16:16 %x] [Intel %x] [Flat %x]\n", pvBits32, pvIntelBits, pvBits)); ul = GETHBITMAP16(hbm32); // Add it to the list used for cleanup at DeleteObject time. if ((pdi = malloc_w (sizeof (DIBSECTIONINFO))) != NULL) { pdi->di_hbm = hbm32; pdi->di_pv16 = pvBits32; #ifndef i386 pdi->di_newIntelDib = pvIntelBits; #endif pdi->di_next = pDibSectionInfoHead; pDibSectionInfoHead = pdi; // need to turn batching off since a DIBSECTION means the app can // also draw on the bitmap and we need synchronization. GdiSetBatchLimit(1); goto cds_ok; } else { // Failure, free the selector array Parm16.WndProc.wParam = (WORD)-1; // -1 => allocate/free Parm16.WndProc.lParam = (LONG) pvBits32; // pointer Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT Parm16.WndProc.hwnd = 0; // 0 => free CallBack16(RET_SETDIBSEL, &Parm16, 0, (PVPVOID)&ul); #ifndef i386 VdmRemoveVirtualMemory((ULONG)pvIntelBits); #endif } } else { LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection, CreateDibSection Failed\n")); } cds_err: if (hbm32 != 0) { DeleteObject(hbm32); } LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection returning failure\n")); ul = 0; cds_ok: WOW32APIWARN(ul, "CreateDIBSection"); FREEMISCPTR(pv16); FREEARGPTR(parg16); return(ul); } ULONG FASTCALL WG32GetDIBColorTable(PVDMFRAME pFrame) { ULONG ul = 0; RGBQUAD * prgb; register PGETDIBCOLORTABLE16 parg16; GETARGPTR(pFrame, sizeof(GETDIBCOLORTABLE16), parg16); GETMISCPTR(parg16->f4,prgb); ul = (ULONG)GetDIBColorTable(HDC32(parg16->f1), parg16->f2, parg16->f3, prgb); WOW32APIWARN(ul, "GetDIBColorTable"); if (ul) FLUSHVDMPTR(parg16->f4,sizeof(RGBQUAD) * ul,prgb); FREEMISCPTR(prgb); FREEARGPTR(parg16); return(ul); } ULONG FASTCALL WG32SetDIBColorTable(PVDMFRAME pFrame) { ULONG ul = 0; RGBQUAD * prgb; register PSETDIBCOLORTABLE16 parg16; GETARGPTR(pFrame, sizeof(SETDIBCOLORTABLE16), parg16); GETMISCPTR(parg16->f4,prgb); ul = (ULONG)SetDIBColorTable(HDC32(parg16->f1), parg16->f2, parg16->f3, prgb); WOW32APIWARN(ul, "SetDIBColorTable"); FREEMISCPTR(prgb); FREEARGPTR(parg16); return(ul); } // DIBSection routines BOOL W32CheckAndFreeDibSectionInfo (HBITMAP hbm) { PDIBSECTIONINFO pdi = pDibSectionInfoHead,pdiLast=NULL; while (pdi) { if (pdi->di_hbm == hbm){ PARM16 Parm16; ULONG ulRet; // need to free the selector array for the memory Parm16.WndProc.wParam = (WORD)-1; // selector, -1 == allocate/free Parm16.WndProc.lParam = (LONG) pdi->di_pv16; // pointer Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT Parm16.WndProc.hwnd = 0; // selector count, 0 == free CallBack16(RET_SETDIBSEL, &Parm16, 0, (PVPVOID)&ulRet); #ifndef i386 VdmRemoveVirtualMemory((ULONG)pdi->di_newIntelDib); #endif if (pdiLast == NULL) pDibSectionInfoHead = pdi->di_next; else pdiLast->di_next = pdi->di_next; // now delete the object DeleteObject (pdi->di_hbm); free_w(pdi); return TRUE; } pdiLast = pdi; pdi = pdi->di_next; } return FALSE; }