Skip to content

Commit

Permalink
Generic fix for Star Trek Armada 1
Browse files Browse the repository at this point in the history
Hook window message to get notified when the window is about to exit to
remove the exclusive flag.
Fixes a bug in ddraw in Windows 8 and 10 where the exclusive flag
remains even after the window (hWnd) closes.
  • Loading branch information
elishacloud committed Apr 28, 2018
1 parent 5275bf3 commit ce945be
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Dllmain/BuildNo.rc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#define BUILD_NUMBER 4258
#define BUILD_NUMBER 4390
43 changes: 40 additions & 3 deletions ddraw/IDirectDrawX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include "ddraw.h"
std::unordered_map<HWND, IDirectDraw7*> g_hookmap;

HRESULT m_IDirectDrawX::QueryInterface(REFIID riid, LPVOID FAR * ppvObj)
{
Expand Down Expand Up @@ -238,12 +239,48 @@ HRESULT m_IDirectDrawX::RestoreDisplayMode()
return ProxyInterface->RestoreDisplayMode();
}

// Fixes a bug in ddraw in Windows 8 and 10 where the exclusive flag remains even after the window (hWnd) closes
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);

if (nCode == HCBT_DESTROYWND)
{
HWND hWnd = (HWND)wParam;
IDirectDraw7 *Interface = (IDirectDraw7*)InterlockedExchangePointer((PVOID*)&CurrentDDInterface, nullptr);
if (Interface && Interface == g_hookmap[hWnd])
{
Interface->SetCooperativeLevel(hWnd, DDSCL_NORMAL);
}
g_hookmap.erase(hWnd);
}

return NULL;
}

HRESULT m_IDirectDrawX::SetCooperativeLevel(HWND hWnd, DWORD dwFlags)
{
// Set ModeEx to fix issues with some games like Star Trek Armada 1 & 2
if (IsDDrawCreateEx && (dwFlags & DDSCL_EXCLUSIVE) && !(dwFlags & DDSCL_ALLOWMODEX))
// Release previouse Exclusive flag
// Hook window message to get notified when the window is about to exit to remove the exclusive flag
if (dwFlags & DDSCL_EXCLUSIVE && hWnd != chWnd)
{
dwFlags |= DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN;
if (IsWindow(chWnd))
{
ProxyInterface->SetCooperativeLevel(chWnd, DDSCL_NORMAL);
}
else
{
if (g_hook)
{
UnhookWindowsHookEx(g_hook);
g_hook = nullptr;
}

g_hookmap[hWnd] = ProxyInterface;
g_hook = SetWindowsHookEx(WH_CBT, CBTProc, NULL, GetWindowThreadProcessId(hWnd, nullptr));
}

chWnd = hWnd;
}

return ProxyInterface->SetCooperativeLevel(hWnd, dwFlags);
Expand Down
17 changes: 14 additions & 3 deletions ddraw/IDirectDrawX.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class m_IDirectDrawX
DWORD DirectXVersion;
DWORD ProxyDirectXVersion;
IID WrapperID;
bool IsDDrawCreateEx = false;
HHOOK g_hook = nullptr;
HWND chWnd = nullptr;

public:
m_IDirectDrawX(IDirectDraw7 *aOriginal, DWORD Version, m_IDirectDraw7 *Interface) : ProxyInterface(aOriginal), DirectXVersion(Version), WrapperInterface(Interface)
Expand All @@ -26,18 +27,28 @@ class m_IDirectDrawX
(ProxyID == IID_IDirectDraw4) ? 4 :
(ProxyID == IID_IDirectDraw7) ? 7 : 7;

InterlockedExchangePointer((PVOID*)&CurrentDDInterface, ProxyInterface);

if (ProxyDirectXVersion != DirectXVersion)
{
Logging::LogDebug() << "Convert DirectDraw v" << DirectXVersion << " to v" << ProxyDirectXVersion;
}
}
~m_IDirectDrawX() {}
~m_IDirectDrawX()
{
PVOID MyNull = nullptr;
InterlockedExchangePointer((PVOID*)&CurrentDDInterface, MyNull);

if (g_hook)
{
UnhookWindowsHookEx(g_hook);
}
}

DWORD GetDirectXVersion() { return DDWRAPPER_TYPEX; }
REFIID GetWrapperType() { return WrapperID; }
IDirectDraw7 *GetProxyInterface() { return ProxyInterface; }
m_IDirectDraw7 *GetWrapperInterface() { return WrapperInterface; }
void SetDDrawCreateExFlag() { IsDDrawCreateEx = true; }

/*** IUnknown methods ***/
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj);
Expand Down
3 changes: 1 addition & 2 deletions ddraw/ddraw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

AddressLookupTableDdraw<void> ProxyAddressLookupTable = AddressLookupTableDdraw<void>();
m_IDirect3DDeviceX *lpCurrentD3DDevice = nullptr;
IDirectDraw7 *CurrentDDInterface = nullptr;

#define INITUALIZE_WRAPPED_PROC(procName, unused) \
FARPROC procName ## _out = (FARPROC)*(ddraw::procName);
Expand Down Expand Up @@ -167,8 +168,6 @@ HRESULT WINAPI dd_DirectDrawCreateEx(GUID FAR *lpGUID, LPVOID *lplpDD, REFIID ri
if (SUCCEEDED(hr))
{
genericQueryInterface(riid, lplpDD);

((m_IDirectDrawX*)*lplpDD)->SetDDrawCreateExFlag();
}

return hr;
Expand Down
1 change: 1 addition & 0 deletions ddraw/ddraw.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ REFIID ConvertREFIID(REFIID riid);
HRESULT ProxyQueryInterface(LPVOID ProxyInterface, REFIID CalledID, LPVOID * ppvObj, REFIID CallerID, LPVOID WrapperInterface);
void genericQueryInterface(REFIID riid, LPVOID * ppvObj);
extern AddressLookupTableDdraw<void> ProxyAddressLookupTable;
extern IDirectDraw7 *CurrentDDInterface;
extern m_IDirect3DDeviceX *lpCurrentD3DDevice;

// Direct3D
Expand Down

0 comments on commit ce945be

Please sign in to comment.