/* (C) Copyright Microsoft Corporation 1991-1994. All Rights Reserved */ // // FILE: oleglue.c // // NOTES: OLE-related outbound references from SoundRecorder // #include #include #include #include #include #define INCLUDE_OLESTUBS #include "soundrec.h" #include "srecids.h" // // GLOBALS // // should unify state variables and put globals into a single location DWORD dwOleBuildVersion = 0; // OLE library version number BOOL gfOleInitialized = FALSE; // did OleInitialize succeed? BOOL gfStandalone = FALSE; // status, are we a non-embedded object BOOL gfEmbedded = FALSE; // were we invoked with an -Embedding flag? BOOL gfLinked = FALSE; // are we a linked object? BOOL gfTerminating = FALSE; // has TerminateServer been called? BOOL gfHideAfterPlaying = FALSE; BOOL gfShowWhilePlaying = TRUE; BOOL gfCloseAtEndOfPlay = FALSE; TCHAR gachLinkFilename[_MAX_PATH]; BOOL gfClosing = FALSE; int giExtWidth; // Metafile extent width int giExtHeight; // Metafile extent height // // Utility functions ported from old OLE1 code // /* * DibFromBitmap() * * Will create a global memory block in DIB format that represents the DDB * passed in * */ #define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */ HANDLE FAR PASCAL DibFromBitmap(HBITMAP hbm, HPALETTE hpal, HANDLE hMem) { BITMAP bm; BITMAPINFOHEADER bi; BITMAPINFOHEADER FAR *lpbi; DWORD dw; HANDLE hdib = NULL; HDC hdc; HPALETTE hpalT; if (!hbm) return NULL; GetObject(hbm,sizeof(bm),&bm); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = bm.bmWidth; bi.biHeight = bm.bmHeight; bi.biPlanes = 1; bi.biBitCount = (bm.bmPlanes * bm.bmBitsPixel) > 8 ? 24 : 8; bi.biCompression = BI_RGB; bi.biSizeImage = (DWORD)WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = bi.biBitCount == 8 ? 256 : 0; bi.biClrImportant = 0; dw = bi.biSize + bi.biClrUsed * sizeof(RGBQUAD) + bi.biSizeImage; if (hMem && GlobalSize(hMem) != 0) { if (GlobalSize(hMem) < dw) return NULL; lpbi = GlobalLock(hMem); } else lpbi = GlobalAllocPtr(GHND | GMEM_DDESHARE, dw); if (!lpbi) return NULL; *lpbi = bi; hdc = CreateCompatibleDC(NULL); if (hdc) { if (hpal) { hpalT = SelectPalette(hdc,hpal,FALSE); RealizePalette(hdc); } GetDIBits(hdc, hbm, 0, (UINT)bi.biHeight, (LPBYTE)lpbi + (int)lpbi->biSize + (int)lpbi->biClrUsed * sizeof(RGBQUAD), (LPBITMAPINFO)lpbi, DIB_RGB_COLORS); if (hpal) SelectPalette(hdc,hpalT,FALSE); DeleteDC(hdc); } hdib = GlobalHandle(lpbi); GlobalUnlock(hdib); return hdib; } HANDLE GetDIB(HANDLE hMem) { HPALETTE hpal = GetStockObject(DEFAULT_PALETTE); HBITMAP hbm = GetBitmap(); HANDLE hDib = NULL; if (hbm && hpal) { hDib = DibFromBitmap(hbm,hpal,hMem); if (!hDib) DOUT(TEXT("DibFromBitmap failed!\r\n")); } if (hpal) DeleteObject(hpal); if (hbm) DeleteObject(hbm); return hDib; } HBITMAP GetBitmap(void) { HDC hdcmem = NULL; HDC hdc = NULL; HBITMAP hbitmap = NULL; HBITMAP holdbitmap = NULL; RECT rc; hdc = GetDC(ghwndApp); if (hdc) { SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); hdcmem = CreateCompatibleDC(hdc); if (hdcmem) { hbitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom); holdbitmap = (HBITMAP)SelectObject(hdcmem, hbitmap); // paint directly into the bitmap PatBlt(hdcmem, 0, 0, rc.right, rc.bottom, WHITENESS); DrawIcon(hdcmem, 0, 0, ghiconApp); hbitmap = (HBITMAP)SelectObject(hdcmem, holdbitmap); DeleteDC(hdcmem); } ReleaseDC(ghwndApp, hdc); } return hbitmap; } #pragma message("this code should extract the picture from the file") HANDLE GetPicture(void) { HANDLE hpict = NULL; HMETAFILE hMF = NULL; LPMETAFILEPICT lppict = NULL; HBITMAP hbmT = NULL; HDC hdcmem = NULL; HDC hdc = NULL; BITMAP bm; HBITMAP hbm; hbm = GetBitmap(); if (hbm == NULL) return NULL; GetObject(hbm, sizeof(bm), (LPVOID)&bm); hdc = GetDC(ghwndApp); if (hdc) { hdcmem = CreateCompatibleDC(hdc); ReleaseDC(ghwndApp, hdc); } if (!hdcmem) { DeleteObject(hbm); return NULL; } hdc = CreateMetaFile(NULL); hbmT = (HBITMAP)SelectObject(hdcmem, hbm); SetWindowOrgEx(hdc, 0, 0, NULL); SetWindowExtEx(hdc, bm.bmWidth, bm.bmHeight, NULL); StretchBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcmem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); hMF = CloseMetaFile(hdc); SelectObject(hdcmem, hbmT); DeleteObject(hbm); DeleteDC(hdcmem); lppict = (LPMETAFILEPICT)GlobalAllocPtr(GHND|GMEM_DDESHARE , sizeof(METAFILEPICT)); if (!lppict) { if (hMF) DeleteMetaFile(hMF); return NULL; } hdc = GetDC(ghwndApp); lppict->mm = MM_ANISOTROPIC; lppict->hMF = hMF; lppict->xExt = MulDiv(bm.bmWidth, 2540, GetDeviceCaps(hdc, LOGPIXELSX)); lppict->yExt = MulDiv(bm.bmHeight, 2540, GetDeviceCaps(hdc, LOGPIXELSX)); giExtWidth = lppict->xExt; giExtHeight = lppict->yExt; ReleaseDC(ghwndApp, hdc); hpict = GlobalHandle(lppict); GlobalUnlock(hpict); return hpict; } // // Code ported from server.c (OLE1) for serialization... // HANDLE GetNativeData(void) { LPBYTE lplink = NULL; MMIOINFO mmioinfo; HMMIO hmmio; BOOL fOk; lplink = (LPBYTE)GlobalAllocPtr(GHND | GMEM_SHARE, 4096L); if (lplink == NULL) { #if DBG OutputDebugString(TEXT("GetNativeData: malloc failed\r\n")); #endif return NULL; } mmioinfo.fccIOProc = FOURCC_MEM; mmioinfo.pIOProc = NULL; mmioinfo.pchBuffer = lplink; mmioinfo.cchBuffer = 4096L; // initial size mmioinfo.adwInfo[0] = 4096L; // grow by this much hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READWRITE); if (hmmio == NULL) { GlobalFreePtr(lplink); return NULL; } fOk = WriteWaveFile(hmmio , gpWaveFormat , gcbWaveFormat , gpWaveSamples , glWaveSamplesValid); mmioGetInfo(hmmio, &mmioinfo, 0); mmioClose(hmmio,0); if (fOk) { // // Warning, the buffer we allocated may have been realloc'd // HANDLE hlink = GlobalHandle(mmioinfo.pchBuffer); GlobalUnlock(hlink); return hlink; } else { gfErrorBox++; ErrorResBox( ghwndApp , ghInst , MB_ICONEXCLAMATION | MB_OK , IDS_APPTITLE , IDS_ERROREMBED ); #if DBG OutputDebugString(TEXT("Failed to WriteWaveFile\r\n")); #endif gfErrorBox--; // // Warning, the buffer we allocated may have been realloc'd // if (mmioinfo.pchBuffer) GlobalFreePtr(mmioinfo.pchBuffer); return NULL; } } /* * Called from OLE storage code */ LPBYTE PutNativeData(LPBYTE lpbData, DWORD dwSize) { MMIOINFO mmioinfo; HMMIO hmmio; MMRESULT mmr; LPWAVEFORMATEX pwfx; DWORD cbwfx; DWORD cbdata; LPBYTE pdata; mmioinfo.fccIOProc = FOURCC_MEM; mmioinfo.pIOProc = NULL; mmioinfo.pchBuffer = lpbData; mmioinfo.cchBuffer = dwSize; // initial size mmioinfo.adwInfo[0] = 0L; // grow by this much hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READ); if (hmmio) { mmr = ReadWaveFile(hmmio , &pwfx , &cbwfx , &pdata , &cbdata , TEXT("NativeData") , TRUE); mmioClose(hmmio,0); if (mmr != MMSYSERR_NOERROR) return NULL; if (pwfx == NULL) return NULL; DestroyWave(); gpWaveFormat = pwfx; gcbWaveFormat = cbwfx; gpWaveSamples = pdata; glWaveSamples = cbdata; } // // update state variables // glWaveSamplesValid = glWaveSamples; glWavePosition = 0L; gfDirty = FALSE; // // update the display // UpdateDisplay(TRUE); return (LPBYTE)gpWaveSamples; } /* * PERMANENT ENTRY POINTS */ BOOL ParseCommandLine(LPTSTR lpCommandLine); /* * modifies gfEmbedded, initializes gStartParams */ BOOL InitializeSRS(HINSTANCE hInst) { TCHAR * lptCmdLine = GetCommandLine(); BOOL fOLE = FALSE, fServer; gfUserClose = FALSE; gachLinkFilename[0] = 0; fServer = ParseCommandLine(lptCmdLine); gfEmbedded = fServer; // We are embedded or linked if (!fServer) { if (gStartParams.achOpenFilename[0] != 0) { lstrcpy(gachLinkFilename, gStartParams.achOpenFilename); } } // // Only if we are invoked as an embedded object do we initialize OLE. // Defer initialization for the standalone object until later. // if (gfEmbedded) fOLE = InitializeOle(hInst); return fOLE; } /* OLE initialization */ BOOL InitializeOle(HINSTANCE hInst) { BOOL fOLE; DOUT(TEXT("SOUNDREC: Initializing OLE\r\n")); dwOleBuildVersion = OleBuildVersion(); // Fix bug #33271 // As stated in the docs: // Typically, the COM library is initialized on an apartment only once. // Subsequent calls will succeed, as long as they do not attempt to change // the concurrency model of the apartment, but will return S_FALSE. To close // the COM library gracefully, each successful call to OleInitialize, // including those that return S_FALSE, must be balanced by a corresponding // call to OleUninitialize. // gfOleInitialized = (OleInitialize(NULL) == NOERROR) ? TRUE : FALSE; gfOleInitialized = SUCCEEDED(OleInitialize(NULL)); if (gfOleInitialized) fOLE = CreateSRClassFactory(hInst, gfEmbedded); else fOLE = FALSE; // signal a serious problem! return fOLE; } /* * Initialize the state of the application or * change state from Embedded to Standalone. */ void FlagEmbeddedObject(BOOL flag) { // Set global state variables. Note, gfEmbedding is untouched. gfEmbeddedObject = flag; gfStandalone = !flag; } void SetOleCaption( LPTSTR lpszObj) { TCHAR aszFormatString[256]; LPTSTR lpszTitle; // // Change title to "Sound Object in XXX" // LoadString(ghInst, IDS_OBJECTTITLE, aszFormatString, SIZEOF(aszFormatString)); lpszTitle = (LPTSTR)GlobalAllocPtr(GHND, (lstrlen(lpszObj) + SIZEOF(aszFormatString))*sizeof(TCHAR)); if (lpszTitle) { wsprintf(lpszTitle, aszFormatString, lpszObj); SetWindowText(ghwndApp, lpszTitle); GlobalFreePtr(lpszTitle); } } void SetOleMenu( HMENU hMenu, LPTSTR lpszObj) { TCHAR aszFormatString[256]; LPTSTR lpszMenu; // // Change menu to "Exit & Return to XXX" // LoadString(ghInst, IDS_EXITANDRETURN, aszFormatString, SIZEOF(aszFormatString)); lpszMenu = (LPTSTR)GlobalAllocPtr(GHND, (lstrlen(lpszObj) + SIZEOF(aszFormatString))*sizeof(TCHAR)); if (lpszMenu) { wsprintf(lpszMenu, aszFormatString, lpszObj); ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND, IDM_EXIT, lpszMenu); GlobalFreePtr(lpszMenu); } } /* Adjust menus according to system state. * */ void FixMenus(void) { HMENU hMenu; hMenu = GetMenu(ghwndApp); if (!gfLinked && gfEmbeddedObject) { // Remove these menu items as they are irrelevant. DeleteMenu(hMenu, IDM_NEW, MF_BYCOMMAND); DeleteMenu(hMenu, IDM_SAVE, MF_BYCOMMAND); DeleteMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND); DeleteMenu(hMenu, IDM_REVERT, MF_BYCOMMAND); DeleteMenu(hMenu, IDM_OPEN, MF_BYCOMMAND); } else { TCHAR ach[40]; // Is this necessary? LoadString(ghInst, IDS_NONEMBEDDEDSAVE, ach, SIZEOF(ach)); ModifyMenu(hMenu, IDM_SAVE, MF_BYCOMMAND, IDM_SAVE, ach); } // // Update the titlebar and exit menu too. // if (!gfLinked && gfEmbeddedObject) { LPTSTR lpszObj = NULL; LPTSTR lpszApp = NULL; OleObjGetHostNames(&lpszApp,&lpszObj); if (lpszObj) lpszObj = (LPTSTR)FileName((LPCTSTR)lpszObj); if (lpszObj) { SetOleCaption(lpszObj); SetOleMenu(hMenu, lpszObj); } } DrawMenuBar(ghwndApp); /* Can't hurt... */ } #define WM_USER_DESTROY (WM_USER+10) // // Called from WM_CLOSE (from user) or SCtrl::~SCtrl (from container) // void TerminateServer(void) { DOUT(TEXT("SoundRec: TerminateServer\r\n")); gfTerminating = TRUE; if (gfOleInitialized) { WriteObjectIfEmpty(); ReleaseSRClassFactory(); FlushOleClipboard(); // // If, at this time, we haven't closed, we really should. // if (!gfClosing) { DoOleClose(TRUE); AdviseClosed(); } } // // only if the user is terminating OR we're embedded // if (gfUserClose || !gfStandalone) PostMessage(ghwndApp, WM_USER_DESTROY, 0, 0); } /* start params! * the app will use these params to determine behaviour once started. */ StartParams gStartParams = { FALSE,FALSE,FALSE,FALSE,TEXT("") }; BOOL ParseCommandLine(LPTSTR lpCommandLine) { #define TEST_STRING_MAX 11 // sizeof szEmbedding #define NUMOPTIONS 6 static TCHAR szEmbedding[] = TEXT("embedding"); static TCHAR szPlay[] = TEXT("play"); static TCHAR szOpen[] = TEXT("open"); static TCHAR szNew[] = TEXT("new"); static TCHAR szClose[] = TEXT("close"); static struct tagOption { LPTSTR name; LPTSTR filename; int cchfilename; LPBOOL state; } options [] = { { NULL, gStartParams.achOpenFilename, _MAX_PATH, &gStartParams.fOpen }, { szEmbedding, gStartParams.achOpenFilename, _MAX_PATH, &gfEmbedded }, { szPlay, gStartParams.achOpenFilename, _MAX_PATH, &gStartParams.fPlay }, { szOpen, gStartParams.achOpenFilename, _MAX_PATH, &gStartParams.fOpen }, { szNew, gStartParams.achOpenFilename, _MAX_PATH, &gStartParams.fNew }, { szClose, NULL, 0, &gStartParams.fClose } }; LPTSTR pchNext; int iOption = 0,i,cNumOptions = sizeof(options)/sizeof(struct tagOption); TCHAR szSwitch[TEST_STRING_MAX]; TCHAR ch; if (lpCommandLine == NULL) return FALSE; /* skip argv[0] */ if (*lpCommandLine == TEXT('"')) { // // eat up everything to the next quote // lpCommandLine++; do { ch = *lpCommandLine++; } while (ch != TEXT('"')); } else { // // eat up everything to the next whitespace // ch = *lpCommandLine; while (ch != TEXT(' ') && ch != TEXT('\t') && ch != TEXT('\0')) ch = *++lpCommandLine; } pchNext = lpCommandLine; while ( *pchNext ) { LPTSTR pchName = options[iOption].filename; int cchName = options[iOption].cchfilename; /* whitespace */ switch (*pchNext) { case TEXT(' '): case TEXT('\t'): pchNext++; continue; case TEXT('-'): case TEXT('/'): { lstrcpyn(szSwitch,pchNext+1,TEST_STRING_MAX); szSwitch[TEST_STRING_MAX-1] = 0; /* scan to the NULL or ' ' and terminate string */ for (i = 0; i < TEST_STRING_MAX && szSwitch[i] != 0; i++) if (szSwitch[i] == TEXT(' ')) { szSwitch[i] = 0; break; } /* now test each option switch for a hit */ for (i = 0; i < cNumOptions; i++) { if (options[i].name == NULL) continue; if (!lstrcmpi(szSwitch,options[i].name)) { *(options[i].state) = TRUE; if (options[i].filename) /* next non switch string applies to this option */ iOption = i; break; } } /* seek ahead */ while (*pchNext && *pchNext != TEXT(' ')) pchNext++; continue; } case TEXT('\"'): /* filename */ /* copy up to next quote */ pchNext++; while (*pchNext && *pchNext != TEXT('\"')) { if (cchName) { *pchName++ = *pchNext++; cchName--; } else break; } pchNext++; continue; default: /* filename */ /* copy up to the end */ while (*pchNext && cchName) { *pchName++ = *pchNext++; cchName--; } break; } } /* special case. * we are linked if given a LinkFilename and an embedding flag. * Does this ever happen or only through IPersistFile? */ if (gfEmbedded && gStartParams.achOpenFilename[0] != 0) { gfLinked = TRUE; } return gfEmbedded; } void BuildUniqueLinkName(void) { // //Ensure a unique filename in gachLinkFilename so we can create valid //FileMonikers... // if(gachLinkFilename[0] == 0) { TCHAR aszFile[_MAX_PATH]; GetTempFileName(TEXT("."), TEXT("Tmp"), 0, gachLinkFilename); /* GetTempFileName creates an empty file, delete it. */ GetFullPathName(gachLinkFilename,SIZEOF(aszFile),aszFile,NULL); DeleteFile(aszFile); } } void AppPlay(BOOL fClose) { if (fClose) { //ugh. don't show while playing. gfShowWhilePlaying = FALSE; } if (IsWindow(ghwndApp)) { gfCloseAtEndOfPlay = fClose; PostMessage(ghwndApp,WM_COMMAND,ID_PLAYBTN, 0L); } }