/* DirectDraw Base Functions * * Copyright 1997-1999 Marcus Meissner * Copyright 1998 Lionel Ulmer (most of Direct3D stuff) */ #include "config.h" #include #include #include #include #include #include #include "winerror.h" #include "heap.h" #include "wine/exception.h" #include "debugtools.h" #include "initguid.h" #include "ddraw.h" #include "d3d.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; GUID zeroGUID; 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"); } if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES) { FIXME("no attached secondary devices supported.\n"); /*return E_FAIL;*/ } memset(&zeroGUID,0,sizeof(zeroGUID)); /* we have at least one DDRAW driver */ if (ddraw_drivers[0]) { if (!lpCallback( &zeroGUID, /* FIXME: or NULL? -MM */ "WINE DirectDraw", "display", lpContext, 0 /* FIXME: flags not supported here */ )) return DD_OK; } /* Invoke callback for what flags we do support */ for (i=0;icreateDDRAW(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"); } 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 ) { /* We didn't handle the message - give it to the application */ if (ddraw && ddraw->d->mainWindow) { WNDPROC winproc = (WNDPROC)GetWindowLongA( ddraw->d->mainWindow, GWL_WNDPROC ); ret = CallWindowProcA(winproc, ddraw->d->mainWindow, msg, wParam, lParam ); } } 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;ipreferencepreference)) { drvindex = i; ddd = xddd; } } } else { for (i=0;iguid,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 ) { LPDIRECTDRAW ddraw; HRESULT hres; FIXME("(%p,%p,%s,%p), might be wrong.\n",lpGUID,lplpDD,debugstr_guid(iid),pUnkOuter); hres=DirectDrawCreate(lpGUID,(LPDIRECTDRAW*)&ddraw,pUnkOuter); if (!hres) { hres=IDirectDraw_QueryInterface(ddraw,iid,lplpDD); IDirectDraw_Release(ddraw); } return hres; } /******************************************************************************* * 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; }