/* * CLIPFILE.C - Windows Clipboard File I/O Routines * * Copyright 1985-92, Microsoft Corporation */ /* NOTE: * When saving the contents of the clipboard we SetClipboardData(fmt, NULL) * to free up the memory associated with each clipboard format. Then * after we are done saving we take over as the clipboard owner. This * causes OWNERDRAW formats to be lost in the save process. */ /* * * Touched by : Anas Jarrah * On Date : May 11/1992. * Revision remarks by Anas Jarrah ext #15201 * This file has been changed to comply with the Unicode standard * Following is a quick overview of what I have done. * * Was Changed it into Remark * === =============== ====== * CHAR TCHAR if it refers to a text elements * LPCHAR & LPSTR LPTSTR if it refers to text. * LPCHAR & LPSTR LPBYTE if it does not refer to text * "..." TEXT("...") compile time macro resolves it. * '...' TEXT('...') same * strlen CharStrLen compile time macro resolves it. * strcpy CharStrCpy compile time macro resolves it. * strcmp CharStrCmp compile time macro resolves it. * strcat CharStrCat compile time macro resolves it. * LoadResource LoadResource(A/W) NT compiles resource strings into * Unicode binaries * MOpenFile() MapOpenFile/MOpenFile Depending on whether Unicode is defined or not. * This is a temporary cluge, That has to be taken care of. * * */ #include "clipbrd.h" #include "dib.h" #define ATTRDIRLIST 0xC010 // Windows 3.1 programs were packed on byte boundaries. #pragma pack(1) // Windows 3.1 BITMAP struct - used to save Win 3.1 .CLP files typedef struct { WORD bmType; WORD bmWidth; WORD bmHeight; WORD bmWidthBytes; BYTE bmPlanes; BYTE bmBitsPixel; LPVOID bmBits; } WIN31BITMAP; #pragma pack() /* EXTERN data */ extern BOOL fAnythingToRender; /* FORWARD procs */ HBITMAP PASCAL BitmapToBitmap(HBITMAP, WORD, WORD); TCHAR szFileSpecifier[] = TEXT("*.CLP"); TCHAR szFileName[MAX_PATH]; BOOL fNTReadFileFormat; #ifdef JAPAN extern TCHAR szCaptionName[]; #endif /* ofSaveStruct is required; Otherwise, the following bug will occur * When the contents of the clipboard are loaded from a file, the * ofStruct is used to open the file and the data handles assigned to * the clipboard are NULL because of DELAYED RENDERING; Delayed * rendering will be done by reading from the file (ofStruct). But, * now, if the contents are to be saved into another file, it should * use the same ofStruct, because data has to be obtained from this * file using delayed rendering; So, a temporary ofSaveStruct is used * to hold the saved file's info; Once the save is successful, the * contents of ofSaveStruct are copied onto ofStruct */ /* the ofStruct and ofSaveStruct are replaced by szFileName and * szSaveFileName strings. */ TCHAR szSaveFileName[MAX_PATH]; BOOL fNTSaveFileFormat; /* * IsWriteable() * * Test if a clipboard format is writeable(i.e. if it makes sense to write it) * OWNERDRAW and others can't be written because we (CLIPBRD) will become the * owner when the files are reopened. */ BOOL NEAR PASCAL IsWriteable(UINT Format) { /* Are the PRIVATEFIRST and PRIVATELAST things right? */ if ((Format >= CF_PRIVATEFIRST && Format <= CF_PRIVATELAST) || Format == CF_OWNERDISPLAY) return(FALSE); if (!fNTSaveFileFormat && (Format == CF_UNICODETEXT || Format == CF_ENHMETAFILE || Format == CF_DSPENHMETAFILE)) return(FALSE); return(TRUE); } /* * ReadClipboardFromFile() * * Read in a clipboard file and register all the formats in delayed mode. * to render things for real reopen the file specified by szFileName (was ofStruct). * * NOTE: * This makes us the clipboard owner. * * Bug 14564: Changed return value to a short integer noting why the * reading failed. * Return Value: 0 Success * 1 Improper format * 2 OpenClipboard failed */ #define READFILE_SUCCESS 0 #define READFILE_IMPROPERFORMAT 1 #define READFILE_OPENCLIPBRDFAIL 2 short NEAR PASCAL ReadClipboardFromFile(HWND hwnd,INT fh) { register WORD i; FILEHEADER FileHeader; FORMATHEADER FormatHeader; /* Read the File Header */ _lread(fh, (LPBYTE)&FileHeader, sizeof(FILEHEADER)); /* Sanity check, make sure this is one of ours. */ #ifndef JAPAN if (FileHeader.magic == CLP_NT_ID) fNTReadFileFormat = TRUE; else if (FileHeader.magic == CLP_ID) fNTReadFileFormat = FALSE; else return(READFILE_IMPROPERFORMAT); if (FileHeader.FormatCount > 100) return(READFILE_IMPROPERFORMAT); #else if (FileHeader.magic == CLP_NT_ID) fNTReadFileFormat = TRUE; else if (FileHeader.magic == CLP_ID) fNTReadFileFormat = FALSE; else goto improperformat; if (FileHeader.FormatCount > 100) { improperformat: TCHAR szOutMessage[BUFFERLEN]; TCHAR szCapBuffer[SMALLBUFFERLEN]; LoadStringW(hInst, IDS_NAME, szCapBuffer, SMALLBUFFERLEN); LoadStringW(hInst, IDS_ENOTVALIDFILE, szOutMessage, BUFFERLEN); MessageBox(hwnd, szOutMessage,szCapBuffer, MB_OK | MB_ICONEXCLAMATION); return(READFILE_IMPROPERFORMAT); } #endif /* We become the clipboard owner here! */ if (!OpenClipboard(hwnd)) return(READFILE_OPENCLIPBRDFAIL); EmptyClipboard(); for (i=0; i < FileHeader.FormatCount; i++) { if (fNTReadFileFormat) _lread(fh, (LPBYTE)&(FormatHeader.FormatID), sizeof(FormatHeader.FormatID)); else { FormatHeader.FormatID = 0; /* initialize the high WORD */ _lread(fh, (LPBYTE)&(FormatHeader.FormatID), sizeof(WORD)); } _lread(fh, (LPBYTE)&(FormatHeader.DataLen), sizeof(FormatHeader.DataLen)); _lread(fh, (LPBYTE)&(FormatHeader.DataOffset), sizeof(FormatHeader.DataOffset)); _lread(fh, (LPBYTE)&(FormatHeader.Name), sizeof(FormatHeader.Name)); if (PRIVATE_FORMAT(FormatHeader.FormatID)) FormatHeader.FormatID = (UINT)RegisterClipboardFormat(FormatHeader.Name); /* Delayed Render. */ SetClipboardData(FormatHeader.FormatID, NULL); } /* Now, clipbrd viewer has something to render */ if (FileHeader.FormatCount > 0) fAnythingToRender = TRUE; CloseClipboard(); return(READFILE_SUCCESS); } /* * OpenClipboardFile() */ void NEAR PASCAL OpenClipboardFile(HWND hwnd) { INT fh; lstrcpy(szFileName, TEXT("")); OFN.lpstrTitle = szOpenCaption; OFN.lpstrFile = szFileName; /* Added OFN_FILEMUSTEXIST. 4 March 1991 clarkc */ /* Added OFN_HIDEREADONLY. Happy now, Patrick? :) 1 Oct 1992 a-mgates.*/ OFN.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; /* All long pointers should be defined immediately before the call. * L.Raman - 2/12/91 */ OFN.lpstrDefExt = (LPTSTR)szDefExt; OFN.lpstrFilter = (LPTSTR)szFilterSpec; OFN.lpstrCustomFilter = (LPTSTR)szCustFilterSpec; fh = GetOpenFileName ((LPOPENFILENAME) &OFN); if (fh) { fh = (INT)CreateFile((LPCTSTR)szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fh > 0) { short nReadError; if (ClearClipboard(hwnd)) { if (nReadError = ReadClipboardFromFile(hwnd, fh)) { TCHAR szErr[MSGMAX]; LoadString (hInst, IDS_READERR + nReadError, szErr, MSGMAX); MessageBox(hwnd,szErr,szAppName,MB_OK | MB_ICONEXCLAMATION); } } _lclose(fh); } } /* On GetOpenFileName failure CommDlgExtendedError will return a value.*/ if(CommDlgExtendedError()) { MemErrorMessage(); } } /* * WriteFormatBlock() - */ DWORD NEAR PASCAL WriteFormatBlock(INT fh,DWORD offset,DWORD DataOffset, DWORD DataLen,UINT Format,LPSTR szName) { FORMATHEADER FormatHeader; DWORD dwBytesWritten = 0; FormatHeader.FormatID = Format; FormatHeader.DataLen = DataLen; FormatHeader.DataOffset = DataOffset; lstrcpy(FormatHeader.Name, szName); _llseek(fh, offset, 0); if (fNTSaveFileFormat) dwBytesWritten += _lwrite(fh, (LPSTR)&(FormatHeader.FormatID), sizeof(FormatHeader.FormatID)); else dwBytesWritten += _lwrite(fh, (LPSTR)&(FormatHeader.FormatID), sizeof(WORD)); dwBytesWritten += _lwrite(fh, (LPSTR)&(FormatHeader.DataLen), sizeof(FormatHeader.DataLen)); dwBytesWritten += _lwrite(fh, (LPSTR)&(FormatHeader.DataOffset), sizeof(FormatHeader.DataOffset)); dwBytesWritten += _lwrite(fh, (LPSTR)&(FormatHeader.Name), sizeof(FormatHeader.Name)); return(dwBytesWritten); } /* * lread() - Good ol' _lread that will handle >64k */ #define MAXREAD ((LONG) (60L * 1024L)) DWORD APIENTRY lread(INT hFile,void FAR *pBuffer,DWORD dwBytes) { DWORD dwByteCount = dwBytes; #ifdef WIN16 BYTE huge *hpBuffer = pBuffer; while (dwByteCount > MAXREAD) { if (_lread(hFile, hpBuffer, (WORD)MAXREAD) != MAXREAD) return(0); dwByteCount -= MAXREAD; hpBuffer += MAXREAD; } #else BYTE FAR *hpBuffer = pBuffer; #endif if ((DWORD)_lread(hFile, hpBuffer, dwByteCount) != dwByteCount) return(0); return(dwBytes); } /* * lwrite() - Good ol' _lwrite that will handle >64k */ DWORD APIENTRY lwrite(INT hFile,void FAR *pBuffer,DWORD dwBytes) { DWORD dwByteCount=dwBytes; #ifdef WIN16 BYTE huge *hpBuffer = pBuffer; while (dwByteCount > MAXREAD) { if (_lwrite(hFile, (LPSTR)hpBuffer, (WORD)MAXREAD) != MAXREAD) return(0); dwByteCount -= MAXREAD; hpBuffer += MAXREAD; } #else BYTE FAR *hpBuffer = pBuffer; #endif if ((DWORD)_lwrite(hFile, (LPSTR)hpBuffer, dwByteCount) != dwByteCount) return(0); return(dwBytes); } /* * WriteDataBlock() - * * Returns: * # of bytes written to the output file * * NOTE: Write saves the name of a temp file in the clipboard for it's * own internal clipboard format. This file goes aways when Write * (or windows?) shuts down. Thus saving Write clipboards won't work * (should we special case hack this?) * */ DWORD NEAR PASCAL WriteDataBlock(register INT hFile,LONG offset,UINT Format) { WORD wPalEntries; LPBYTE lpData; DWORD dwSize; BITMAP bitmap; HANDLE hMF; HANDLE hBitmap; HANDLE hLogPalette; register HANDLE hData; LPLOGPALETTE lpLogPalette; LPMETAFILEPICT lpMFP; HENHMETAFILE hEMF; WIN31BITMAP bmWin31; if (!(hData = GetClipboardData(Format))) return(0); if(_llseek(hFile, offset, 0) != (int)offset) return(0); /* We have to special case a few common formats but most things * get handled in the default case. */ switch (Format) { case CF_ENHMETAFILE: hEMF = hData; dwSize = (DWORD) GetEnhMetaFileBits(hEMF, 0, NULL); /* Get data size */ if (!(hData = GlobalAlloc(GHND, dwSize))) /* allocate mem for EMF bits */ return(0); if (!(lpData = GlobalLock(hData))) return(0); if (!GetEnhMetaFileBits(hEMF, dwSize, (LPBYTE)lpData)) return(0); dwSize = lwrite(hFile, lpData, dwSize); GlobalUnlock(hData); GlobalFree(hData); break; case CF_METAFILEPICT: if (!(lpMFP = (LPMETAFILEPICT)GlobalLock(hData))) /* get header */ return(0); if (fNTSaveFileFormat) _lwrite(hFile, (LPBYTE)lpMFP, sizeof(METAFILEPICT)); /* write header */ else { /* If we save the metafile in the Windows 3.1 .CLP file format we have to save the METAFILEPICT structure as a 16bit METAFILEPICT structure. This may cause loss of information if the hight half of the METAFILEPICT structure's fields are used. [pierrej 5/27/92] */ _lwrite(hFile, (LPBYTE)&(lpMFP->mm), sizeof(WORD)); _lwrite(hFile, (LPBYTE)&(lpMFP->xExt), sizeof(WORD)); _lwrite(hFile, (LPBYTE)&(lpMFP->yExt), sizeof(WORD)); _lwrite(hFile, (LPBYTE)&(lpMFP->hMF), sizeof(WORD)); } hMF = lpMFP->hMF; GlobalUnlock(hData); /* unlock the header */ /* A-MGates 9/15/92 - Converted this block to use */ /* GetMetaFileBitsEx */ /* Figure out how big a block we need */ dwSize = GetMetaFileBitsEx(hMF, 0, NULL); if (0 == dwSize) { return(0); } hData = GlobalAlloc(GMEM_MOVEABLE, dwSize); if (!(lpData = GlobalLock(hData))) { return(0); } if (dwSize != GetMetaFileBitsEx(hMF, dwSize, lpData)) { GlobalUnlock(hData); GlobalFree(hData); return(0); } dwSize = lwrite(hFile, lpData, dwSize); /* spit them out */ GlobalUnlock(hData); GlobalFree(hData); if(dwSize) if (fNTSaveFileFormat) dwSize += sizeof(METAFILEPICT); /* we wrote this much data */ else dwSize += SIZE_OF_WIN31_METAFILEPICT_STRUCT; break; case CF_BITMAP: // hBitmap = hData; /* Writing DDBs to disk is bad. Therefore, we */ /* write an intelligent CF_DIB block instead. */ /* A-MGATES 9/29/92 */ Format = CF_DIB; hBitmap = DibFromBitmap((HBITMAP)hData, BI_RGB, 4, NULL); lpData = GlobalLock(hBitmap); // dwSize might be too big, but we can live with that. dwSize = GlobalSize(lpData); _lwrite(hFile, lpData, dwSize); GlobalUnlock(hBitmap); GlobalFree(hBitmap); break; #ifdef ICKYOLDCODE if (!fNTSaveFileFormat) hBitmap = BitmapToBitmap(hBitmap, 4, 1); GetObject(hBitmap, sizeof(BITMAP), (LPBYTE) &bitmap); dwSize = (DWORD)bitmap.bmWidthBytes * bitmap.bmHeight * bitmap.bmPlanes; if (!fNTSaveFileFormat) { // Round up to the nearest TWO bytes when saving to Win 3.1, // not the nearest four, which is what GetObject gives you. // Note: The WidthBytes calculation does not include // bmPlanes in the multiplication because it seems to represent // bytes in a given plane. bitmap.bmWidthBytes = ((bitmap.bmWidth * bitmap.bmBitsPixel)+ 15 ) >> 3; // ">> 3" == " / 8", except cheaper. if (bitmap.bmWidthBytes & 1) { bitmap.bmWidthBytes++; } } if (!(hData = GlobalAlloc(GHND, dwSize))) return(0); if (!(lpData = GlobalLock(hData))) { GlobalFree(hData); return(0); } GetBitmapBits(hBitmap, dwSize, lpData); if (fNTSaveFileFormat) _lwrite(hFile, (LPBYTE) & bitmap, sizeof(BITMAP)); else { /* If we save the bitmap in the Windows 3.1 .CLP file format we have to save the BITMAP structure as a 16bit BITMAP structure. This may cause loss of information if the hight half of the BITMAP structure's fields are used. [pierrej 5/27/92] */ bmWin31.bmType = bitmap.bmType; bmWin31.bmWidth = bitmap.bmWidth; bmWin31.bmHeight = bitmap.bmHeight; bmWin31.bmWidthBytes = bitmap.bmWidthBytes; bmWin31.bmPlanes = bitmap.bmPlanes; bmWin31.bmBitsPixel = bitmap.bmBitsPixel; bmWin31.bmBits = bitmap.bmBits; _lwrite(hFile, (LPBYTE) &bmWin31, sizeof(WIN31BITMAP)); } dwSize = lwrite(hFile, lpData, dwSize); GlobalUnlock(hData); GlobalFree(hData); if(dwSize) if (fNTSaveFileFormat) dwSize += sizeof(BITMAP); else dwSize += sizeof(WIN31BITMAP); break; #endif case CF_PALETTE: /* Get the number of palette entries */ GetObject(hData, sizeof(WORD), (LPBYTE)&wPalEntries); /* Allocate enough place to build the LOGPALETTE struct */ dwSize = (DWORD)(sizeof(LOGPALETTE) + (LONG)wPalEntries * sizeof(PALETTEENTRY)); if (!(hLogPalette = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, dwSize))) { dwSize = 0L; goto Palette_Error; } if (!(lpLogPalette = (LPLOGPALETTE)GlobalLock(hLogPalette))) { dwSize = 0L; goto Palette_Error; } lpLogPalette->palVersion = 0x300; /* Windows 3.00 */ lpLogPalette->palNumEntries = wPalEntries; if (GetPaletteEntries(hData, 0, wPalEntries, (LPPALETTEENTRY)(lpLogPalette->palPalEntry)) == 0) { dwSize = 0L; goto Palette_Error; } /* Write the LOGPALETTE structure onto disk */ dwSize = lwrite(hFile, (LPBYTE)lpLogPalette, dwSize); Palette_Error: if (lpLogPalette) GlobalUnlock(hLogPalette); if (hLogPalette) GlobalFree(hLogPalette); break; default: dwSize = GlobalSize(hData); if (0 ==(lpData = GlobalLock(hData)) ) { return 0; } dwSize = _lwrite(hFile, lpData, dwSize); GlobalUnlock(hData); break; } /* Return the number of bytes written. */ return(dwSize); } /* This function will return the number of clipboard formats compatible with the Windows 3.1 clipboard, this excludes CF_UNICODETEXT, CF_ENHMETAFILE and CF_DSPENHMETAFILE */ int Count16BitClipboardFormats(void) { int iCount; iCount = CountClipboardFormats(); if (IsClipboardFormatAvailable(CF_UNICODETEXT)) iCount--; if (IsClipboardFormatAvailable(CF_ENHMETAFILE)) iCount--; if (IsClipboardFormatAvailable(CF_DSPENHMETAFILE)) iCount--; return iCount; } /* * SaveClipboardData() - Writes a clipboard file. * * In: * hwnd handle of wnd that becomes the clipboard owner * szFileName file handle to read from * * NOTE: * When done we call ReadClipboardFromFile(). this makes us the * clipboard owner. */ BOOL NEAR PASCAL SaveClipboardData(HWND hwnd,LPTSTR szLocalFileName) { INT fh; register UINT Format; DWORD HeaderPos; DWORD DataPos; DWORD datasize; BOOL fComplain; BOOL fDIBUsed; HCURSOR hCursor; FILEHEADER FileHeader; TCHAR szComplaint[BUFFERLEN]; TCHAR szName[CCHFMTNAMEMAX]; WORD wHeaderSize; UINT uiSizeHeaderToWrite; /* First open the clipboard */ if (!OpenClipboard(hwndMain)) return(FALSE); /* Open the file */ fh = (INT)CreateFile((LPCTSTR)szLocalFileName, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fh == -1) { GetLastError(); CloseClipboard(); return(FALSE); } /* Fill out the file header structure */ if (fNTSaveFileFormat) { FileHeader.magic = CLP_NT_ID; /* magic number to tag our files */ uiSizeHeaderToWrite = (sizeof(UINT) + 2*sizeof(DWORD) + CCHFMTNAMEMAX*sizeof(TCHAR)); } else { FileHeader.magic = CLP_ID; /* magic number to tag our files */ uiSizeHeaderToWrite = (sizeof(WORD) + 2*sizeof(DWORD) + CCHFMTNAMEMAX*sizeof(TCHAR)); } FileHeader.FormatCount = 0; /* dummy for now */ /* Update HeaderPos and DataPos */ HeaderPos = sizeof(FILEHEADER); /* This is the maximum number of formats that will be written. Potentially * some may fail and some space will be wasted. * In 32bit the number of bytes written to the disk isn't sizeof(FORMATHEADER) * because of DWORD alignment in the FORMATHEADER structure. Instead we write * the format headre structure one field at a time to remain compatible with * the 16bit Windows versions. */ if (fNTSaveFileFormat) DataPos = HeaderPos + (uiSizeHeaderToWrite * CountClipboardFormats()); else DataPos = HeaderPos + (uiSizeHeaderToWrite * Count16BitClipboardFormats()); /* Now loop throught the data, one format at a time, and write out the data. */ fComplain = FALSE; LoadString(hInst, IDS_FMTNOTSAV, szComplaint, BUFFERLEN); hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); /* Enumerate all formats */ Format = 0; fDIBUsed = FALSE; while ((Format = EnumClipboardFormats(Format)) != 0) { if (IsWriteable(Format)) { // DO NOT write CF_BITMAP to disk. Transform to CF_DIB // and write that instead. if (CF_BITMAP == Format || CF_DIB == Format) { if (!fDIBUsed) { fDIBUsed = TRUE; } // If I've already done DIB, go on to the next format. else continue; } GetClipboardName((Format == CF_BITMAP ? CF_DIB : Format), szName, sizeof(szName)); if ((datasize = WriteDataBlock(fh, DataPos, Format)) != 0) { /* Create a Format header and write it to the file */ wHeaderSize = (WORD)WriteFormatBlock(fh, HeaderPos, DataPos, datasize, (Format == CF_BITMAP ? CF_DIB : Format), (LPTSTR)szName); if(wHeaderSize < uiSizeHeaderToWrite) { fComplain = TRUE; break; } HeaderPos += wHeaderSize; /* Update the data pos for the next block */ DataPos += datasize; FileHeader.FormatCount++; /* this format has been written */ } else { fComplain = TRUE; break; } } } ShowCursor(FALSE); SetCursor(hCursor); if (fComplain) { #ifdef JAPAN /* Use Japanese message for caption instead of app name */ MessageBox(hwnd, szComplaint, szCaptionName, MB_OK | MB_ICONEXCLAMATION); #else MessageBox(hwnd, szComplaint, szAppName, MB_OK | MB_ICONEXCLAMATION); #endif CloseClipboard(); _lclose(fh); return(FALSE); } CloseClipboard(); /* we are done looking at this */ _llseek(fh, 0L, 0); /* move back to the start of file */ /* Write the File Header with the correct number of formats written */ _lwrite(fh, (LPBYTE) & FileHeader, sizeof(FILEHEADER)); /* Now we open the clipboard and become the owner. this places * all the things we just saved in the clipboard (and throws out * those things we didn't save) */ _llseek(fh, 0L, 0); /* ofStruct will be used for reopening the file */ lstrcpy(szFileName, szSaveFileName); fNTReadFileFormat = fNTSaveFileFormat; ReadClipboardFromFile(hwndMain, fh); _lclose(fh); return(TRUE); } /* * SaveClipboardToFile() - */ void NEAR PASCAL SaveClipboardToFile(HWND hwnd) { INT hFile; OFN.lpstrTitle = szSaveCaption; OFN.lpstrFile = szSaveFileName; szSaveFileName[0] = 0; OFN.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN; /* All long pointers should be defined immediately before the call. */ OFN.lpstrDefExt = (LPTSTR)szDefExt; OFN.lpstrFilter = (LPTSTR)szFilterSpec; OFN.lpstrCustomFilter = NULL; OFN.lpfnHook = NULL; OFN.nFilterIndex = 1; hFile = GetSaveFileName ((LPOPENFILENAME) &OFN); if (hFile) { // The first filter listed is "NT Clipboard File". The second is // "Windows 3.1 Clipboard file". fNTSaveFileFormat = (1 == OFN.nFilterIndex); hFile = (INT)CreateFile((LPCTSTR)szSaveFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != -1) /* The file already exists and the user wants to * overwrite! Now, we have to check whether this * file is the most recently saved clip file; * If so, it will be used for delayed rendering; So, * before we overwrite this file we must read all data * from it thro RENDERALLFORMATS; * Fix for Bug #5602 --SANKAR-- 10-16-89 */ { CloseHandle((HANDLE)hFile); if (lstrcmp(szSaveFileName, szFileName) == 0) { SendMessage(hwndMain, WM_RENDERALLFORMATS, 0, 0L); } } if (!SaveClipboardData(hwnd, (LPTSTR)szSaveFileName)) { /* If Failure, Delete the incomplete file */ DeleteFile(szSaveFileName); } } } // // Purpose: // Convert an existing bitmap to the given number of planes and // bits/pixel. // // Parameters: // hBitmap - Handle to the existing bitmap. // wPlanes - Number of planes in the destination bitmap. // wBitCount - Number of bits/pel in the destination bitmap. // // Returns: // A handle to the converted bitmap. // //////////////////////////////////////////////////////////////////////////// HBITMAP PASCAL BitmapToBitmap(HBITMAP hBitmap, WORD wPlanes, WORD wBitCount) { BITMAP bm; BITMAPINFOHEADER BmpInfoHeader; HANDLE hDib, hBmp; LPBYTE lpDib, lpBits; DWORD dwLength, dwSize; int iColorTable; int iColorUsed; HDC hDC; /* ** Get the size of the bitmap. These values are used to setup the memory ** requirements for the DIB. */ GetObject(hBitmap,sizeof(BITMAP),(LPSTR)&bm); if ((bm.bmBitsPixel == wBitCount) && (bm.bmPlanes == wPlanes)) return hBitmap; #if 0 dwSize = dwLength = (DWORD)(bm.bmWidthBytes+sizeof(WORD)) * bm.bmHeight * bm.bmPlanes; #else dwSize = dwLength = (DWORD)(((bm.bmWidth * wBitCount + 7)/8)*2 + 1)/2 * wPlanes * bm.bmHeight; #endif switch(bm.bmBitsPixel * bm.bmPlanes) { case 1: iColorTable = sizeof(RGBQUAD) * 2; break; case 4: iColorTable = sizeof(RGBQUAD) * 16; break; case 8: iColorTable = sizeof(RGBQUAD) * 256; break; case 24: default: iColorTable = 0; break; } iColorUsed = iColorTable / sizeof(RGBQUAD); dwLength += (sizeof(BITMAPINFOHEADER) + iColorTable); /* ** Create the DIB. First, to the size of the bitmap. We will calculate ** the new memory requirements if DIB-Compression is desired. */ if(hDib = GlobalAlloc(GHND,dwLength)) { if(lpDib = GlobalLock(hDib)) { ((LPBITMAPINFOHEADER)lpDib)->biSize = sizeof(BITMAPINFOHEADER); ((LPBITMAPINFOHEADER)lpDib)->biWidth = bm.bmWidth; ((LPBITMAPINFOHEADER)lpDib)->biHeight = bm.bmHeight; ((LPBITMAPINFOHEADER)lpDib)->biPlanes = 1; ((LPBITMAPINFOHEADER)lpDib)->biBitCount = bm.bmBitsPixel*bm.bmPlanes; ((LPBITMAPINFOHEADER)lpDib)->biCompression = BI_RGB; ((LPBITMAPINFOHEADER)lpDib)->biSizeImage = 0; ((LPBITMAPINFOHEADER)lpDib)->biXPelsPerMeter = 0; ((LPBITMAPINFOHEADER)lpDib)->biYPelsPerMeter = 0; ((LPBITMAPINFOHEADER)lpDib)->biClrUsed = 0; ((LPBITMAPINFOHEADER)lpDib)->biClrImportant = 0; // Figure out where the bits go lpBits = (LPBYTE)lpDib+sizeof(BITMAPINFOHEADER)+iColorTable; hDC = GetDC(hwndMain); if (NULL != hDC) { if (bm.bmHeight == GetDIBits(hDC,hBitmap,0, bm.bmHeight,lpBits,(LPBITMAPINFO)lpDib, // DIB_PAL_INDICES)) DIB_RGB_COLORS)) { BmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); BmpInfoHeader.biWidth = bm.bmWidth; BmpInfoHeader.biHeight = bm.bmHeight; BmpInfoHeader.biPlanes = wPlanes; BmpInfoHeader.biBitCount = wBitCount; BmpInfoHeader.biCompression = BI_RGB; BmpInfoHeader.biSizeImage = dwSize; BmpInfoHeader.biXPelsPerMeter = 0; BmpInfoHeader.biYPelsPerMeter = 0; BmpInfoHeader.biClrUsed = iColorUsed; BmpInfoHeader.biClrImportant = iColorUsed; hBmp = CreateDIBitmap(NULL, &BmpInfoHeader, CBM_INIT, lpBits, (LPBITMAPINFO)lpDib, DIB_RGB_COLORS); } ReleaseDC(hwndMain, hDC); } GlobalUnlock(hDib); } GlobalFree(hDib); } return(hBmp); }