/****************************************************************************\ * * MODULE: anifile.c * * PURPOSE: Processes files for the Animated Cursor Editor * * Copyright 1993-1996 Microsoft Corp. * * * History: * 21-Apr-1993 JonPa Wrote it. * \****************************************************************************/ #include #include #include "anidefs.h" /****************************************************************************\ * * FUNCTION: BOOL CreateFrameFromCursorFile( LPSTR pszFile ) * * PURPOSE: Opens a cursor file, reads the icon info out of it, * and creates a frame and step for that icon, then links * everything together and updates the listbox. * * NOTES: This function accesses the global flag gfEditFrame. * If this bool is TRUE, then the currently selected frame * in the listbox is overwritten. If it is false, then * a new frame is created and inserted after the currently * selected frame (or at the end if no selection). * * History: * 21-Apr-1993 JonPa Created it * \****************************************************************************/ BOOL CreateFrameFromCursorFile(HWND hwnd, LPTSTR pszFile, BOOL fEdit) { PFRAME pf; HANDLE hf; PSTEP psOld, psNew; DWORD ckSize; int iSel; int cSel; cSel = GetSelStepCount(hwnd); if ( (fEdit && (cSel != 1)) || cSel > 1) { FmtMessageBox( hwnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE, fEdit ? MSG_MUSTEQONEFAME : MSG_LESSEQONEFRAME); return FALSE; } /* get currently selected frame */ GetCurrentSel(hwnd, DLG_MAIN_FRAMELIST, &iSel, 1, &cSel ); if (cSel == 0) psOld = NULL; else psOld = GetStep(hwnd, iSel); /* * If not editing, create a new step */ if (!fEdit || !IsValidPS(psOld)) { psNew = NewStep(); if (psNew == NULL) { return FALSE; } } else { psNew = NULL; } hf = CreateFile(pszFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hf == INVALID_HANDLE_VALUE) return FALSE; ckSize = GetFileSize(hf, NULL); /* get the frame out of the file */ pf = ReadIconFromFile(hwnd, hf, ckSize); CloseHandle(hf); if (pf == NULL) { if (psNew != NULL) FreeMem(psNew); return FALSE; } if (psNew != NULL) { if (IsValidPS(psOld)) { psNew->jif = psOld->jif; iSel += 1; } else { psNew->jif = ganiAcon.anih.jifRate; iSel = SendDlgItemMessage(hwnd, DLG_MAIN_FRAMELIST, LB_GETCOUNT, 0, 0); } LinkStepFrame(psNew, pf); SendDlgItemMessage(hwnd, DLG_MAIN_FRAMELIST, LB_INSERTSTRING, iSel, (LPARAM)psNew); SetCurrentSel(hwnd, DLG_MAIN_FRAMELIST, FALSE, iSel); } else { HWND hwndLB = GetDlgItem(hwnd, DLG_MAIN_FRAMELIST); /* * Delete the old frame and point the step to the new one. */ LinkStepFrame(psOld, pf); InvalidateRect(hwndLB, NULL, TRUE); } return TRUE; } /****************************************************************************\ * * FUNCTION: HICON ConvertDataToIcon( PFRAME pf ) * * PURPOSE: * * * * * History: * 23-Apr-1993 JonPa copied from Win NT USERs ReadIconGuts * \****************************************************************************/ HICON ConvertDataToIcon( PFRAME pf, WORD *pxHotSave, WORD *pyHotSave ) { NEWHEADER *pnh; NEWHEADER *pnhBase; RESDIR *prd; int offMatch; ICONFILERESDIR *pird; PCURSORRESOURCE pcres; BOOL fIcon; HICON hicon; WORD x, y; LPBYTE pbBits; pnhBase = (NEWHEADER *)pf->abIcon; /* * Construct a fake array of RESDIR entries using the info at the head * of the file. Store the data offset in the idIcon WORD so it can be * returned by RtlGetIdFromDirectory. */ pnh = (NEWHEADER *)LocalAlloc(LMEM_FIXED, sizeof(NEWHEADER) + (pnhBase->cResources * sizeof(RESDIR))); if (pnh == NULL) return NULL; *pnh = *pnhBase; prd = (RESDIR *)(pnh + 1); pird = (ICONFILERESDIR *)(pnhBase + 1); /* prime pird for first line of loop */ pird--; for (offMatch = 0; offMatch < (int)pnh->cResources; offMatch++, prd++) { /* * Get the next resource directory from the icon file. */ ++pird; /* * Convert from the icon editor's resource directory format * to the post-RC.EXE format LookupIconIdFromDirectory expects. */ if (pnh->rt == 1) { // ICON prd->ResInfo.Icon.Width = pird->bWidth; prd->ResInfo.Icon.Height = pird->bHeight; prd->ResInfo.Icon.ColorCount = pird->bColorCount; prd->ResInfo.Icon.reserved = 0; } else { // CURSOR prd->ResInfo.Cursor.Width = pird->bWidth; prd->ResInfo.Cursor.Height = pird->bHeight; } prd->Planes = 0; // Hopefully nobody uses this prd->BitCount = 0; // " " prd->BytesInRes = pird->dwDIBSize; prd->idIcon = (WORD)pird->dwDIBOffset; } /* * NOTE: nh.rt is NOT an RT_ type value. For instance, nh.rt == 1 for * an icon file where as 1 == RT_CURSOR, not RT_ICON. */ fIcon = (pnhBase->rt == 1); offMatch = LookupIconIdFromDirectory((PBYTE)pnh, fIcon); LocalFree(pnh); if (fIcon) { pcres = (PCURSORRESOURCE)&(pf->abIcon[offMatch]); *pxHotSave = gcxCursor / 2; *pyHotSave = gcyCursor / 2; } else { offMatch -= (sizeof(pcres->xHotspot) + sizeof(pcres->yHotspot)); for(; pird->dwDIBOffset != (WORD)offMatch && pird != (ICONFILERESDIR *)(pnhBase + 1); pird--); pcres = (PCURSORRESOURCE)&(pf->abIcon[offMatch]); x = pcres->xHotspot; y = pcres->yHotspot; *pxHotSave = pcres->xHotspot = pird->xHotspot; *pyHotSave = pcres->yHotspot = pird->yHotspot; } // Buffer must be aligned pbBits = LocalAlloc(LMEM_FIXED, pf->rtag.ckSize - offMatch ); if (pbBits) { CopyMemory( pbBits, pcres, pf->rtag.ckSize - offMatch ); hicon = CreateIconFromResource( pbBits, pf->rtag.ckSize - offMatch, fIcon, 0x00030000); LocalFree( pbBits ); } else hicon = NULL; if(!fIcon) { pcres->xHotspot = x; pcres->yHotspot = y; } return hicon; } /****************************************************************************\ * * FUNCTION: PFRAME ReadIconFromFile(HWND hwnd, HANDLE hf, DWORD ckSize) * * PURPOSE: Reads the icon info out of a file, * and creates a frame for that icon. * * * History: * 22-Apr-1993 JonPa Created it * \****************************************************************************/ PFRAME ReadIconFromFile(HWND hwnd, HANDLE hf, DWORD ckSize) { PFRAME pf = AllocMem( sizeof( FRAME ) + ckSize ); DWORD cbRead; PFRAME pfList; if (pf != NULL) { pf->cRef = 0; if (ReadFile(hf, pf->abIcon, ckSize, &cbRead, NULL) && cbRead == ckSize) { /* got the data, now set up the rest of the frame and link it in */ pf->dwCheckSum = CalcCheckSum( pf->abIcon, ckSize ); pf->rtag.ckID = FOURCC_icon; pf->rtag.ckSize = ckSize; /* Check if this fram is already in the list */ for (pfList = gpfrmFrames; pfList != NULL; pfList = pfList->pfrmNext ) { if (pf->dwCheckSum == pfList->dwCheckSum && pf->rtag.ckSize == pfList->rtag.ckSize && memcmp( pf->abIcon, pfList->abIcon, ckSize ) == 0) { /* * These frames are the same, coalesce them into a * sequence. */ FreeMem(pf); pf = pfList; break; } } if (pfList == NULL) { /* * Did not find a dup, create an icon for this frame */ pf->hcur = ConvertDataToIcon( pf, &(pf->xHotSpot), &(pf->yHotSpot) ); pf->pfrmNext = gpfrmFrames; gpfrmFrames = pf; } } else { /* File Error */ FreeMem(pf); pf = NULL; } } return pf; } /****************************************************************************\ * * FUNCTION: HANDLE PromptAndOpenFile( ) * * PURPOSE: Pust up the standard open dialog and then opens the file * * * * * History: * 21-Apr-1993 JonPa Created it * \****************************************************************************/ HANDLE PromptAndOpenFile( HWND hwnd, DWORD cchFileTitle, LPTSTR pszFileTitle, DWORD cchFileName, LPTSTR pszFileName, LPTSTR pszFilter ) { HANDLE hf = INVALID_HANDLE_VALUE; if (PromptForFile( hwnd, cchFileTitle, pszFileTitle, cchFileName, pszFileName, pszFilter, NULL, FALSE )) { /* Open the file. */ hf = CreateFile(pszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hf == INVALID_HANDLE_VALUE) { FmtMessageBox( hwnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE, MSG_CANTOPENFILE, pszFileName ); } } return hf; } /****************************************************************************\ * * FUNCTION: HANDLE PromptForFile( ) * * PURPOSE: Pust up the standard open dialog * * * * * History: * 28-Apr-1993 JonPa Created it from PromptAndOpenFile * \****************************************************************************/ BOOL PromptForFile( HWND hwnd, DWORD cchFileTitle, LPTSTR pszFileTitle, DWORD cchFileName, LPTSTR pszFile, LPTSTR pszFilter, LPTSTR pszDlgTitle, BOOL fSave ) { OPENFILENAME ofn; ZeroMemory(&ofn, sizeof(ofn)); /* Set the members of the OPENFILENAME structure. */ ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = pszFilter; ofn.nFilterIndex = 0; ofn.lpstrFile = pszFile; ofn.nMaxFile = cchFileName; ofn.lpstrFileTitle = pszFileTitle; ofn.nMaxFileTitle = cchFileTitle; ofn.lpstrTitle = pszDlgTitle; ofn.lpstrDefExt = gpszANI; if (fSave) { ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; } else { ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; } /* Display the SaveAs or Open dialog box. */ return fSave ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn); } /****************************************************************************\ * * FUNCTION: BOOL ReadAniFile( HWND hwnd, HANDLE hf ) { * * PURPOSE: & * Loads an animatied cursor from a RIFF file. The RIFF file format for * animated cursors looks like this: * * RIFF( 'ACON' * LIST( 'INFO' * INAM( ) * IART( ) * ) * anih( ) * [rate( ) ] * ['seq '( )] * LIST( 'fram' icon( ) ) * ) * * * History: * 02-Oct-1991 DarrinM Created. (in Win32 user) * 17-Mar-1993 JonPa Rewrote to use RIFF format instead of RAD * 21-Apr-1993 JonPa Copied it to anifile.c and tweeked it. * \****************************************************************************/ BOOL ReadAniFile( HWND hwnd, HANDLE hf ) { RTAG tag; DWORD cbRead; BOOL fSuccess = FALSE; JIF *pjifRate = NULL; DWORD *pseq = NULL; PFRAME *ppfram = NULL; int iFrame = 0; int i; if (!ReadTag(hf, &tag)) goto laiFileErr; /* * Make sure it's a RIFF ANI file */ if (tag.ckID != FOURCC_RIFF) goto laiFileErr; /* read the chunk type */ if(!ReadFile(hf, &tag.ckID, sizeof(tag.ckID), &cbRead, NULL) || cbRead < sizeof(tag.ckID)) { goto laiFileErr; } if (tag.ckID != FOURCC_ACON) goto laiFileErr; /* look for 'anih', 'rate', 'seq ', and 'icon' chunks */ while( ReadTag(hf, &tag)) { switch( tag.ckID ) { case FOURCC_anih: if (!ReadChunk(hf, &tag, &ganiAcon.anih)) goto laiFileErr; if (!(ganiAcon.anih.fl & AF_ICON) || (ganiAcon.anih.cFrames == 0)) goto laiFileErr; /* * Allocate space for the ANIHEADER, and a seq and * rate table (in case we run into one later). */ pjifRate = AllocMem( ganiAcon.anih.cSteps * sizeof(JIF) + ganiAcon.anih.cSteps * sizeof(DWORD) + ganiAcon.anih.cSteps * sizeof(PFRAME)); if (pjifRate == NULL) goto laiFileErr; pseq = (DWORD *)(pjifRate + ganiAcon.anih.cSteps); ppfram = (PFRAME *)(pseq + ganiAcon.anih.cSteps); for( i = 0; i < (int)ganiAcon.anih.cSteps; i++ ) { pjifRate[i] = ganiAcon.anih.jifRate; pseq[i] = i; ppfram[i] = NULL; } break; case FOURCC_rate: /* * If we find a rate chunk, read it into its preallocated * space. */ if(!ReadChunk(hf, &tag, (PBYTE)pjifRate)) goto laiFileErr; break; case FOURCC_seq: /* * If we find a seq chunk, read it into its preallocated * space. */ if(!ReadChunk(hf, &tag, (PBYTE)pseq)) goto laiFileErr; break; case FOURCC_LIST: { DWORD cbChunk = PADUP(tag.ckSize); /* * See if this list is the 'fram' list of icon chunks */ if(!ReadFile(hf, &tag.ckID, sizeof(tag.ckID), &cbRead, NULL) || cbRead < sizeof(tag.ckID)) { goto laiFileErr; } cbChunk -= cbRead; if (tag.ckID == FOURCC_fram) { while(cbChunk >= sizeof(tag)) { if (!ReadTag(hf, &tag)) goto laiFileErr; cbChunk -= sizeof(tag); if(tag.ckID == FOURCC_icon) { PFRAME pfrm; /* * Ok, load the icon/cursor bits, */ pfrm = ReadIconFromFile(hwnd, hf, tag.ckSize); if (pfrm == NULL) { goto laiFileErr; } for( i = 0; i < (int)ganiAcon.anih.cSteps; i++ ) { if (pseq[i] == (DWORD)iFrame) { ppfram[i] = pfrm; } } iFrame++; } else { /* * Unknown chunk in fram list, just ignore it */ SkipChunk(hf, &tag); } cbChunk -= PADUP(tag.ckSize); } } else if (tag.ckID == FOURCC_INFO) { /* now look for INAM and IART chunks */ while( cbChunk >= sizeof(tag) ) { if (!ReadTag(hf, &tag)) goto laiFileErr; cbChunk -= sizeof(tag); switch( tag.ckID ) { case FOURCC_INAM: if (cbChunk < tag.ckSize || !ReadChunkN(hf, &tag, ganiAcon.azTitle, sizeof(ganiAcon.azTitle))) goto laiFileErr; cbChunk -= PADUP(tag.ckSize); break; case FOURCC_IART: if (cbChunk < tag.ckSize || !ReadChunkN(hf, &tag, ganiAcon.azCreator, sizeof(ganiAcon.azCreator))) goto laiFileErr; cbChunk -= PADUP(tag.ckSize); break; default: if (!SkipChunk( hf, &tag )) goto laiFileErr; cbChunk -= PADUP(tag.ckSize); break; } } } else { /* * Not the fram list or the INFO list. Skip * the rest of this chunk. (Don't forget that we have * already skipped one dword!) */ tag.ckSize = cbChunk; SkipChunk(hf, &tag); break; } break; } default: /* * We're not interested in this chunk, skip it. */ if(!SkipChunk(hf, &tag)) goto laiFileErr; break; } } /* * Update the frame count incase we coalesced some frames while reading * in the file. */ ganiAcon.anih.cFrames = iFrame; /* * Now build up the listbox */ for( i = 0; i < (int)ganiAcon.anih.cSteps; i++ ) { PSTEP ps; ps = NewStep(); if (ps == NULL) goto laiFileErr; ps->jif = pjifRate[i]; LinkStepFrame(ps, ppfram[i]); SendDlgItemMessage(hwnd, DLG_MAIN_FRAMELIST, LB_INSERTSTRING, i, (LPARAM)ps); } SetDlgItemText(hwnd, DLG_MAIN_TITLE, ganiAcon.azTitle); SetDlgItemText(hwnd, DLG_MAIN_AUTHOR, ganiAcon.azCreator); SendDlgItemMessage(hwnd, DLG_MAIN_PREVIEW, PM_NEWCURSOR, 0, 0); fSuccess = TRUE; laiFileErr: if (pjifRate != NULL) FreeMem(pjifRate); if (!fSuccess) NewAniCursor(hwnd); CloseHandle(hf); return fSuccess; } /***************************************************************************\ * DWORD CalcCheckSum( PBYTE pb ); * * * History: * * 23-Apr-1993 JonPa Created. \***************************************************************************/ DWORD CalcCheckSum( PBYTE pb, DWORD cb ) { DWORD dw = 0; while(cb--) dw += (DWORD)*pb++; return dw; } /***************************************************************************\ * ReadTag, ReadChunk, SkipChunk * * Some handy functions for reading RIFF files. * * History: * 10-02-91 DarrinM Created. * 03-25-93 Jonpa Changed to use RIFF format instead of ASDF * 23-Apr-1993 JonPa Copied from Win NT USER. \***************************************************************************/ BOOL ReadTag( HANDLE hf, PRTAG ptag) { DWORD cbActual; ptag->ckID = ptag->ckSize = 0L; if (!ReadFile(hf, ptag, sizeof(RTAG), &cbActual, NULL) || (cbActual != sizeof(RTAG))) return FALSE; /* no need to align file pointer since RTAG is already word aligned */ return TRUE; } BOOL ReadChunk( HANDLE hf, PRTAG ptag, PVOID pv) { DWORD cbActual; if (!ReadFile(hf, pv, ptag->ckSize, &cbActual, NULL) || (cbActual != ptag->ckSize)) return FALSE; /* WORD align file pointer */ if( ptag->ckSize & 1 ) SetFilePointer(hf, 1, NULL, FILE_CURRENT); return TRUE; } BOOL ReadChunkN( HANDLE hf, PRTAG ptag, PVOID pv, DWORD cbMax) { DWORD cbActual; DWORD cbRead = min( cbMax, ptag->ckSize ); if (!ReadFile(hf, pv, ptag->ckSize, &cbActual, NULL) || (cbActual != cbRead)) return FALSE; /* WORD align file pointer */ cbRead = ptag->ckSize - cbActual; if( ptag->ckSize & 1 ) cbRead++; return SetFilePointer(hf, cbRead, NULL, FILE_CURRENT) != 0xFFFFFFFF; } BOOL SkipChunk( HANDLE hf, PRTAG ptag) { /* Round ptag->ckSize up to nearest word boundary to maintain alignment */ return SetFilePointer(hf, PADUP(ptag->ckSize), NULL, FILE_CURRENT) != 0xFFFFFFFFL; } /****************************************************************************\ * * FUNCTION: VOID GetTempCursorFileName( szFileName ); * * PURPOSE: Create a temporary .cur filename * * * History: * 22-Apr-1993 JonPa Created it * \****************************************************************************/ BOOL GetTempCursorFileName( LPTSTR pszName ) { TCHAR szPath[MAX_PATH]; if( GetTempPath( MAX_PATH, szPath ) >= MAX_PATH ) lstrcpy( pszName, TEXT(".") ); return GetTempFileName(szPath, TEXT("ae"), 0, pszName) != 0; } /****************************************************************************\ * * FUNCTION: BOOL SaveAniFile( HWND hwnd, HANDLE hf ) * * PURPOSE: & * Saves an animatied cursor to a RIFF file. The RIFF file format for * animated cursors looks like this: * * RIFF( 'ACON' * [LIST( 'INFO' * [INAM( )] * [IART( )] * )] * anih( ) * [rate( ) ] * ['seq '( )] * LIST( 'fram' icon( ) ) * ) * * * History: * 29-Apr-1993 JonPa Created it. * \****************************************************************************/ BOOL SaveAniFile( HWND hwnd, HANDLE hf ) { int cSteps, i; int cFrames; PFRAME pf; DWORD cbFile, cbFram, cbINFO, cbTitle, cbAuthor; BOOL fRate, fSeq; RTAG rtag; PJIF pjif; DWORD *pseq; PFRAME *pfrm; fRate = fSeq = FALSE; cbINFO = cbFram = cbFile = cbTitle = cbAuthor = 0; PausePreview(hwnd, DLG_MAIN_PREVIEW); cSteps = GetStepCount(hwnd); if( cSteps == LB_ERR ) { FmtMessageBox( ghwndMain, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE, MSG_OUTOFRESOUCES ); return FALSE; } cFrames = 0; for( pf = gpfrmFrames; pf != NULL; pf = pf->pfrmNext ) { pf->iFrame = -1; cFrames++; } ganiAcon.anih.cSteps = cSteps; pjif = AllocMem( (sizeof(JIF) + sizeof(DWORD) + sizeof(PFRAME)) * cSteps ); if(pjif == NULL) return FALSE; pseq = (DWORD *)&pjif[cSteps]; pfrm = (PFRAME *)&pseq[cSteps]; cFrames = 0; for( i = 0; i < cSteps; i++ ) { PSTEP ps; ps = GetStep(hwnd, i); if( IsValidPS(ps) ) { if (ps->pfrmFrame->iFrame == -1) { cbFram += sizeof(RTAG); cbFram += PADUP(ps->pfrmFrame->rtag.ckSize); ps->pfrmFrame->iFrame = cFrames; pfrm[cFrames++] = ps->pfrmFrame; } else fSeq = TRUE; pseq[i] = ps->pfrmFrame->iFrame; if ((pjif[i] = ps->jif) != ganiAcon.anih.jifRate) { fRate = TRUE; } } } ganiAcon.anih.cbSizeof = sizeof(ganiAcon.anih); ganiAcon.anih.cFrames = cFrames; ganiAcon.anih.fl = AF_ICON | (fSeq ? AF_SEQUENCE : 0); cbTitle = GetDlgItemTextA(hwnd, DLG_MAIN_TITLE, ganiAcon.azTitle, COUNTOF(ganiAcon.azTitle)); cbAuthor = GetDlgItemTextA(hwnd, DLG_MAIN_AUTHOR, ganiAcon.azCreator, COUNTOF(ganiAcon.azCreator)); /* * At this point, cbFram == the size required by all the frames, * add in the rate, seq, anih, and INFO list sizes as well as * all the other overhead. */ cbFram += sizeof(FOURCC); //fram type cbFile = cbFram; cbFile += sizeof(FOURCC) + //ACON type sizeof(RTAG) + //anih tag PADUP(sizeof(ANIHEADER)) + sizeof(RTAG); //LIST tag (for fram list) if( cbTitle || cbAuthor) { /* * Remember, azCreator, and azTitle are ANSI strings! */ if( cbTitle ) { cbTitle += 1; //add in ASCIIZ terminator cbINFO += sizeof(RTAG) + //INAM tag PADUP( cbTitle * sizeof(char)); } if (cbAuthor) { cbAuthor += 1; //add in ASCIIZ terminator cbINFO += sizeof(RTAG) + //IART tag PADUP(cbAuthor * sizeof(char)); } cbINFO += sizeof(FOURCC); //INFO type cbFile += sizeof(RTAG) + //LIST tag cbINFO; } if (fSeq) { cbFile += sizeof(RTAG) + //seq tag PADUP(cSteps * sizeof(DWORD)); } if (fRate) { cbFile += sizeof(RTAG) + //rate tag PADUP(cSteps * sizeof(JIF)); } /* * Now we have all the structures built in memory, it's time to * write them out in RIFF ACON format! */ rtag.ckID = FOURCC_RIFF; rtag.ckSize = cbFile; RET_CLOSE_IF_ERR( WriteTag(hf, &rtag), hf ); RET_CLOSE_IF_ERR( WriteType(hf, FOURCC_ACON), hf ); if( cbTitle || cbAuthor) { rtag.ckID = FOURCC_LIST; rtag.ckSize = cbINFO; RET_CLOSE_IF_ERR( WriteTag(hf, &rtag), hf ); RET_CLOSE_IF_ERR( WriteType(hf, FOURCC_INFO), hf ); if (cbTitle) { rtag.ckID = FOURCC_INAM; rtag.ckSize = cbTitle; RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, ganiAcon.azTitle), hf ); } if (cbAuthor) { rtag.ckID = FOURCC_IART; rtag.ckSize = cbAuthor; RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, ganiAcon.azCreator), hf ); } } /* write anih */ rtag.ckID = FOURCC_anih; rtag.ckSize = sizeof(ganiAcon.anih); RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, &(ganiAcon.anih)), hf ); /* if rate then write it */ if (fRate) { rtag.ckID = FOURCC_rate; rtag.ckSize = cSteps * sizeof(JIF); RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, pjif), hf ); } /* if seq, then write it */ if (fSeq) { rtag.ckID = FOURCC_seq; rtag.ckSize = cSteps * sizeof(DWORD); RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, pseq), hf ); } /* write the fram list */ rtag.ckID = FOURCC_LIST; rtag.ckSize = cbFram; RET_CLOSE_IF_ERR( WriteTag(hf, &rtag), hf ); RET_CLOSE_IF_ERR( WriteType(hf, FOURCC_fram), hf ); for( i = 0; i < cFrames; i++ ) { RET_CLOSE_IF_ERR( WriteTagData(hf, &(pfrm[i]->rtag), pfrm[i]->abIcon), hf); } /* Close the file */ CloseHandle(hf); return TRUE; } /***************************************************************************\ * WriteTag, WriteType, WriteTagData * * Some handy functions for writing RIFF files. * * History: * 30-Apr-1993 JonPa Created them. \***************************************************************************/ BOOL WriteTag(HANDLE hf, PRTAG prtag) { DWORD cbWritten; return (WriteFile(hf, prtag, sizeof(RTAG), &cbWritten, NULL) && cbWritten == sizeof(RTAG)); } BOOL WriteType(HANDLE hf, FOURCC ckID ) { DWORD cbWritten; return (WriteFile(hf, &ckID, sizeof(FOURCC), &cbWritten, NULL) && cbWritten == sizeof(FOURCC)); } BOOL WriteTagData(HANDLE hf, PRTAG prtag, VOID *pvData ) { DWORD cbWritten; DWORD cbWrite = PADUP(prtag->ckSize); return WriteTag(hf, prtag) && WriteFile(hf, pvData, cbWrite, &cbWritten, NULL) && cbWritten == cbWrite; } /***************************************************************************\ * VOID SaveFile(HWND hwnd, BOOL fPrompt) * * Conditionally Prompt the user for a name and then save the file * * History: * 04-May-1993 JonPa It \***************************************************************************/ VOID SaveFile(HWND hwnd, BOOL fPrompt) { TCHAR szFileTitle[MAX_PATH]; HANDLE hf; szFileTitle[0] = TEXT('\0'); if (fPrompt || ganiAcon.szFile[0] == TEXT('\0')) { tryagain: if (!PromptForFile(hwnd, COUNTOF(szFileTitle), szFileTitle, COUNTOF(ganiAcon.szFile), ganiAcon.szFile, gpszAniFilter, NULL, TRUE)) { return; } } hf = CreateFile( ganiAcon.szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hf == INVALID_HANDLE_VALUE) { FmtMessageBox(hwnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE, MSG_CANTCREATEFILE, ganiAcon.szFile); goto tryagain; } if( !SaveAniFile(hwnd, hf) ) { FmtMessageBox(hwnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE, MSG_FILEWRITEERR, ganiAcon.szFile); return; } if (szFileTitle[0] != TEXT('\0')) SetWindowFileTitle(hwnd, szFileTitle); ganiAcon.fDirty = FALSE; }