4 #define _CRT_SECURE_NO_WARNINGS
6 #include "lobbyclient.h"
10 #include <QMutexLocker>
11 #include <QScopedPointer>
12 #include <QStringList>
25 namespace swift::simplugin::fs9
27 CLobbyClient::CLobbyClient(QObject *parent)
28 : QObject(parent), m_callbackWrapper(this, &
CLobbyClient::directPlayMessageHandler),
29 m_lobbyCallbackWrapper(this, &
CLobbyClient::directPlayLobbyMessageHandler)
31 Q_ASSERT_X(
sApp, Q_FUNC_INFO,
"Missing global object");
39 m_directPlayPeer->Close(DPNCLOSE_IMMEDIATE);
40 m_directPlayPeer->Release();
48 m_dpLobbyClient->ReleaseApplication(DPLHANDLE_ALLCONNECTIONS, 0);
49 m_dpLobbyClient->Close(0);
60 if (FAILED(hr = CoCreateInstance(CLSID_DirectPlay8Peer,
nullptr, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Peer,
61 (LPVOID *)&m_directPlayPeer)))
62 return logDirectPlayError(hr);
65 const DWORD dwInitFlags = 0;
69 m_directPlayPeer->Initialize(&m_callbackWrapper, m_callbackWrapper.
messageHandler, dwInitFlags)))
70 return logDirectPlayError(hr);
73 if (FAILED(hr = CoCreateInstance(CLSID_DirectPlay8LobbyClient,
nullptr, CLSCTX_INPROC_SERVER,
74 IID_IDirectPlay8LobbyClient, (LPVOID *)&m_dpLobbyClient)))
75 return logDirectPlayError(hr);
77 if (FAILED(hr = m_dpLobbyClient->Initialize(&m_lobbyCallbackWrapper, m_lobbyCallbackWrapper.
messageHandler,
79 return logDirectPlayError(hr);
86 if (!m_dpLobbyClient) {
return false; }
90 const HRESULT hr = m_dpLobbyClient->EnumLocalPrograms(&appGuid,
nullptr, &dwSize, &dwItems, 0);
91 if (hr == DPNERR_BUFFERTOOSMALL)
93 QScopedArrayPointer<BYTE> memPtr(
new BYTE[dwSize]);
94 DPL_APPLICATION_INFO *appInfo =
reinterpret_cast<DPL_APPLICATION_INFO *
>(memPtr.data());
96 m_dpLobbyClient->EnumLocalPrograms(&appGuid, memPtr.data(), &dwSize, &dwItems, 0);
101 <<
"Found lobby application:" << QString::fromWCharArray(appInfo->pwszApplicationName);
104 else {
return false; }
106 else {
return false; }
116 DPL_CONNECT_INFO dnConnectInfo;
117 ZeroMemory(&dnConnectInfo,
sizeof(DPL_CONNECT_INFO));
118 dnConnectInfo.dwSize =
sizeof(DPL_CONNECT_INFO);
119 dnConnectInfo.pvLobbyConnectData =
nullptr;
120 dnConnectInfo.dwLobbyConnectDataSize = 0;
121 dnConnectInfo.dwFlags = 0;
122 dnConnectInfo.guidApplication = pAppGuid;
124 if (FAILED(hr = allocAndInitConnectSettings(address, &pAppGuid, &dnConnectInfo.pdplConnectionSettings)))
129 hr = m_dpLobbyClient->ConnectApplication(&dnConnectInfo,
nullptr, &m_applicationHandle, INFINITE, 0);
130 if (FAILED(hr)) {
return hr; }
133 freeConnectSettings(dnConnectInfo.pdplConnectionSettings);
137 HRESULT CLobbyClient::allocAndInitConnectSettings(
const QString &address, GUID *pAppGuid,
138 DPL_CONNECTION_SETTINGS **ppdplConnectSettings)
142 IDirectPlay8Address *pHostAddress =
nullptr;
143 IDirectPlay8Address *pDeviceAddress =
nullptr;
145 QScopedPointer<GUID> pSPGuid(
new GUID);
146 memcpy(pSPGuid.data(), &CLSID_DP8SP_TCPIP,
sizeof(GUID));
149 if (FAILED(hr = CoCreateInstance(CLSID_DirectPlay8Address,
nullptr, CLSCTX_INPROC_SERVER,
150 IID_IDirectPlay8Address,
reinterpret_cast<void **
>(&pHostAddress))))
152 return logDirectPlayError(hr);
156 if (FAILED(hr = pHostAddress->SetSP(pSPGuid.data()))) {
return logDirectPlayError(hr); }
159 if (FAILED(hr = CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address,
160 reinterpret_cast<void **
>(&pDeviceAddress))))
162 return logDirectPlayError(hr);
166 if (FAILED(hr = pDeviceAddress->SetSP(&CLSID_DP8SP_TCPIP))) {
return logDirectPlayError(hr); }
168 if (FAILED(hr = pHostAddress->BuildFromURLA(address.toLocal8Bit().data()))) {
return logDirectPlayError(hr); }
171 DPL_CONNECTION_SETTINGS *pSettings =
new DPL_CONNECTION_SETTINGS;
176 IDirectPlay8Address **apDevAddress =
new IDirectPlay8Address *[1];
179 apDevAddress[0] = pDeviceAddress;
182 QScopedArrayPointer<wchar_t> wstrSessionName(
new wchar_t[session.size() + 1]);
183 session.toWCharArray(wstrSessionName.data());
184 wstrSessionName[session.size()] = 0;
187 ZeroMemory(pSettings,
sizeof(DPL_CONNECTION_SETTINGS));
188 pSettings->dwSize =
sizeof(DPL_CONNECTION_SETTINGS);
189 pSettings->dpnAppDesc.dwSize =
sizeof(DPN_APPLICATION_DESC);
190 pSettings->dwFlags = 0;
191 pSettings->dpnAppDesc.guidApplication = *pAppGuid;
192 pSettings->dpnAppDesc.guidInstance = GUID_NULL;
193 pSettings->dpnAppDesc.dwFlags = DPNSESSION_NODPNSVR;
194 pSettings->pdp8HostAddress = pHostAddress;
195 pSettings->ppdp8DeviceAddresses = apDevAddress;
196 pSettings->cNumDeviceAddresses = 1;
197 pSettings->dpnAppDesc.pwszSessionName =
new WCHAR[wcslen(wstrSessionName.data()) + 1];
198 wcscpy(pSettings->dpnAppDesc.pwszSessionName, wstrSessionName.data());
201 QString playerName(
"Player");
202 WCHAR wstrPlayerName[m_maxSizePlayerName];
203 playerName.toWCharArray(wstrPlayerName);
204 wstrPlayerName[playerName.size()] = 0;
205 pSettings->pwszPlayerName =
new WCHAR[wcslen(wstrPlayerName) + 1];
206 wcscpy(pSettings->pwszPlayerName, wstrPlayerName);
208 *ppdplConnectSettings = pSettings;
213 void CLobbyClient::freeConnectSettings(DPL_CONNECTION_SETTINGS *pSettings)
215 if (!pSettings)
return;
232 HRESULT CLobbyClient::directPlayMessageHandler(
DWORD ,
void * ) {
return S_OK; }
234 HRESULT CLobbyClient::directPlayLobbyMessageHandler(
DWORD messageId,
void *msgBuffer)
238 case DPL_MSGID_DISCONNECT:
240 PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
241 pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)msgBuffer;
242 Q_UNUSED(pDisconnectMsg)
251 case DPL_MSGID_RECEIVE:
253 PDPL_MESSAGE_RECEIVE pReceiveMsg;
254 pReceiveMsg = (PDPL_MESSAGE_RECEIVE)msgBuffer;
255 Q_UNUSED(pReceiveMsg)
263 case DPL_MSGID_SESSION_STATUS:
265 PDPL_MESSAGE_SESSION_STATUS pStatusMsg;
266 pStatusMsg = (PDPL_MESSAGE_SESSION_STATUS)msgBuffer;
269 message.append(QString(
"%1: ").arg(pStatusMsg->hSender, 0, 16));
270 switch (pStatusMsg->dwStatus)
272 case DPLSESSION_CONNECTED: message.append(
"Session connected");
break;
273 case DPLSESSION_COULDNOTCONNECT: message.append(
"Session could not connect");
break;
274 case DPLSESSION_DISCONNECTED: message.append(
"Session disconnected");
break;
275 case DPLSESSION_TERMINATED: message.append(
"Session terminated");
break;
276 case DPLSESSION_HOSTMIGRATED: message.append(
"Host migrated");
break;
277 case DPLSESSION_HOSTMIGRATEDHERE: message.append(
"Host migrated to this client");
break;
279 message.append(QStringLiteral(
"Unknown PDPL_MESSAGE_SESSION_STATUS: %1").arg(pStatusMsg->dwStatus));
287 case DPL_MSGID_CONNECTION_SETTINGS:
289 PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
290 pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)msgBuffer;
291 Q_UNUSED(pConnectionStatusMsg)
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
const QString & swiftVersionString() const
swift info string
Class for emitting a log message.
Derived & debug()
Set the severity to debug.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
static GUID guid()
Get FS9 application GUID.
Lobby client launching and connecting FS9.
HRESULT initDirectPlay()
Initialize DirectPlay.
void disconnected()
Emitted when FS9 is closed.
virtual ~CLobbyClient()
Destructor.
HRESULT connectFs9ToHost(const QString &address)
Connect FS9 simulator to our host.
bool canLobbyConnect()
Can FS9 be lobby connected?
void SafeDeleteArray(T *&pT)
Safely delete an allocated array.
void SafeRelease(T *&pT)
Safely release a COM allocated object.
void SafeDelete(T *&pT)
Safely delete an allocated pointer.
Free functions in swift::misc.
unsigned long DWORD
Fake Windows DWORD.
static ReturnType WINAPI messageHandler(void *userContext, Argument1 arg1, Argument2 arg2)
FS9 message handler callback.