|  | /*		DirectDraw Base Functions | 
|  | * | 
|  | * Copyright 1997-1999 Marcus Meissner | 
|  | * Copyright 1998 Lionel Ulmer (most of Direct3D stuff) | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include <unistd.h> | 
|  | #include <assert.h> | 
|  | #include <fcntl.h> | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include "winerror.h" | 
|  | #include "heap.h" | 
|  | #include "dc.h" | 
|  | #include "win.h" | 
|  | #include "wine/exception.h" | 
|  | #include "ddraw.h" | 
|  | #include "d3d.h" | 
|  | #include "debugtools.h" | 
|  | #include "message.h" | 
|  | #include "monitor.h" | 
|  |  | 
|  | /* This for all the enumeration and creation of D3D-related objects */ | 
|  | #include "ddraw_private.h" | 
|  |  | 
|  | #define MAX_DDRAW_DRIVERS	3 | 
|  | static ddraw_driver * ddraw_drivers[MAX_DDRAW_DRIVERS]; | 
|  | static int nrof_ddraw_drivers			= 0; | 
|  |  | 
|  | DEFAULT_DEBUG_CHANNEL(ddraw); | 
|  |  | 
|  | /* register a direct draw driver. We better not use malloc for we are in | 
|  | * the ELF startup initialisation at this point. | 
|  | */ | 
|  | void ddraw_register_driver(ddraw_driver *driver) { | 
|  | ddraw_drivers[nrof_ddraw_drivers++] = driver; | 
|  |  | 
|  | /* increase MAX_DDRAW_DRIVERS if the line below triggers */ | 
|  | assert(nrof_ddraw_drivers <= MAX_DDRAW_DRIVERS); | 
|  | } | 
|  |  | 
|  | /**********************************************************************/ | 
|  |  | 
|  | typedef struct { | 
|  | LPVOID lpCallback; | 
|  | LPVOID lpContext; | 
|  | } DirectDrawEnumerateProcData; | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		DirectDrawEnumerateExA (DDRAW.*) | 
|  | */ | 
|  | HRESULT WINAPI DirectDrawEnumerateExA( | 
|  | LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags) | 
|  | { | 
|  | int i; | 
|  | TRACE("(%p,%p, %08lx)\n", lpCallback, lpContext, dwFlags); | 
|  |  | 
|  | if (TRACE_ON(ddraw)) { | 
|  | DPRINTF("  Flags : "); | 
|  | if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES) | 
|  | DPRINTF("DDENUM_ATTACHEDSECONDARYDEVICES "); | 
|  | if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) | 
|  | DPRINTF("DDENUM_DETACHEDSECONDARYDEVICES "); | 
|  | if (dwFlags & DDENUM_NONDISPLAYDEVICES) | 
|  | DPRINTF("DDENUM_NONDISPLAYDEVICES "); | 
|  | DPRINTF("\n"); | 
|  | } | 
|  |  | 
|  | /* Invoke callback for what flags we do support */ | 
|  | for (i=0;i<MAX_DDRAW_DRIVERS;i++) { | 
|  | if (!ddraw_drivers[i]) | 
|  | continue; | 
|  | if (ddraw_drivers[i]->createDDRAW(NULL)) /* !0 is failing */ | 
|  | continue; | 
|  | TRACE("Enumerating %s/%s interface\n",ddraw_drivers[i]->name,ddraw_drivers[i]->type); | 
|  | if (!lpCallback( | 
|  | ddraw_drivers[i]->guid, | 
|  | (LPSTR)ddraw_drivers[i]->name, | 
|  | (LPSTR)ddraw_drivers[i]->type, | 
|  | lpContext, | 
|  | 0		/* FIXME: flags not supported here */ | 
|  | )) | 
|  | return DD_OK; | 
|  | } | 
|  | if (nrof_ddraw_drivers) { | 
|  | TRACE("Enumerating the default interface\n"); | 
|  | if (!lpCallback(NULL,"WINE (default)", "display", lpContext, 0)) | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /* Unsupported flags */ | 
|  | if (dwFlags & DDENUM_NONDISPLAYDEVICES) { | 
|  | FIXME("no non-display devices supported.\n"); | 
|  | } | 
|  | /* Hmm. Leave this out. | 
|  | if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES) { | 
|  | FIXME("no attached secondary devices supported.\n"); | 
|  | } | 
|  | */ | 
|  | if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) { | 
|  | FIXME("no detached secondary devices supported.\n"); | 
|  | } | 
|  |  | 
|  | return DD_OK; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		DirectDrawEnumerateExW (DDRAW.*) | 
|  | */ | 
|  |  | 
|  | static BOOL CALLBACK DirectDrawEnumerateExProcW( | 
|  | GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, | 
|  | LPVOID lpContext, HMONITOR hm) | 
|  | { | 
|  | DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext; | 
|  | LPWSTR lpDriverDescriptionW = | 
|  | HEAP_strdupAtoW(GetProcessHeap(), 0, lpDriverDescription); | 
|  | LPWSTR lpDriverNameW = | 
|  | HEAP_strdupAtoW(GetProcessHeap(), 0, lpDriverName); | 
|  |  | 
|  | BOOL bResult = (*(LPDDENUMCALLBACKEXW *) pEPD->lpCallback)( | 
|  | lpGUID, lpDriverDescriptionW, lpDriverNameW, pEPD->lpContext, hm); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, lpDriverDescriptionW); | 
|  | HeapFree(GetProcessHeap(), 0, lpDriverNameW); | 
|  | return bResult; | 
|  | } | 
|  |  | 
|  | /**********************************************************************/ | 
|  |  | 
|  | HRESULT WINAPI DirectDrawEnumerateExW( | 
|  | LPDDENUMCALLBACKEXW lpCallback, LPVOID lpContext, DWORD dwFlags) | 
|  | { | 
|  | DirectDrawEnumerateProcData epd; | 
|  | epd.lpCallback = (LPVOID) lpCallback; | 
|  | epd.lpContext = lpContext; | 
|  |  | 
|  | return DirectDrawEnumerateExA(DirectDrawEnumerateExProcW, (LPVOID) &epd, 0); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		DirectDrawEnumerateA (DDRAW.*) | 
|  | */ | 
|  |  | 
|  | static BOOL CALLBACK DirectDrawEnumerateProcA( | 
|  | GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, | 
|  | LPVOID lpContext, HMONITOR hm) | 
|  | { | 
|  | DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext; | 
|  |  | 
|  | return ((LPDDENUMCALLBACKA) pEPD->lpCallback)( | 
|  | lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext); | 
|  | } | 
|  |  | 
|  | /**********************************************************************/ | 
|  |  | 
|  | HRESULT WINAPI DirectDrawEnumerateA( | 
|  | LPDDENUMCALLBACKA lpCallback, LPVOID lpContext) | 
|  | { | 
|  | DirectDrawEnumerateProcData epd; | 
|  | epd.lpCallback = (LPVOID) lpCallback; | 
|  | epd.lpContext = lpContext; | 
|  |  | 
|  | return DirectDrawEnumerateExA(DirectDrawEnumerateProcA, (LPVOID) &epd, 0); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		DirectDrawEnumerateW (DDRAW.*) | 
|  | */ | 
|  |  | 
|  | static BOOL WINAPI DirectDrawEnumerateProcW( | 
|  | GUID *lpGUID, LPWSTR lpDriverDescription, LPWSTR lpDriverName, | 
|  | LPVOID lpContext, HMONITOR hm) | 
|  | { | 
|  | DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext; | 
|  |  | 
|  | return ((LPDDENUMCALLBACKW) pEPD->lpCallback)( | 
|  | lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext); | 
|  | } | 
|  |  | 
|  | /**********************************************************************/ | 
|  |  | 
|  | HRESULT WINAPI DirectDrawEnumerateW( | 
|  | LPDDENUMCALLBACKW lpCallback, LPVOID lpContext) | 
|  | { | 
|  | DirectDrawEnumerateProcData epd; | 
|  | epd.lpCallback = (LPVOID) lpCallback; | 
|  | epd.lpContext = lpContext; | 
|  |  | 
|  | return DirectDrawEnumerateExW(DirectDrawEnumerateProcW, (LPVOID) &epd, 0); | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * 				DirectDraw Window Procedure | 
|  | */ | 
|  | static LRESULT WINAPI DDWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) | 
|  | { | 
|  | LRESULT ret; | 
|  | IDirectDrawImpl* ddraw = NULL; | 
|  | DWORD lastError; | 
|  |  | 
|  | /* FIXME(ddraw,"(0x%04x,%s,0x%08lx,0x%08lx),stub!\n",(int)hwnd,SPY_GetMsgName(msg),(long)wParam,(long)lParam); */ | 
|  |  | 
|  | SetLastError( ERROR_SUCCESS ); | 
|  | ddraw  = (IDirectDrawImpl*)GetPropA( hwnd, ddProp ); | 
|  | if( (!ddraw)  && ( ( lastError = GetLastError() ) != ERROR_SUCCESS )) | 
|  | ERR("Unable to retrieve this ptr from window. Error %08lx\n",lastError); | 
|  |  | 
|  | if( ddraw ) { | 
|  | /* Perform any special direct draw functions */ | 
|  | if (msg==WM_PAINT) | 
|  | ddraw->d.paintable = 1; | 
|  |  | 
|  | /* Now let the application deal with the rest of this */ | 
|  | if( ddraw->d.mainWindow ) { | 
|  |  | 
|  | /* Don't think that we actually need to call this but... | 
|  | * might as well be on the safe side of things... | 
|  | */ | 
|  |  | 
|  | /* I changed hwnd to ddraw->d.mainWindow as I did not see why | 
|  | * it should be the procedures of our fake window that gets called | 
|  | * instead of those of the window provided by the application. | 
|  | * And with this patch, mouse clicks work with Monkey Island III | 
|  | * - Lionel | 
|  | */ | 
|  | ret = DefWindowProcA( ddraw->d.mainWindow, msg, wParam, lParam ); | 
|  |  | 
|  | if( !ret ) { | 
|  | WND *tmpWnd =WIN_FindWndPtr(ddraw->d.mainWindow); | 
|  | /* We didn't handle the message - give it to the application */ | 
|  | if (ddraw && ddraw->d.mainWindow && tmpWnd) | 
|  | ret = CallWindowProcA(tmpWnd->winproc, | 
|  | ddraw->d.mainWindow, msg, wParam, lParam ); | 
|  | WIN_ReleaseWndPtr(tmpWnd); | 
|  | } | 
|  | return ret; | 
|  | } /* else FALLTHROUGH */ | 
|  | } /* else FALLTHROUGH */ | 
|  | return DefWindowProcA(hwnd,msg,wParam,lParam); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		DirectDrawCreate | 
|  | */ | 
|  | HRESULT WINAPI DirectDrawCreate( | 
|  | LPGUID lpGUID, LPDIRECTDRAW *lplpDD, LPUNKNOWN pUnkOuter | 
|  | ) { | 
|  | IDirectDrawImpl** ilplpDD=(IDirectDrawImpl**)lplpDD; | 
|  | WNDCLASSA	wc; | 
|  | HRESULT	ret = 0; | 
|  | int		i,drvindex=0; | 
|  | GUID	zeroGUID; | 
|  |  | 
|  | struct ddraw_driver	*ddd = NULL; | 
|  |  | 
|  | if (!HIWORD(lpGUID)) lpGUID = NULL; | 
|  |  | 
|  | TRACE("(%s,%p,%p)\n",debugstr_guid(lpGUID),ilplpDD,pUnkOuter); | 
|  |  | 
|  | memset(&zeroGUID,0,sizeof(zeroGUID)); | 
|  | while (1) { | 
|  | ddd = NULL; | 
|  | if ( ( !lpGUID ) || | 
|  | ( IsEqualGUID( &zeroGUID,  lpGUID ) ) || | 
|  | ( IsEqualGUID( &IID_IDirectDraw,  lpGUID ) ) || | 
|  | ( IsEqualGUID( &IID_IDirectDraw2, lpGUID ) ) || | 
|  | ( IsEqualGUID( &IID_IDirectDraw4, lpGUID ) ) || | 
|  | ( IsEqualGUID( &IID_IDirectDraw7, lpGUID ) ) | 
|  | ) { | 
|  | /* choose an interface out of the list */ | 
|  | for (i=0;i<nrof_ddraw_drivers;i++) { | 
|  | ddraw_driver *xddd = ddraw_drivers[i]; | 
|  | if (!xddd) | 
|  | continue; | 
|  | if (!ddd || (ddd->preference<xddd->preference)) { | 
|  | drvindex = i; | 
|  | ddd = xddd; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | for (i=0;i<nrof_ddraw_drivers;i++) { | 
|  | if (!ddraw_drivers[i]) | 
|  | continue; | 
|  | if (IsEqualGUID(ddraw_drivers[i]->guid,lpGUID)) { | 
|  | drvindex = i; | 
|  | ddd = ddraw_drivers[i]; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (!ddd) { | 
|  | if (!nrof_ddraw_drivers) { | 
|  | ERR("DirectDrawCreate(%s,%p,%p): no DirectDraw drivers compiled in.\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter); | 
|  | return DDERR_NODIRECTDRAWHW; | 
|  | } | 
|  | ERR("DirectDrawCreate(%s,%p,%p): did not recognize requested GUID.\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter); | 
|  | return DDERR_INVALIDDIRECTDRAWGUID; | 
|  | } | 
|  | TRACE("using \"%s\" driver, calling %p\n",ddd->name,ddd->createDDRAW); | 
|  |  | 
|  | ret = ddd->createDDRAW(lplpDD); | 
|  | if (!ret) | 
|  | break; | 
|  | ddraw_drivers[drvindex] = NULL; /* mark this one as unusable */ | 
|  | } | 
|  | wc.style		= CS_GLOBALCLASS; | 
|  | wc.lpfnWndProc	= DDWndProc; | 
|  | wc.cbClsExtra	= 0; | 
|  | wc.cbWndExtra	= 0; | 
|  |  | 
|  | /* We can be a child of the desktop since we're really important */ | 
|  | wc.hInstance= 0; | 
|  | wc.hIcon	= 0; | 
|  | wc.hCursor	= (HCURSOR)IDC_ARROWA; | 
|  | wc.hbrBackground	= NULL_BRUSH; | 
|  | wc.lpszMenuName 	= 0; | 
|  | wc.lpszClassName	= "WINE_DirectDraw"; | 
|  | (*ilplpDD)->d.winclass = RegisterClassA(&wc); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		DirectDrawCreateEx | 
|  | */ | 
|  | HRESULT WINAPI DirectDrawCreateEx( | 
|  | LPGUID lpGUID, LPVOID* lplpDD, REFIID iid, LPUNKNOWN pUnkOuter | 
|  | ) { | 
|  | FIXME(":semi stub\n"); | 
|  | /* I don't know about what functionality is unique to Ex */ | 
|  | return DirectDrawCreate(lpGUID,(LPDIRECTDRAW*)lplpDD,pUnkOuter); | 
|  | } | 
|  |  | 
|  | /******************************************************************************* | 
|  | * DirectDraw ClassFactory | 
|  | * | 
|  | *  Heavily inspired (well, can you say completely copied :-) ) from DirectSound | 
|  | * | 
|  | */ | 
|  | typedef struct { | 
|  | /* IUnknown fields */ | 
|  | ICOM_VFIELD(IClassFactory); | 
|  | DWORD		ref; | 
|  | } IClassFactoryImpl; | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | DDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { | 
|  | ICOM_THIS(IClassFactoryImpl,iface); | 
|  |  | 
|  | FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI | 
|  | DDCF_AddRef(LPCLASSFACTORY iface) { | 
|  | ICOM_THIS(IClassFactoryImpl,iface); | 
|  | return ++(This->ref); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface) { | 
|  | ICOM_THIS(IClassFactoryImpl,iface); | 
|  | /* static class, won't be  freed */ | 
|  | return --(This->ref); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DDCF_CreateInstance( | 
|  | LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj | 
|  | ) { | 
|  | ICOM_THIS(IClassFactoryImpl,iface); | 
|  |  | 
|  | TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); | 
|  | if ( ( IsEqualGUID( &IID_IDirectDraw,  riid ) ) || | 
|  | ( IsEqualGUID( &IID_IDirectDraw2, riid ) ) || | 
|  | ( IsEqualGUID( &IID_IDirectDraw4, riid ) ) ) { | 
|  | /* FIXME: reuse already created DirectDraw if present? */ | 
|  | return DirectDrawCreate((LPGUID) riid,(LPDIRECTDRAW*)ppobj,pOuter); | 
|  | } | 
|  | return CLASS_E_CLASSNOTAVAILABLE; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { | 
|  | ICOM_THIS(IClassFactoryImpl,iface); | 
|  | FIXME("(%p)->(%d),stub!\n",This,dolock); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static ICOM_VTABLE(IClassFactory) DDCF_Vtbl = | 
|  | { | 
|  | ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE | 
|  | DDCF_QueryInterface, | 
|  | DDCF_AddRef, | 
|  | DDCF_Release, | 
|  | DDCF_CreateInstance, | 
|  | DDCF_LockServer | 
|  | }; | 
|  | static IClassFactoryImpl DDRAW_CF = {&DDCF_Vtbl, 1 }; | 
|  |  | 
|  | /******************************************************************************* | 
|  | * DllGetClassObject [DDRAW.13] | 
|  | * Retrieves class object from a DLL object | 
|  | * | 
|  | * NOTES | 
|  | *    Docs say returns STDAPI | 
|  | * | 
|  | * PARAMS | 
|  | *    rclsid [I] CLSID for the class object | 
|  | *    riid   [I] Reference to identifier of interface for class object | 
|  | *    ppv    [O] Address of variable to receive interface pointer for riid | 
|  | * | 
|  | * RETURNS | 
|  | *    Success: S_OK | 
|  | *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, | 
|  | *             E_UNEXPECTED | 
|  | */ | 
|  | DWORD WINAPI DDRAW_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv) | 
|  | { | 
|  | TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); | 
|  | if ( IsEqualGUID( &IID_IClassFactory, riid ) ) { | 
|  | *ppv = (LPVOID)&DDRAW_CF; | 
|  | IClassFactory_AddRef((IClassFactory*)*ppv); | 
|  | return S_OK; | 
|  | } | 
|  | FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); | 
|  | return CLASS_E_CLASSNOTAVAILABLE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /******************************************************************************* | 
|  | * DllCanUnloadNow [DDRAW.12]  Determines whether the DLL is in use. | 
|  | * | 
|  | * RETURNS | 
|  | *    Success: S_OK | 
|  | *    Failure: S_FALSE | 
|  | */ | 
|  | DWORD WINAPI DDRAW_DllCanUnloadNow(void) { | 
|  | FIXME("(void): stub\n"); | 
|  | return S_FALSE; | 
|  | } |