Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Application.c
/* |
File: Offscreen.c |
Contains: QuickTime 3.0 Offscreen sample application. |
Written by: Scott Kuechle |
based on MDIPlayer code by Brian S. Friedkin |
Copyright: © 1998 by Apple Computer, Inc., all rights reserved. |
Change History (most recent first): |
<2> 5/18/98 rtm minor tweaks to GetBitDepthOfBitmap and DrawBackgroundBitmap to get this code |
working with the Metrowerks compiler |
<1> 4/24/98 srk first file; revised to personal coding style |
NOTES: |
TO DO: |
*/ |
#include "Application.h" |
#include "QTCode.h" |
long FAR PASCAL FrameWndProc (HWND, UINT, UINT, LONG) ; |
long FAR PASCAL MovieWndProc (HWND, UINT, UINT, LONG) ; |
BOOL DoOpenMovie(); |
int DoIdleMenus(HWND hWnd, HMENU hMenu); |
static void DoCut(HWND); |
static void DoCopy(HWND); |
static void DoPaste(HWND); |
static void DoClear(HWND); |
static void DoUndo(HWND); |
static void DoAbout(void); |
HPALETTE DoCreatePaletteFromBitMap(HMODULE appInstance, WORD bitMapID); |
void SetMovieFrameTimeValue(Movie theMovie, TimeValue thisPoint); |
WORD GetBitDepthOfBitmap(HMODULE appInstance, WORD bitMapID); |
void GetRBGColorsFromBitmap(HDC hDC, HANDLE hInst, WORD bitMapID, LPRGBQUAD *srcRgbQuadArray, HPALETTE *hPalette); |
void DoEraseRect(HDC hDC, RECT *theRect); |
int GetLineHeight(HDC hDC); |
void DrawMovieAndBackground(HGLOBAL hWinStorage, HDC hDC, HWND hwnd); |
/* globals for this module */ |
HANDLE ghInst = NULL; |
HWND ghWndFrame = NULL; |
HWND ghWndMDIClient = NULL; |
BOOL gWeAreSizingWindow = 0; |
BOOL gWeAreCreatingWindow = 0; |
int gOpenMovieCount = 0; |
char gAppName[20]; |
char gChildName[20]; |
LPRGBQUAD gSrcRgbQuadArray = NULL; /* rbg color values for our window background bitmap */ |
HPALETTE gHBackgroundPalette = NULL; /* color palette for our window background */ |
HANDLE ghBkgrndBitMap = NULL; /* bitmap we paint on the background of our client windows */ |
/* ---------------------------------------------------------------- */ |
/* */ |
/* WinMain() */ |
/* */ |
/* */ |
/* The main function for this application */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, |
LPSTR lpszCmdLine, int nCmdShow) |
{ |
HANDLE hAccel ; |
HWND hwndFrame; |
MSG msg ; |
WNDCLASSEX wc; |
BOOL success; |
ghInst = hInstance ; |
if (!hPrevInstance) |
{ |
LoadString(hInstance, IDS_APPNAME, gAppName, sizeof(gAppName)); |
// Register the frame window class |
wc.cbSize = sizeof(WNDCLASSEX); |
wc.style = CS_HREDRAW | CS_VREDRAW; |
wc.lpfnWndProc = (WNDPROC)FrameWndProc; |
wc.cbClsExtra = 0; |
wc.cbWndExtra = 0; |
wc.hInstance = hInstance; |
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON)); |
wc.hCursor = LoadCursor(NULL, IDC_ARROW); |
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); |
wc.lpszMenuName = gAppName; |
wc.lpszClassName = gAppName; |
wc.hIconSm = LoadImage(hInstance, |
MAKEINTRESOURCE(IDI_APPICON), |
IMAGE_ICON, |
16, 16, |
0); |
if (!RegisterClassEx(&wc)) |
{ |
if (!RegisterClass((LPWNDCLASS)&wc.style)) |
return FALSE; |
} |
LoadString(hInstance, IDS_MDICHILD, gChildName, sizeof(gChildName)); |
// Register the Movie child window class |
wc.cbSize = sizeof(WNDCLASSEX); |
wc.style = CS_HREDRAW | CS_VREDRAW; |
wc.lpfnWndProc = (WNDPROC)MovieWndProc; |
wc.cbClsExtra = 0; |
wc.cbWndExtra = 0; |
wc.hInstance = hInstance; |
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CHILDICON)); |
wc.hCursor = LoadCursor(NULL, IDC_ARROW); |
wc.hbrBackground = NULL /* we want to handle erasing of the background ourselves */; |
wc.lpszMenuName = NULL; |
wc.lpszClassName = gChildName; |
wc.hIconSm = LoadImage(hInstance, |
MAKEINTRESOURCE(IDI_CHILDICON), |
IMAGE_ICON, |
16, 16, |
0); |
if (!RegisterClassEx(&wc)) |
{ |
if (!RegisterClass((LPWNDCLASS)&wc.style)) |
return FALSE; |
} |
} |
// Load accelerators |
hAccel = LoadAccelerators (hInstance, gAppName); |
// Create the main frame window |
ghWndFrame = hwndFrame = CreateWindow (gAppName, gAppName, |
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, |
CW_USEDEFAULT, CW_USEDEFAULT, |
CW_USEDEFAULT, CW_USEDEFAULT, |
NULL, NULL, hInstance, NULL) ; |
/* get background bitmap for use with our client windows */ |
ghBkgrndBitMap = LoadResource(ghInst, FindResource(ghInst, MAKEINTRESOURCE(IDB_BITMAP2), RT_BITMAP) ); |
/* Show the window */ |
ShowWindow(hwndFrame, nCmdShow); |
UpdateWindow(hwndFrame); |
/* Initialize QuickTime */ |
success = QTCode_DoQTInit(); |
if (success) |
{ |
/* Process messages */ |
while (GetMessage(&msg, NULL, 0, 0)) |
{ |
if (!TranslateMDISysAccel(ghWndMDIClient, &msg)) |
if (!TranslateAccelerator(hwndFrame, hAccel, &msg)) |
{ |
TranslateMessage(&msg); |
DispatchMessage(&msg); |
} |
} |
} |
else |
{ |
MessageBox(hwndFrame, "Quicktime 3.0 not available", "", MB_OK); |
} |
/* QuickTime clean up */ |
QTCode_QTCleanUp(); |
return msg.wParam; |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* FrameWndProc() */ |
/* */ |
/* */ |
/* The window procedure for the MDI frame window */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
long FAR PASCAL FrameWndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam) |
{ |
HWND hwndChild ; |
switch (message) |
{ |
case WM_CREATE: // Create the client window |
{ |
CLIENTCREATESTRUCT ccs = {0}; |
ccs.hWindowMenu = GetSubMenu(GetMenu(hwnd), WINDOWMENU); |
ccs.idFirstChild = IDM_WINDOWCHILD; |
// Create the MDI client filling the client area |
ghWndMDIClient = CreateWindow("mdiclient", |
NULL, |
WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | |
WS_HSCROLL, |
0, 0, 0, 0, |
hwnd, |
(HMENU)0xCAC, |
ghInst, |
(LPVOID)&ccs); |
ShowWindow(ghWndMDIClient, SW_SHOW); |
} |
return 0 ; |
case WM_COMMAND: |
switch (LOWORD(wParam)) |
{ |
case IDM_FILEOPEN: |
DoOpenMovie(); |
return 0 ; |
case IDM_FILECLOSE: |
hwndChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L) ; |
if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0L)) |
{ |
SendMessage (ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0L) ; |
} |
return 0 ; |
case IDM_EXIT: |
SendMessage (hwnd, WM_CLOSE, 0, 0L) ; |
return 0 ; |
case IDM_WINDOWTILE: |
SendMessage (ghWndMDIClient, WM_MDITILE, 0, 0L) ; |
return 0 ; |
case IDM_WINDOWCASCADE: |
SendMessage (ghWndMDIClient, WM_MDICASCADE, 0, 0L) ; |
return 0 ; |
case IDM_WINDOWICONS: |
SendMessage (ghWndMDIClient, WM_MDIICONARRANGE, 0, 0L) ; |
return 0 ; |
case IDM_WINDOWCLOSEALL: |
{ |
HWND hwndT; |
while (hwndT = GetWindow(ghWndMDIClient, GW_CHILD)) |
{ |
// Skip the icon and title windows |
while (hwndT && GetWindow(hwndT, GW_OWNER)) |
hwndT = GetWindow(hwndT, GW_HWNDNEXT); |
if (!hwndT) break; |
SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndT, 0L); |
} |
} |
return 0; |
case IDM_ABOUT: |
DoAbout(); |
return 0; |
default: // Pass to active child |
hwndChild = (HWND)SendMessage (ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L) ; |
if (IsWindow (ghWndMDIClient)) |
SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ; |
break ; // and then to DefFrameProc |
} |
break ; |
case WM_INITMENU: |
if (GetMenu(hwnd) == (HMENU)wParam) |
return DoIdleMenus((HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0), (HMENU)wParam); |
return 1; |
case WM_DESTROY : |
PostQuitMessage (0) ; |
return 0 ; |
} |
return DefFrameProc (hwnd, ghWndMDIClient, message, wParam, lParam) ; |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* MovieWndProc() */ |
/* */ |
/* */ |
/* The window procedure for our movie window */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
long FAR PASCAL MovieWndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam) |
{ |
HGLOBAL hWinStorage = NULL; |
ChildWindowPtr childWinPtr = NULL; |
MSG msg = {0}; |
hWinStorage = (HGLOBAL)GetWindowLong(hwnd, GWL_USERDATA); |
switch (message) |
{ |
case WM_CREATE: |
{ |
GrafPtr gp; |
/* Tuck away some private storage */ |
hWinStorage = GlobalAlloc(GMEM_MOVEABLE + GMEM_ZEROINIT, sizeof(ChildWindowRecord)); |
SetWindowLong(hwnd, GWL_USERDATA, (LPARAM)hWinStorage); |
/* Associate a GrafPort with this window */ |
gp = QTCode_DoCreatePortAssociation(hwnd, NULL, 0); |
} |
return 0; |
case WM_GETMINMAXINFO: |
{ |
if (hWinStorage != NULL) |
{ |
childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage); |
if (childWinPtr != NULL) |
{ |
LPMINMAXINFO lpmmi; |
lpmmi = (LPMINMAXINFO) lParam; |
/* we restrict the grow size of our window */ |
lpmmi->ptMaxSize.x = childWinPtr->maxWindowWidth; |
lpmmi->ptMaxSize.y = childWinPtr->maxWindowHeight; |
lpmmi->ptMaxTrackSize.x = childWinPtr->maxWindowWidth; |
lpmmi->ptMaxTrackSize.y = childWinPtr->maxWindowHeight; |
GlobalUnlock(hWinStorage); |
} |
} |
} |
return 0; |
case WM_PAINT: |
{ |
PAINTSTRUCT lPaint; |
HDC hDC; |
hDC = BeginPaint(hwnd, &lPaint); |
if (hDC != NULL) |
{ |
DrawMovieAndBackground(hWinStorage, hDC, hwnd); |
} |
EndPaint(hwnd, &lPaint); |
} |
return 0; |
case WM_WINDOWPOSCHANGING: |
// Don't show the window until we have created a movie and therefore |
// can properly size the window to contain the movie. |
if (gWeAreCreatingWindow) |
{ |
WINDOWPOS *lpWindowPos = (WINDOWPOS*)lParam; |
lpWindowPos->flags &= ~SWP_SHOWWINDOW; |
return 0; |
} |
return 0; |
case WM_KEYDOWN: |
if (wParam == VK_RETURN) /* return key was pressed */ |
{ |
HDC hDC = NULL; |
OSType mediaType = VideoMediaType; |
if (hWinStorage != NULL) |
{ |
childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage); |
if (childWinPtr != NULL) |
{ |
/* move to next interesting movie time to display */ |
childWinPtr->currentTime = |
QTCode_DoGetMovieNextInterestingTime(childWinPtr->currentTime, childWinPtr->movie, |
VideoMediaType); |
GlobalUnlock(hWinStorage); |
hDC = GetDC(hwnd); |
if (hDC != NULL) |
{ |
DrawMovieAndBackground(hWinStorage, hDC, hwnd); |
ReleaseDC(hwnd, hDC); |
} |
} |
} |
} |
return 0; |
case WM_SIZE: |
{ |
if (hWinStorage != NULL) |
{ |
childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage); |
if (childWinPtr != NULL) |
{ |
if (childWinPtr->movie) |
{ |
QTCode_PositionMovieRectInClientWindow(childWinPtr->movie, hwnd); |
} |
GlobalUnlock(hWinStorage); |
} |
} |
} |
return 0; |
case WM_ERASEBKGND: |
{ |
/* we don't want the background erased when the window is |
re-sized, so we'll trap calls here for the WM_ERASEBKGND |
event */ |
} |
return (1); /* tell GDI we've handled erasing ourselves */ |
case WM_COMMAND: |
{ |
switch(LOWORD(wParam)) // Undo, Cut, Copy, Paste and Clear |
{ |
case IDM_EDITUNDO: |
DoUndo(hwnd); |
break; |
case IDM_EDITCUT: |
DoCut(hwnd); |
break; |
case IDM_EDITCOPY: |
DoCopy(hwnd); |
break; |
case IDM_EDITPASTE: |
DoPaste(hwnd); |
break; |
case IDM_EDITCLEAR: |
DoClear(hwnd); |
break; |
} |
} |
break; |
case WM_DESTROY: |
{ |
if (hWinStorage != NULL) |
{ |
childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage); |
if (childWinPtr != NULL) |
{ |
/* One less movie open */ |
--gOpenMovieCount; |
QTCode_DisposeMovieAndController(childWinPtr->movie, childWinPtr->refNum); |
/* Destroy the port association */ |
QTCode_DoDestroyPortAssociation(hwnd); |
/* clean up offscreen GWorld */ |
QTCode_DoDestroyOffscreen(childWinPtr->offscreenGWorld, childWinPtr->hBitmap); |
SetWindowLong(hwnd, GWL_USERDATA, 0); |
GlobalUnlock(hWinStorage); |
GlobalFree((HGLOBAL)GetWindowLong(hwnd, GWL_USERDATA)); |
} |
} |
} |
return 0; |
} |
return DefMDIChildProc (hwnd, message, wParam, lParam); |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoOpenMovie() */ |
/* */ |
/* */ |
/* Code to open a given movie and prepare it for display in a */ |
/* window */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
BOOL DoOpenMovie() |
{ |
DWORD dwVersion; |
short len; |
char szPathName[256], szFileName[256]; |
HWND hwndChild = 0; |
OPENFILENAME ofn = {0}; |
HDC hDC; |
HGLOBAL hWinStorage = NULL; |
OSErr err; |
Movie movie = NULL; |
short movieRefNum; |
short movieResId; |
int movWidth, movHeight; |
// Present the dialog... |
*szPathName = 0; |
ofn.lStructSize = sizeof(OPENFILENAME); |
ofn.hwndOwner = ghWndFrame; |
ofn.lpstrFile = (LPSTR)szPathName; |
ofn.nMaxFile = sizeof(szPathName); |
ofn.lpstrFilter = "QuickTime Movies (*.mov) \0 *.mov\0All Files (*.*) \0 *.*\0"; |
ofn.nFilterIndex = 1; |
ofn.lpstrInitialDir = NULL; |
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; |
if (!GetOpenFileName(&ofn)) goto bail; |
err = QTCode_NewMovieFromWinPathname(szPathName, /* c-string path to movie */ |
&movie, /* Movie returned here */ |
&movieRefNum, /* Movie RefNum returned here */ |
&movieResId); /* Movie Resource ID returned here */ |
if (err == noErr) |
{ |
Rect movieBounds; |
GetMovieBox(movie, &movieBounds); |
movWidth = RECT_WIDTH(movieBounds); |
movHeight = RECT_HEIGHT(movieBounds); |
} |
// Create the child movie window |
dwVersion = GetVersion(); |
gWeAreCreatingWindow = TRUE; |
if ((dwVersion < 0x80000000) || (LOBYTE(LOWORD(dwVersion)) < 4)) |
{ |
// This is Windows NT or Win32s, so use the WM_MDICREATE message |
MDICREATESTRUCT mcs; |
mcs.szClass = gChildName; |
mcs.szTitle = szFileName; |
mcs.hOwner = ghInst; |
mcs.x = CW_USEDEFAULT; |
mcs.y = CW_USEDEFAULT; |
mcs.cx = movWidth + kWinSpacer; /* set an appropriate width for our movie window */ |
mcs.cy = movHeight + kWinSpacer; /* set an appropriate height for our movie window */ |
mcs.style = 0; |
mcs.lParam = 0; |
hwndChild = (HWND) SendMessage(ghWndMDIClient, |
WM_MDICREATE, |
0, |
(LPARAM)(LPMDICREATESTRUCT) &mcs); |
} |
else |
{ |
// This method will only work with Windows 95, not Windows NT or Win32s |
hwndChild = CreateWindowEx(WS_EX_MDICHILD, |
gChildName, |
szFileName, |
0, |
CW_USEDEFAULT, |
CW_USEDEFAULT, |
movWidth + kWinSpacer, /* set an appropriate width for our movie window */ |
movHeight + kWinSpacer, /* set an appropriate height for our movie window */ |
ghWndMDIClient, |
NULL, |
ghInst, |
0); |
} |
gWeAreCreatingWindow = FALSE; |
if (!hwndChild) goto bail; |
// Set the window title to the movie filename |
len = strlen(szPathName); |
while (len--) |
{ |
char c = szPathName[len]; |
if (c == 0x5c || c == '/') |
{ |
strcpy(szFileName, &szPathName[len+1]); |
break; |
} |
} |
SetWindowText(hwndChild, szFileName); |
// Store movie info in private window record |
hWinStorage = (HGLOBAL)GetWindowLong(hwndChild, GWL_USERDATA); |
if (hWinStorage != NULL) |
{ |
ChildWindowPtr childWinPtr = NULL; |
childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage); |
if (childWinPtr != NULL) |
{ |
childWinPtr->ghInst = ghInst; |
if (movie != NULL) |
{ |
childWinPtr->movie = movie; |
childWinPtr->refNum = movieRefNum; |
childWinPtr->hBkgrndBitmap = ghBkgrndBitMap; |
childWinPtr->maxWindowWidth = movWidth + kWinSpacer; |
childWinPtr->maxWindowHeight = movHeight + kWinSpacer; |
QTCode_PositionMovieRectInClientWindow(childWinPtr->movie, hwndChild); |
err = QTCode_GetStartPointOfFirstVideoSample(childWinPtr->movie, &childWinPtr->currentTime); |
} |
hDC = GetDC(hwndChild); |
if (hDC != NULL) |
{ |
WORD bitDepthDC; |
RECT windowRect; |
QDErr err; |
GetRBGColorsFromBitmap( hDC, |
ghInst, |
IDB_BITMAP2, /* ID of background bitmap we want to use */ |
&childWinPtr->srcRgbQuadArray, /* on return, a pointer to a rgbquad |
structure for this bitmap */ |
&childWinPtr->hBackgroundPalette); /* if bitmap bit depth <= 8, a custom palette */ |
bitDepthDC = GetDCBitDepth(hDC); |
GetWindowRect(hwndChild, &windowRect); |
childWinPtr->hBitmap = DoCreateDIBSection(hDC, /* the device context for this HWND */ |
childWinPtr->srcRgbQuadArray, /* pointer to RGBQUAD array to use when creating |
DIB - NULL if bit depth > 8 */ |
bitDepthDC, /* screen depth setting */ |
RECT_WIDTH(windowRect), /* window width */ |
RECT_HEIGHT(windowRect) /* window height */ |
); |
childWinPtr->hMemDC = DoCreateMemoryDC(hwndChild); |
SelectObject(childWinPtr->hMemDC, childWinPtr->hBitmap); |
err = QTCode_CreateOffscreen(&childWinPtr->offscreenGWorld, |
NULL, |
NULL, |
0, |
childWinPtr->hBitmap,/* a pointer to a valid bitmap or NULL */ |
childWinPtr->hMemDC); /* a pointer to a valid device context or NULL */ |
QTCode_SetMovieGWorld(childWinPtr->movie, childWinPtr->offscreenGWorld); |
ReleaseDC(hwndChild, hDC); |
} |
GlobalUnlock(hWinStorage); |
} |
} |
SetWindowLong(hwndChild, GWL_USERDATA, (LPARAM)hWinStorage); |
// Show the window |
ShowWindow(hwndChild, SW_SHOW); |
UpdateWindow(hwndChild); |
SetFocus(hwndChild); |
// One more window has been opened |
gOpenMovieCount += 1; |
return TRUE; |
bail: |
if (hwndChild) SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0L); |
return FALSE; |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DrawMovieAndBackground() */ |
/* */ |
/* */ |
/* Code to display a movie and background image in a given */ |
/* window */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
void DrawMovieAndBackground(HGLOBAL hWinStorage, HDC hDC, HWND hwnd) |
{ |
HPALETTE previousPalette = NULL; |
ChildWindowPtr childWinPtr; |
if ((childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage)) != NULL) |
{ |
RECT clientRect, windowRect; |
Rect movieBounds; |
previousPalette = UseCustomPalette(hDC, childWinPtr->hBackgroundPalette); |
GetClientRect(hwnd, &clientRect); |
GetWindowRect(hwnd, &windowRect); |
DrawBackgroundBitmap(childWinPtr->hMemDC, hwnd, childWinPtr->hBkgrndBitmap, &clientRect); |
DrawHelpMessage(childWinPtr->hMemDC, hwnd); |
GetMovieBox(childWinPtr->movie, &movieBounds); |
DoDrawFrameInfo(childWinPtr->hMemDC, hwnd, &movieBounds, childWinPtr->currentTime); |
SetMovieTimeValue(childWinPtr->movie, childWinPtr->currentTime); |
QTCode_ForceMovieRedraw(childWinPtr->movie); |
/* copy our memory DC image to the display DC */ |
BitBlt(hDC, 0, 0, RECT_WIDTH(windowRect), RECT_HEIGHT(windowRect), childWinPtr->hMemDC, |
0, 0, SRCCOPY); |
GlobalUnlock(hWinStorage); |
} |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoCut() */ |
/* */ |
/* */ |
/* Handles clipboard "cut" operations */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
static void DoCut(HWND hwnd) |
{ |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoCopy() */ |
/* */ |
/* */ |
/* Handles clipboard "copy" operations */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
static void DoCopy(HWND hwnd) |
{ |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoPaste() */ |
/* */ |
/* */ |
/* Handles clipboard "paste" operations */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
static void DoPaste(HWND hwnd) |
{ |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoClear() */ |
/* */ |
/* */ |
/* Handles clipboard "clear" operations */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
static void DoClear(HWND hwnd) |
{ |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoUndo() */ |
/* */ |
/* */ |
/* Handles clipboard "undo" operations */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
static void DoUndo(HWND hwnd) |
{ |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoIdleMenus() */ |
/* */ |
/* */ |
/* Enable the close item if there are any movie windows opened */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
int DoIdleMenus(HWND hWnd, HMENU hMenu) |
{ |
/* Enable the close item if there are any movie windows opened */ |
EnableMenuItem(hMenu, IDM_FILECLOSE, (gOpenMovieCount) ? MF_ENABLED : MF_GRAYED); |
return 0; |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DialogProc() */ |
/* */ |
/* */ |
/* Callback for our dialog box */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
static LRESULT CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) |
{ |
switch (message) |
{ |
case WM_COMMAND: |
switch (LOWORD(wParam)) |
{ |
case IDOK: |
EndDialog(hDlg, IDOK); |
break; |
} |
break; |
} |
return 0; |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoAbout() */ |
/* */ |
/* */ |
/* Displays a dialog box with information about our program */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
static void DoAbout() |
{ |
DialogBox(ghInst, MAKEINTRESOURCE(IDD_ABOUT), ghWndFrame, (DLGPROC)DialogProc); |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DrawBackgroundBitmap() */ |
/* */ |
/* */ |
/* Sets the pixels in the target device context to those from */ |
/* a given DIB */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
void DrawBackgroundBitmap( HDC hDC, |
HWND hwnd, |
HANDLE hBitMap, |
RECT *updateRect) |
{ |
if ((hBitMap != NULL) && (hDC != NULL) && (hwnd != NULL)) |
{ |
LPBITMAPINFO lpBi; |
LPTSTR lpBits; |
int x, y, width, height; |
int success = FALSE; |
RECT clientRect; |
int childHeight, childWidth; |
GetClientRect(hwnd, &clientRect); |
childWidth = RECT_WIDTH(clientRect); |
childHeight = RECT_HEIGHT(clientRect); |
lpBi = (LPBITMAPINFO)LockResource(hBitMap); |
lpBits = (LPSTR)lpBi; |
lpBits += lpBi->bmiHeader.biSize + ((1 << lpBi->bmiHeader.biBitCount) * sizeof(RGBQUAD)); |
width = lpBi->bmiHeader.biWidth; |
height = lpBi->bmiHeader.biHeight; |
for (y = 0; y <= childHeight; y += lpBi->bmiHeader.biHeight) |
{ |
for (x = 0; x <= childWidth; x += lpBi->bmiHeader.biWidth) |
{ |
BOOL intersectRect = FALSE; |
RECT bitMapRect; |
RECT destRect; |
SetRect(&bitMapRect, x, y, x+lpBi->bmiHeader.biWidth, y+lpBi->bmiHeader.biHeight); |
intersectRect = IntersectRect( &destRect, // address of structure for intersection |
updateRect, // address of structure with first rectangle |
&bitMapRect // address of structure with second rectangle |
); |
/* does the current rectangle intersect with the update |
rectangle? If so, draw it, otherwise, don't */ |
if (intersectRect) |
{ |
success = SetDIBitsToDevice(hDC, x, y, |
lpBi->bmiHeader.biWidth, |
lpBi->bmiHeader.biHeight, |
0,0, |
0, lpBi->bmiHeader.biHeight, |
lpBits, lpBi, |
DIB_RGB_COLORS); |
} |
} |
} |
} |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoCreatePaletteFromBitMap() */ |
/* */ |
/* */ |
/* Builds a palette from a given bitmap */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
HPALETTE DoCreatePaletteFromBitMap( HMODULE appInstance, |
WORD bitMapID) |
{ |
HANDLE hBitMap; |
HPALETTE hPalette = NULL; |
hBitMap = LoadResource(appInstance, |
FindResource(appInstance, MAKEINTRESOURCE(bitMapID), RT_BITMAP) ); |
if (hBitMap != NULL) |
{ |
LPBITMAPINFO lpBi; |
HANDLE hPal; |
LPLOGPALETTE lpPal; |
int i, nColorData; |
lpBi = (LPBITMAPINFO)LockResource(hBitMap); |
if (lpBi->bmiHeader.biClrUsed != 0) |
{ |
nColorData = lpBi->bmiHeader.biClrUsed; |
} |
else |
{ |
switch( lpBi->bmiHeader.biBitCount) |
{ |
case 1 : |
nColorData = 2; |
break; |
case 4 : |
nColorData = 16; |
break; |
case 8 : |
nColorData = 256; |
break; |
case 24 : |
case 32 : |
nColorData = 0; |
break; |
} |
} |
hPal = GlobalAlloc( GHND, sizeof (LOGPALETTE) + (nColorData * sizeof (PALETTEENTRY)) ); |
lpPal = (LPLOGPALETTE)GlobalLock(hPal); |
lpPal->palVersion = 0x300; |
lpPal->palNumEntries = nColorData; |
for (i = 0; i < nColorData; i++) |
{ |
lpPal->palPalEntry[i].peRed = lpBi->bmiColors[i].rgbRed; |
lpPal->palPalEntry[i].peGreen = lpBi->bmiColors[i].rgbGreen; |
lpPal->palPalEntry[i].peBlue = lpBi->bmiColors[i].rgbBlue; |
} |
hPalette = CreatePalette( lpPal ); |
GlobalUnlock(hPal); |
GlobalFree(hPal); |
} |
return hPalette; |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoEraseRect() */ |
/* */ |
/* */ |
/* Code to erase a given windows rectangle */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
void DoEraseRect(HDC hDC, |
RECT *theRect) |
{ |
if (hDC != NULL) |
{ |
HBRUSH aBrush; |
/* erase rect. for string before redraw */ |
aBrush = CreateSolidBrush(RGB(255,255,255)); |
if (aBrush != NULL) |
{ |
FillRect(hDC, theRect, aBrush); |
DeleteObject(aBrush); |
} |
} |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* GetLineHeight() */ |
/* */ |
/* */ |
/* Returns the line height for a given device context */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
int GetLineHeight(HDC hDC) |
{ |
TEXTMETRIC tm; |
GetTextMetrics(hDC, &tm); |
return(tm.tmExternalLeading + tm.tmHeight); |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DrawHelpMessage() */ |
/* */ |
/* */ |
/* Draws our help text in a window */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
void DrawHelpMessage( HDC hDC, |
HWND hwnd) |
{ |
if (hDC != NULL) |
{ |
RECT clientRect, targetRect; |
char helpText[100] = "Press <enter> to advance to next movie frame"; |
TEXTMETRIC tm; |
int nLineHeight, strWidth; |
GetClientRect(hwnd, &clientRect); |
GetTextMetrics(hDC, &tm); |
nLineHeight = tm.tmExternalLeading + tm.tmHeight; |
strWidth = strlen( (LPCTSTR)&helpText ) * tm.tmAveCharWidth; |
SetRect(&targetRect, clientRect.left + ((RECT_WIDTH(clientRect) - strWidth)/2), |
clientRect.bottom - nLineHeight, |
clientRect.left + ((RECT_WIDTH(clientRect) - strWidth)/2) + strWidth, |
clientRect.bottom); |
DoEraseRect(hDC, &targetRect); |
/* draw help message */ |
DrawText(hDC, (LPCTSTR)&helpText, -1, &targetRect, DT_CENTER); |
} |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoCreateDIBSection() */ |
/* */ |
/* */ |
/* Creates a device independent bitmap using CreateDIBSection */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
HBITMAP DoCreateDIBSection( HDC dc, |
LPRGBQUAD srcRgbQuadArray, /* if (depth > 8), this param ignored */ |
WORD depth, |
LONG width, |
LONG height |
) |
{ |
UINT usage; |
LPTSTR bits = NULL; |
// a struct large enough to hold the largest bitmapinfo ... |
struct BITMAPINFO_256 |
{ |
BITMAPINFOHEADER bmiHeader; |
long bmiColors[256]; |
}; |
typedef struct BITMAPINFO_256 BITMAPINFO_256; |
BITMAPINFO_256 bmi; |
memset(&bmi, 0, sizeof(bmi)); |
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
bmi.bmiHeader.biWidth = width; |
/* important!!! - we specify a top-down DIB (by passing a negative height value) |
with origin in the upper left, otherwise our movie image will show up as inverted */ |
bmi.bmiHeader.biHeight = -1 * height; |
bmi.bmiHeader.biPlanes = 1; |
bmi.bmiHeader.biBitCount = depth; |
bmi.bmiHeader.biSizeImage = 0; |
bmi.bmiHeader.biClrUsed = 0; |
bmi.bmiHeader.biClrImportant = 0; |
switch ( depth ) |
{ |
case 4: |
case 8: |
{ |
long num_colors = (1 << depth), |
i; |
LPRGBQUAD lpQuadDest, lpQuadSource; |
bmi.bmiHeader.biCompression = BI_RGB; |
usage = DIB_RGB_COLORS; |
lpQuadSource = srcRgbQuadArray; |
for (i=0; i<num_colors; i++) |
{ |
lpQuadDest = (LPRGBQUAD)&bmi.bmiColors[i]; |
lpQuadDest->rgbBlue = lpQuadSource->rgbBlue; |
lpQuadDest->rgbRed = lpQuadSource->rgbRed; |
lpQuadDest->rgbGreen = lpQuadSource->rgbGreen; |
lpQuadDest->rgbReserved = lpQuadSource->rgbReserved; |
++lpQuadSource; |
} |
} |
break; |
case 16: |
case 24: |
case 32: |
{ |
bmi.bmiHeader.biCompression = BI_RGB; |
usage = DIB_RGB_COLORS; |
bmi.bmiColors[0] = 0; |
bmi.bmiColors[1] = 0; |
bmi.bmiColors[2] = 0; |
} |
break; |
default: |
break; |
} |
return CreateDIBSection(dc, (BITMAPINFO *) &bmi, usage, &bits, NULL, 0); |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* GetDCBitDepth() */ |
/* */ |
/* */ |
/* Returns the bit depth of a device context */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
WORD GetDCBitDepth(HDC hDC) |
{ |
return(GetDeviceCaps( hDC, BITSPIXEL)); |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* GetBitDepthOfBitmap() */ |
/* */ |
/* */ |
/* Returns the bit depth of a bitmap */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
WORD GetBitDepthOfBitmap(HMODULE appInstance, /* application instance */ |
WORD bitMapID /* resource ID of bit map */ |
) |
{ |
HBITMAP hBitMap; |
hBitMap = LoadResource(appInstance, FindResource(appInstance, MAKEINTRESOURCE(bitMapID), RT_BITMAP) ); |
if (hBitMap != NULL) |
{ |
LPBITMAPINFO lpBi; |
lpBi = (LPBITMAPINFO)LockResource(hBitMap); |
return (lpBi->bmiHeader.biBitCount); |
} |
else |
{ |
return 0; |
} |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* GetRBGColorsFromBitmap() */ |
/* */ |
/* */ |
/* Returns the RGBQUAD array for a bitmap */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
void GetRBGColorsFromBitmap(HDC hDC, |
HANDLE hInst, |
WORD bitMapID, |
LPRGBQUAD *srcRgbQuadArray, /* on return, a pointer to a rgbquad |
structure for this bitmap */ |
HPALETTE *hPalette) /* if bitmap bit depth <= 8, a custom palette |
for the bitmap will be returned here */ |
{ |
WORD bitDepthDC, bitDepthBITMAP; |
LPBITMAPINFO srcBITMAPINFO; |
HANDLE hBitMapTemp; |
bitDepthDC = GetDCBitDepth(hDC); |
bitDepthBITMAP = GetBitDepthOfBitmap(hInst, /* application instance */ |
bitMapID /* resource ID of bit map */ |
); |
srcBITMAPINFO = NULL; |
*srcRgbQuadArray = NULL; |
*hPalette = NULL; |
/* does the device context have a bit depth <= 8? */ |
if (bitDepthDC <= 8) |
{ |
/* does our bitmap have a depth <= 8? */ |
if (bitDepthBITMAP <= 8) |
{ |
/* create custom palette for use with this bitmap */ |
*hPalette = DoCreatePaletteFromBitMap(hInst, bitMapID); |
/* get color data to use when calling CreateDIBSection */ |
hBitMapTemp = LoadResource(hInst, |
FindResource(hInst, MAKEINTRESOURCE(bitMapID), |
RT_BITMAP) ); |
if (hBitMapTemp != NULL) |
{ |
/* get bitmapinfo data */ |
srcBITMAPINFO = (LPBITMAPINFO)LockResource(hBitMapTemp); |
/* get pointer to rgbquad array for this bitmap */ |
*srcRgbQuadArray = &srcBITMAPINFO->bmiColors[0]; |
} |
} |
} |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoCreateMemoryDC() */ |
/* */ |
/* */ |
/* Creates a memory device context */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
HDC DoCreateMemoryDC(HWND hwnd) |
{ |
HDC hMemDC, hDC; |
hDC = GetDC(hwnd); |
if (hDC) |
{ |
hMemDC = CreateCompatibleDC(hDC); |
SetMapMode(hMemDC, GetMapMode(hDC)); |
ReleaseDC(hwnd, hDC); |
return hMemDC; |
} |
return NULL; |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* UseCustomPalette() */ |
/* */ |
/* */ |
/* Selects/Realizes a logical palette */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
HPALETTE UseCustomPalette(HDC hDC, HPALETTE newPalette) |
{ |
HPALETTE previousPalette; |
UINT nEntries; |
/* use a custom palette if need be */ |
if (newPalette) |
{ |
previousPalette = SelectPalette(hDC, newPalette, FALSE); |
nEntries = RealizePalette(hDC); |
} |
return previousPalette; |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* DoDrawFrameInfo() */ |
/* */ |
/* */ |
/* Draws our help text messages into a window */ |
/* */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
void DoDrawFrameInfo(HDC hMemDC, |
HWND hwnd, |
Rect *movieBounds, |
TimeValue theTime) |
{ |
RECT destRect; |
int nLineHeight; |
Str255 theString; |
char frameText[25] = "Frame "; |
Rect centeredRect; |
nLineHeight = GetLineHeight(hMemDC); |
CenterMovieRectInWindow(hwnd, /* window where we are placing the image */ |
(movieBounds->right - movieBounds->left), |
(movieBounds->bottom - movieBounds->top), /* width, height, of the movie */ |
¢eredRect /* on output, a Mac Rect centered in the window */ |
); |
SetRect(&destRect, (int)centeredRect.left - nLineHeight, |
(int)centeredRect.top - nLineHeight /*- menuSize*/, |
(int)centeredRect.right + nLineHeight, |
(int)centeredRect.bottom + nLineHeight /*- menuSize*/); |
DoEraseRect(hMemDC, &destRect); |
SetRect(&destRect, (int)centeredRect.left, |
(int)centeredRect.bottom /*- menuSize*/, |
(int)centeredRect.right, |
(int)centeredRect.bottom + nLineHeight /*- menuSize*/); |
DoEraseRect(hMemDC, &destRect); |
/* draw new frame # */ |
NumToString((long)theTime, theString); |
p2cstr(theString); |
lstrcat((LPSTR)frameText, (LPCSTR)&theString); |
DrawText(hMemDC, (LPCTSTR)&frameText, -1, &destRect, DT_CENTER); |
} |
/* ---------------------------------------------------------------- */ |
/* */ |
/* CenterMovieRectInWindow() */ |
/* */ |
/* */ |
/* Given height/width values for a movie, returns a Mac rect */ |
/* for the movie centered in a window */ |
/* */ |
/* */ |
/* ---------------------------------------------------------------- */ |
void CenterMovieRectInWindow(HWND hwnd, /* window where we are placing the image */ |
int movWidth, int movHeight, /* width, height, of the movie */ |
Rect *centeredRect /* on output, a Mac Rect centered in the window */ |
) |
{ |
RECT clientRect; |
int availSpace; |
BOOL success; |
success = GetClientRect(hwnd, // handle of window |
&clientRect// address of structure for client coordinates |
); |
availSpace = RECT_WIDTH(clientRect) - movWidth; |
if (availSpace < 0) |
{ |
/* movie is bigger than client space? */ |
} |
centeredRect->left = clientRect.left + availSpace/2; |
availSpace = RECT_HEIGHT(clientRect) - movHeight; |
if (availSpace < 0) |
{ |
/* movie is bigger than client space? */ |
} |
centeredRect->top = clientRect.top + availSpace/2; |
centeredRect->right = centeredRect->left + movWidth; |
centeredRect->bottom = centeredRect->top + movHeight; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14