941 lines
24 KiB
C
941 lines
24 KiB
C
//==========================================================================;
|
|
// thunk32.c
|
|
//
|
|
// Copyright (c) 1991-1994 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Description:
|
|
// This module contains routines for thunking the video APIs
|
|
// from 16-bit Windows to 32-bit WOW.
|
|
//
|
|
// History:
|
|
//
|
|
//==========================================================================;
|
|
|
|
// This stuff is not going to work 64-bit
|
|
#pragma warning(disable:4312)
|
|
|
|
|
|
/*
|
|
|
|
WOW Thunking design:
|
|
|
|
Thunks are generated as follows :
|
|
|
|
16-bit :
|
|
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <mmsystem.h>
|
|
#include <mmddk.h>
|
|
#include <mmreg.h>
|
|
#include <memory.h>
|
|
#include <win32.h>
|
|
#ifdef _WIN32
|
|
#include <ivideo32.h>
|
|
#ifndef _INC_MSVIDEO
|
|
#define _INC_MSVIDEO 50 /* version number */
|
|
#endif
|
|
#else
|
|
#include <vfw.h>
|
|
#endif
|
|
#include <msviddrv.h>
|
|
#include <msvideoi.h>
|
|
#ifdef _WIN32
|
|
#include <wownt32.h>
|
|
#include <stdlib.h> // for mbstowcs and wcstombs
|
|
#include <video16.h>
|
|
#ifdef UNICODE
|
|
#include "profile.h" // NT only (for now?)
|
|
#endif
|
|
#endif // WIN32
|
|
|
|
// in capinit.c
|
|
BOOL capInternalGetDriverDescA(UINT wDriverIndex,
|
|
LPSTR lpszName, int cbName,
|
|
LPSTR lpszVer, int cbVer);
|
|
|
|
//
|
|
// pick up the function definitions
|
|
//
|
|
|
|
#include "vidthunk.h"
|
|
|
|
#ifdef DEBUG
|
|
#define MODNAME "AVICAP32"
|
|
int videoDebugLevel = -1;
|
|
void videoDebugInit(VOID)
|
|
{
|
|
if (videoDebugLevel == -1)
|
|
videoDebugLevel = GetProfileIntA("Debug", MODNAME, 0);
|
|
}
|
|
#else
|
|
#define videoDebugInit()
|
|
#endif
|
|
|
|
/* -------------------------------------------------------------------------
|
|
** Handle and memory mapping functions.
|
|
** -------------------------------------------------------------------------
|
|
*/
|
|
LPWOWHANDLE32 lpWOWHandle32;
|
|
LPWOWHANDLE16 lpWOWHandle16;
|
|
LPWOWCALLBACK16 lpWOWCallback16;
|
|
LPGETVDMPOINTER GetVdmPointer;
|
|
int ThunksInitialized;
|
|
|
|
#ifdef WIN32
|
|
#ifdef DEBUG
|
|
void FAR cdecl thkdprintf(LPSTR szFormat, ...)
|
|
{
|
|
char ach[128];
|
|
va_list va;
|
|
|
|
#define MARKER "AVICAP (thunk): "
|
|
lstrcpyA(ach, MARKER);
|
|
|
|
va_start(va, szFormat);
|
|
wvsprintfA(ach+sizeof(MARKER), szFormat, va);
|
|
va_end(va);
|
|
OutputDebugStringA(ach);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
//
|
|
// Useful functions
|
|
//
|
|
|
|
//
|
|
// CopyAlloc - allocate a new piece of memory, and copy the data in
|
|
// Must use LocalFree to release the memory later
|
|
//
|
|
PVOID CopyAlloc(PVOID pvSrc, UINT uSize)
|
|
{
|
|
PVOID pvDest;
|
|
|
|
pvDest = (PVOID)LocalAlloc(LMEM_FIXED, uSize);
|
|
|
|
if (pvDest != NULL) {
|
|
CopyMemory(pvDest, pvSrc, uSize);
|
|
}
|
|
|
|
return pvDest;
|
|
}
|
|
|
|
/*
|
|
* Copy data from source to dest where source is a 32bit pointer
|
|
* and dest is a 16bit pointer
|
|
*/
|
|
void CopyTo16Bit(LPVOID Dest16, LPVOID Src32, DWORD Length)
|
|
{
|
|
PVOID Dest32;
|
|
|
|
if (Src32 == NULL) {
|
|
return;
|
|
}
|
|
|
|
Dest32 = GetVdmPointer((DWORD)(DWORD_PTR)Dest16, Length, TRUE);
|
|
|
|
CopyMemory(Dest32, Src32, Length);
|
|
}
|
|
|
|
|
|
/*
|
|
* Copy data from source to dest where source is a 16bit pointer
|
|
* and dest is a 32bit pointer
|
|
*/
|
|
void CopyTo32Bit(LPVOID Dest32, LPVOID Src16, DWORD Length)
|
|
{
|
|
PVOID Src32;
|
|
|
|
if (Src16 == NULL) {
|
|
return;
|
|
}
|
|
|
|
Src32 = GetVdmPointer((DWORD)(DWORD_PTR)Src16, Length, TRUE);
|
|
|
|
CopyMemory(Dest32, Src32, Length);
|
|
}
|
|
|
|
/*
|
|
* Copy data from source to dest where source is a 16bit pointer
|
|
* and dest is a 32bit pointer ONLY if the source is not aligned
|
|
*
|
|
* Returns which pointer to use (src or dest)
|
|
*/
|
|
LPVOID CopyIfNotAligned(LPVOID Dest32, LPVOID Src16, DWORD Length)
|
|
{
|
|
PVOID Src32;
|
|
|
|
if (Src16 == NULL) {
|
|
return Dest32;
|
|
}
|
|
|
|
Src32 = GetVdmPointer((DWORD)(DWORD_PTR)Src16, Length, TRUE);
|
|
|
|
CopyMemory(Dest32, Src32, Length);
|
|
|
|
return Dest32;
|
|
}
|
|
|
|
|
|
typedef struct _callback {
|
|
WORD flags;
|
|
WORD hVideo16;
|
|
WORD msg;
|
|
DWORD dwCallback16inst;
|
|
DWORD dw1;
|
|
DWORD dw2;
|
|
} CALLBACK16;
|
|
typedef CALLBACK16 * PCALLBACK16;
|
|
|
|
/*
|
|
* Callbacks
|
|
*/
|
|
|
|
void MyVideoCallback(HANDLE handle,
|
|
UINT msg,
|
|
DWORD dwUser,
|
|
DWORD dw1,
|
|
DWORD dw2)
|
|
{
|
|
PVIDEOINSTANCEDATA32 pInst;
|
|
BOOL fFree = FALSE;
|
|
|
|
pInst = (PVIDEOINSTANCEDATA32)dwUser;
|
|
|
|
DPF3(("Video callback - handle = %8X, msg = %8X, dwUser = %8X, dw1 = %8X, dw2 = %8X\n",
|
|
handle, msg, dwUser, dw1, dw2));
|
|
|
|
switch (msg) {
|
|
|
|
/*
|
|
* What are the parameters for these messages ??
|
|
*/
|
|
|
|
case MM_DRVM_OPEN:
|
|
|
|
/*
|
|
* We get this when we INIT_STREAM
|
|
*/
|
|
|
|
break;
|
|
|
|
case MM_DRVM_CLOSE:
|
|
|
|
/*
|
|
* Device is closing - this is where we free our structures
|
|
* (just in case the 32-bit side called close to clean up).
|
|
* dwUser points to our data
|
|
*/
|
|
|
|
fFree = TRUE;
|
|
|
|
break;
|
|
|
|
case MM_DRVM_DATA:
|
|
|
|
/*
|
|
* We have data - this means a buffer has been returned in
|
|
* dw1
|
|
*/
|
|
|
|
{
|
|
PVIDEOHDR32 pHdr32;
|
|
|
|
pHdr32 = CONTAINING_RECORD((PVIDEOHDR)dw1,
|
|
VIDEOHDR32,
|
|
videoHdr);
|
|
|
|
dw1 = (DWORD)(DWORD_PTR)pHdr32->pHdr16; // For callback below
|
|
|
|
/*
|
|
* Map back the data and free our structure
|
|
*/
|
|
|
|
{
|
|
VIDEOHDR Hdr16;
|
|
Hdr16 = pHdr32->videoHdr;
|
|
Hdr16.lpData = pHdr32->lpData16;
|
|
memcpy(pHdr32->pHdr32, (LPVOID)&Hdr16, sizeof(VIDEOHDR));
|
|
}
|
|
|
|
/*
|
|
* Clean up our local structure
|
|
*/
|
|
|
|
LocalFree((HLOCAL)pHdr32);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MM_DRVM_ERROR:
|
|
/*
|
|
* dw1 = frames skipped - unfortunately there's nobody to tell!
|
|
*/
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Call back the application if appropriate
|
|
*/
|
|
|
|
switch (pInst->dwFlags & CALLBACK_TYPEMASK) {
|
|
case CALLBACK_WINDOW:
|
|
PostMessage(ThunkHWND(LOWORD(pInst->dwCallback)),
|
|
msg, (WPARAM)handle, (LPARAM)dw1);
|
|
break;
|
|
|
|
case CALLBACK_FUNCTION:
|
|
#if 0
|
|
// Must call a generic 16 bit callback passing a pointer to
|
|
// a parameter array.
|
|
{
|
|
|
|
WORD hMem;
|
|
PCALLBACK16 pCallStruct;
|
|
pCallStruct = WOWGlobalAllocLock16(0, sizeof(CALLBACK16), &hMem);
|
|
if (pCallStruct) {
|
|
pCallStruct->flags = HIWORD(pInst->dwFlags);
|
|
pCallStruct->hVideo16 = (WORD)pInst->hVideo;
|
|
pCallStruct->msg = (WORD)msg;
|
|
pCallStruct->dwCallback16inst = pInst->dwCallbackInst;
|
|
pCallStruct->dw1 = (DWORD)dw1;
|
|
pCallStruct->dw2 = (DWORD)dw2;
|
|
|
|
lpWOWCallback16(pInst->dwCallback, pCallStruct);
|
|
|
|
// Now free off the callback structure
|
|
WOWGlobalUnlockFree16(pCallStruct);
|
|
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
if (fFree) {
|
|
LocalFree((HLOCAL)pInst);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Thunking callbacks to WOW32 (or wherever)
|
|
//
|
|
|
|
|
|
typedef struct tag_video_stream_init_parms16 {
|
|
DWORD dwMicroSecPerFrame;
|
|
DWORD dwCallback;
|
|
DWORD dwCallbackInst;
|
|
DWORD dwFlags;
|
|
DWORD_PTR hVideo;
|
|
} VIDEO_STREAM_INIT_PARMS16, FAR * LPVIDEO_STREAM_INIT_PARMS16;
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// DWORD videoThunk32
|
|
//
|
|
// Description:
|
|
//
|
|
// 32-bit function dispatcher for thunks.
|
|
//
|
|
// Arguments:
|
|
// DWORD dwThunkId:
|
|
//
|
|
// DWORD dw1:
|
|
//
|
|
// DWORD dw2:
|
|
//
|
|
// DWORD dw3:
|
|
//
|
|
// DWORD dw4:
|
|
//
|
|
// Return (DWORD):
|
|
//
|
|
// History:
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD videoThunk32(DWORD dwThunkId,DWORD dw1,DWORD dw2,DWORD dw3,DWORD dw4)
|
|
{
|
|
//
|
|
// Make sure we've got thunking functionality
|
|
//
|
|
if (ThunksInitialized <= 0) {
|
|
|
|
HMODULE hMod;
|
|
|
|
if (ThunksInitialized == -1) {
|
|
return MMSYSERR_ERROR;
|
|
}
|
|
|
|
videoDebugInit();
|
|
|
|
hMod = GetModuleHandle(GET_MAPPING_MODULE_NAME);
|
|
if (hMod != NULL) {
|
|
|
|
GetVdmPointer =
|
|
(LPGETVDMPOINTER)GetProcAddress(hMod, GET_VDM_POINTER_NAME);
|
|
lpWOWHandle32 =
|
|
(LPWOWHANDLE32)GetProcAddress(hMod, GET_HANDLE_MAPPER32 );
|
|
lpWOWHandle16 =
|
|
(LPWOWHANDLE16)GetProcAddress(hMod, GET_HANDLE_MAPPER16 );
|
|
lpWOWCallback16 =
|
|
(LPWOWCALLBACK16)GetProcAddress(hMod, GET_CALLBACK16 );
|
|
}
|
|
|
|
if ( GetVdmPointer == NULL
|
|
|| lpWOWHandle16 == NULL
|
|
|| lpWOWHandle32 == NULL ) {
|
|
|
|
ThunksInitialized = -1;
|
|
return MMSYSERR_ERROR;
|
|
|
|
} else {
|
|
ThunksInitialized = 1;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Perform the requested function
|
|
//
|
|
|
|
switch (dwThunkId) {
|
|
|
|
case vidThunkvideoMessage32:
|
|
return (DWORD) videoMessage32((HVIDEO)dw1, (UINT)dw2, dw3, dw4);
|
|
break;
|
|
|
|
case vidThunkvideoGetNumDevs32:
|
|
return (DWORD) videoGetNumDevs32();
|
|
break;
|
|
|
|
case vidThunkvideoOpen32:
|
|
return (DWORD) videoOpen32((LPHVIDEO)dw1, dw2, dw3);
|
|
break;
|
|
|
|
case vidThunkvideoClose32:
|
|
return (DWORD) videoClose32((HVIDEO)dw1);
|
|
break;
|
|
|
|
case vidThunkvideoGetDriverDesc32:
|
|
{
|
|
LPSTR lpszName = NULL, lpszVer = NULL;
|
|
short cbName, cbVer;
|
|
DWORD dwRet;
|
|
|
|
cbName = (short) LOWORD(dw4);
|
|
cbVer = (short) HIWORD(dw4);
|
|
|
|
// for chicago, need to call WOW32GetVdmPointerFix
|
|
// (via getprocaddr!)
|
|
|
|
if ((dw2 != 0) && (cbName > 0)) {
|
|
lpszName = WOW32ResolveMemory(dw2);
|
|
}
|
|
if ((dw3 != 0) && (cbVer > 0)) {
|
|
lpszVer = WOW32ResolveMemory(dw3);
|
|
}
|
|
|
|
|
|
dwRet = capInternalGetDriverDescA(
|
|
dw1, // device id
|
|
lpszName,
|
|
cbName,
|
|
lpszVer,
|
|
cbVer);
|
|
|
|
#if 0 //should do this for chicago
|
|
if (lpszName) {
|
|
WOWGetVDMPointerUnfix(dw2);
|
|
}
|
|
if (lpszVer) {
|
|
WOWGetVDMPointerUnfix(dw3);
|
|
}
|
|
#endif
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
default:
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
LRESULT FAR PASCAL videoMessage32(HVIDEO hVideo, UINT msg, DWORD dwP1, DWORD dwP2)
|
|
{
|
|
StartThunk(videoMessage);
|
|
DPF2(("\tvideoMessage id = %4X, lParam1 = %8X, lParam2 = %8X",
|
|
msg, dwP1, dwP2));
|
|
|
|
/*
|
|
* We ONLY support (and we only ever will support) messages which
|
|
* have ALREADY been defined. New 32-bit driver messages will NOT
|
|
* be supported from 16-bit apps.
|
|
*/
|
|
|
|
switch (msg) {
|
|
case DVM_GETVIDEOAPIVER:
|
|
{
|
|
DWORD ApiVer;
|
|
|
|
ReturnCode = videoMessage((HVIDEO)hVideo,
|
|
(UINT)msg,
|
|
(DWORD_PTR)&ApiVer,
|
|
dwP2);
|
|
|
|
if (ReturnCode == DV_ERR_OK) {
|
|
CopyTo16Bit((LPVOID)dwP1, &ApiVer, sizeof(DWORD));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DVM_GETERRORTEXT:
|
|
{
|
|
VIDEO_GETERRORTEXT_PARMS vet;
|
|
VIDEO_GETERRORTEXT_PARMS MappedVet;
|
|
|
|
/*
|
|
* Get the parameter block
|
|
*/
|
|
|
|
CopyTo32Bit((LPVOID)&vet, (LPVOID)dwP1, sizeof(vet));
|
|
MappedVet = vet;
|
|
|
|
/*
|
|
* Map the string pointer
|
|
*/
|
|
|
|
MappedVet.lpText = WOW32ResolveMemory(vet.lpText);
|
|
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
(DWORD_PTR)&MappedVet,
|
|
0);
|
|
}
|
|
break;
|
|
|
|
case DVM_GET_CHANNEL_CAPS:
|
|
{
|
|
CHANNEL_CAPS Caps;
|
|
|
|
ReturnCode = videoMessage((HVIDEO)hVideo,
|
|
(UINT)msg,
|
|
(DWORD_PTR)&Caps,
|
|
dwP2);
|
|
|
|
/*
|
|
* If successful return the data to the 16-bit app
|
|
*/
|
|
|
|
if (ReturnCode == DV_ERR_OK) {
|
|
CopyTo16Bit((LPVOID)dwP1, (LPVOID)&Caps,
|
|
sizeof(Caps));
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case DVM_UPDATE:
|
|
{
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
(DWORD_PTR)ThunkHWND(dwP1),
|
|
(DWORD_PTR)ThunkHDC(dwP2));
|
|
}
|
|
break;
|
|
|
|
case DVM_PALETTE:
|
|
case DVM_PALETTERGB555:
|
|
case DVM_FORMAT:
|
|
/*
|
|
* This stuff all comes from videoConfigure
|
|
*
|
|
* Let's hope this data is all DWORDs!
|
|
*/
|
|
{
|
|
VIDEOCONFIGPARMS vcp, MappedVcp;
|
|
DWORD dwReturn;
|
|
|
|
BOOL Ok;
|
|
|
|
Ok = TRUE;
|
|
|
|
CopyTo32Bit((LPVOID)&vcp, (LPVOID)dwP2, sizeof(vcp));
|
|
MappedVcp.lpdwReturn = &dwReturn;
|
|
MappedVcp.dwSize1 = vcp.dwSize1;
|
|
MappedVcp.dwSize2 = vcp.dwSize2;
|
|
|
|
/*
|
|
* Get some storage to store the answer
|
|
*/
|
|
|
|
if (MappedVcp.dwSize1 != 0) {
|
|
MappedVcp.lpData1 = (LPSTR)LocalAlloc(LPTR, MappedVcp.dwSize1);
|
|
if (MappedVcp.lpData1 == NULL) {
|
|
Ok = FALSE;
|
|
} else {
|
|
if (MappedVcp.dwSize2 != 0) {
|
|
MappedVcp.lpData2 = (LPSTR)LocalAlloc(LPTR, MappedVcp.dwSize2);
|
|
if (MappedVcp.lpData2 == NULL) {
|
|
Ok = FALSE;
|
|
|
|
if (MappedVcp.dwSize1 != 0) {
|
|
LocalFree((HLOCAL)MappedVcp.lpData1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Ok) {
|
|
|
|
CopyTo32Bit(MappedVcp.lpData1, vcp.lpData1, MappedVcp.dwSize1);
|
|
CopyTo32Bit(MappedVcp.lpData2, vcp.lpData2, MappedVcp.dwSize2);
|
|
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
dwP1,
|
|
(DWORD_PTR)&MappedVcp);
|
|
|
|
if (ReturnCode == DV_ERR_OK) {
|
|
|
|
if (vcp.lpdwReturn != NULL) {
|
|
CopyTo16Bit(vcp.lpdwReturn, MappedVcp.lpdwReturn,
|
|
sizeof(DWORD));
|
|
}
|
|
|
|
CopyTo16Bit(vcp.lpData1, MappedVcp.lpData1, MappedVcp.dwSize1);
|
|
CopyTo16Bit(vcp.lpData2, MappedVcp.lpData2, MappedVcp.dwSize2);
|
|
}
|
|
|
|
if (MappedVcp.dwSize1 != 0) {
|
|
LocalFree((HLOCAL)MappedVcp.lpData1);
|
|
}
|
|
if (MappedVcp.dwSize2 != 0) {
|
|
LocalFree((HLOCAL)MappedVcp.lpData2);
|
|
}
|
|
} else {
|
|
ReturnCode = DV_ERR_NOMEM;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DVM_CONFIGURESTORAGE:
|
|
{
|
|
LPSTR lpStrIdent;
|
|
lpStrIdent = WOW32ResolveMemory(dwP1);
|
|
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
(DWORD_PTR)lpStrIdent,
|
|
dwP2);
|
|
|
|
}
|
|
break;
|
|
|
|
case DVM_DIALOG:
|
|
{
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
(DWORD_PTR)ThunkHWND(dwP1),
|
|
dwP2);
|
|
}
|
|
break;
|
|
|
|
case DVM_SRC_RECT:
|
|
case DVM_DST_RECT:
|
|
/*
|
|
* If it's a query only then don't bother with the
|
|
* rectangle
|
|
*/
|
|
|
|
if (dwP2 & VIDEO_CONFIGURE_QUERY) {
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
dwP1,
|
|
dwP2);
|
|
} else {
|
|
|
|
/*
|
|
* The rectangle is regarded as 'in' and 'out'
|
|
* We need to translate between 16-bit and 32-bit rectangle structures
|
|
*/
|
|
|
|
RECT_SHORT SRect;
|
|
RECT Rect;
|
|
|
|
CopyTo32Bit((LPVOID)&SRect, (LPVOID)dwP1, sizeof(SRect));
|
|
|
|
SHORT_RECT_TO_RECT(Rect, SRect);
|
|
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
(DWORD_PTR)&Rect,
|
|
dwP2);
|
|
|
|
if (ReturnCode == DV_ERR_OK) {
|
|
RECT_TO_SHORT_RECT(SRect, Rect);
|
|
CopyTo16Bit((LPVOID)dwP1, (LPVOID)&SRect, sizeof(SRect));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DVM_STREAM_PREPAREHEADER:
|
|
case DVM_STREAM_UNPREPAREHEADER:
|
|
case DVM_FRAME:
|
|
case DVM_STREAM_ADDBUFFER:
|
|
{
|
|
VIDEOHDR Hdr32;
|
|
LPBYTE pData16, pData32;
|
|
DWORD dwSize;
|
|
|
|
dwSize = (UINT)msg == DVM_FRAME ? sizeof(VIDEOHDR) :
|
|
min(dwP2, sizeof(VIDEOHDR));
|
|
|
|
CopyTo32Bit((LPVOID)&Hdr32, (LPVOID)dwP1, dwSize);
|
|
|
|
pData16 = Hdr32.lpData;
|
|
|
|
/*
|
|
* Create a mapping for the pointer
|
|
*/
|
|
|
|
pData32 = GetVdmPointer((DWORD)(DWORD_PTR)pData16, Hdr32.dwBufferLength, TRUE);
|
|
Hdr32.lpData = pData32;
|
|
|
|
if (msg == DVM_STREAM_ADDBUFFER) {
|
|
|
|
PVIDEOHDR32 pHdr32;
|
|
|
|
/*
|
|
* Allocate our callback structure and pass this
|
|
* as our header (suitably offset to the video header part).
|
|
*/
|
|
|
|
pHdr32 = (PVIDEOHDR32)LocalAlloc(LPTR, sizeof(VIDEOHDR32));
|
|
|
|
if (pHdr32 == NULL) {
|
|
ReturnCode = DV_ERR_NOMEM;
|
|
} else {
|
|
|
|
/*
|
|
* Remember the old header so we can pass it back
|
|
* and the old data pointer so we can flush it
|
|
*/
|
|
|
|
pHdr32->pHdr16 = (LPVOID)dwP1;
|
|
|
|
/*
|
|
* Some systems can't handle GetVdmPointer at interrupt
|
|
* time so get a pointer here
|
|
*/
|
|
|
|
pHdr32->pHdr32 = WOW32ResolveMemory(dwP1);
|
|
pHdr32->lpData16 = pData16;
|
|
pHdr32->videoHdr = Hdr32;
|
|
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
(DWORD_PTR)&pHdr32->videoHdr,
|
|
dwP2);
|
|
/*
|
|
* If everything was OK copy it back
|
|
*/
|
|
|
|
if (ReturnCode == DV_ERR_OK) {
|
|
Hdr32.lpData = pData16;
|
|
CopyTo16Bit((LPVOID)dwP1, (LPVOID)&Hdr32, dwSize);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Prepare/unprepare the header for 32bit
|
|
*/
|
|
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
(DWORD_PTR)&Hdr32,
|
|
dwP2);
|
|
|
|
/*
|
|
* If everything was OK copy it back
|
|
*/
|
|
|
|
if (ReturnCode == DV_ERR_OK) {
|
|
Hdr32.lpData = pData16;
|
|
CopyTo16Bit((LPVOID)dwP1, (LPVOID)&Hdr32, dwSize);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DVM_STREAM_RESET:
|
|
case DVM_STREAM_FINI:
|
|
case DVM_STREAM_STOP:
|
|
case DVM_STREAM_START:
|
|
|
|
/*
|
|
* Note that the MM_DRVM_CLOSE message will cause us to clean up our
|
|
* callback structures on DVM_STREAM_FINI.
|
|
*/
|
|
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
0,
|
|
0);
|
|
break;
|
|
|
|
case DVM_STREAM_GETPOSITION:
|
|
{
|
|
MMTIME mmTime;
|
|
MMTIME16 mmTime16;
|
|
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
(DWORD_PTR)&mmTime,
|
|
sizeof(mmTime));
|
|
|
|
if (ReturnCode == DV_ERR_OK) {
|
|
mmTime16.wType = (WORD)mmTime.wType;
|
|
CopyMemory((LPVOID)&mmTime16.u,
|
|
(LPVOID)&mmTime.u, sizeof(mmTime16.u));
|
|
|
|
CopyTo16Bit((LPVOID)dwP1, (LPVOID)&mmTime16,
|
|
min(sizeof(mmTime16), dwP2));
|
|
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case DVM_STREAM_INIT:
|
|
{
|
|
VIDEO_STREAM_INIT_PARMS vsip;
|
|
VIDEO_STREAM_INIT_PARMS16 vsip16;
|
|
PVIDEOINSTANCEDATA32 pInst32;
|
|
|
|
#if 0
|
|
// always do callback
|
|
VIDEO_STREAM_INIT_PARMS16 * pvsip = WOW32ResolveMemory(dwP1);
|
|
if (!(pvsip->dwFlags & CALLBACK_TYPEMASK)) {
|
|
// No callback wanted by the 16 bit code. Pass call
|
|
// straight through
|
|
|
|
ReturnCode = videoMessage((HVIDEO)hVideo,
|
|
(UINT)msg,
|
|
(DWORD_PTR)pvsip,
|
|
(DWORD_PTR)dwP2);
|
|
|
|
} else
|
|
#endif
|
|
{
|
|
// We set up a callback to a 32 bit routine, that in
|
|
// turn will callback to the 16 bit function/window
|
|
pInst32 = (PVIDEOINSTANCEDATA32)
|
|
LocalAlloc(LPTR, sizeof(VIDEOINSTANCEDATA32));
|
|
|
|
if (pInst32 == NULL) {
|
|
ReturnCode = DV_ERR_NOMEM;
|
|
} else {
|
|
CopyTo32Bit((LPVOID)&vsip16, (LPVOID)dwP1,
|
|
min(sizeof(vsip16), dwP2));
|
|
|
|
pInst32->dwFlags = vsip16.dwFlags;
|
|
pInst32->dwCallbackInst = vsip16.dwCallbackInst;
|
|
pInst32->dwCallback = vsip16.dwCallback;
|
|
pInst32->hVideo = (HVIDEO16)vsip16.hVideo;
|
|
|
|
/*
|
|
* Make up our own parms. Only set up a callback if
|
|
* the user wanted one
|
|
*/
|
|
|
|
vsip.dwCallback = (DWORD_PTR)MyVideoCallback;
|
|
vsip.dwFlags = (vsip.dwFlags & ~CALLBACK_TYPEMASK) |
|
|
CALLBACK_FUNCTION;
|
|
vsip.dwCallbackInst = (DWORD_PTR)pInst32;
|
|
|
|
ReturnCode = videoMessage((HVIDEO)hVideo,
|
|
(UINT)msg,
|
|
(DWORD_PTR)&vsip,
|
|
(DWORD_PTR)dwP2);
|
|
|
|
if (ReturnCode != DV_ERR_OK) {
|
|
LocalFree((HLOCAL)pInst32);
|
|
} else {
|
|
// The instance block will be freed off by the
|
|
// 32 bit callback routine when all over
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DVM_STREAM_GETERROR:
|
|
{
|
|
DWORD dwError;
|
|
DWORD dwFramesSkipped;
|
|
|
|
ReturnCode = videoMessage(hVideo,
|
|
msg,
|
|
(DWORD_PTR)&dwError,
|
|
(DWORD_PTR)&dwFramesSkipped);
|
|
|
|
if (ReturnCode == DV_ERR_OK) {
|
|
CopyTo16Bit((LPVOID)dwP1, &dwError, sizeof(DWORD));
|
|
CopyTo16Bit((LPVOID)dwP2, &dwFramesSkipped, sizeof(DWORD));
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DPF2(("videoMessage - Message not implemented %X\n", (UINT)msg));
|
|
ReturnCode = DV_ERR_NOTSUPPORTED;
|
|
|
|
}
|
|
EndThunk();
|
|
}
|
|
|
|
INLINE LRESULT FAR PASCAL videoGetNumDevs32(void)
|
|
{
|
|
StartThunk(videoGetNumDevs);
|
|
ReturnCode = videoGetNumDevs();
|
|
EndThunk();
|
|
}
|
|
|
|
LRESULT FAR PASCAL videoClose32(HVIDEO hVideo)
|
|
{
|
|
StartThunk(videoClose)
|
|
ReturnCode = videoClose(hVideo);
|
|
EndThunk();
|
|
}
|
|
|
|
LRESULT FAR PASCAL videoOpen32(LPHVIDEO lphVideo, DWORD dwDeviceID, DWORD dwFlags)
|
|
{
|
|
HVIDEO hVideo;
|
|
StartThunk(videoOpen);
|
|
|
|
ReturnCode = videoOpen(
|
|
&hVideo,
|
|
dwDeviceID,
|
|
dwFlags);
|
|
|
|
if (ReturnCode == DV_ERR_OK) {
|
|
lphVideo = WOW32ResolveMemory((PVOID)lphVideo);
|
|
* (HVIDEO UNALIGNED *)lphVideo = hVideo;
|
|
}
|
|
EndThunk();
|
|
}
|
|
|
|
|