mirror of https://github.com/PCSX2/pcsx2.git
IPC: original socket ipc implementation
This commit is contained in:
parent
c422aa00aa
commit
86757fd36f
|
@ -75,6 +75,7 @@ set(pcsx2Sources
|
|||
IopIrq.cpp
|
||||
IopMem.cpp
|
||||
IopSio2.cpp
|
||||
IPC.cpp
|
||||
Mdec.cpp
|
||||
Memory.cpp
|
||||
MMI.cpp
|
||||
|
@ -147,6 +148,7 @@ set(pcsx2Headers
|
|||
IopHw.h
|
||||
IopMem.h
|
||||
IopSio2.h
|
||||
IPC.h
|
||||
Mdec.h
|
||||
MTVU.h
|
||||
Memory.h
|
||||
|
|
|
@ -454,6 +454,7 @@ struct Pcsx2Config
|
|||
CdvdShareWrite :1, // allows the iso to be modified while it's loaded
|
||||
EnablePatches :1, // enables patch detection and application
|
||||
EnableCheats :1, // enables cheat detection and application
|
||||
EnableIPC :1, // enables inter-process communication
|
||||
EnableWideScreenPatches :1,
|
||||
#ifndef DISABLE_RECORDING
|
||||
EnableRecordingTools :1,
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <thread>
|
||||
#include <sys/types.h>
|
||||
#if _WIN32
|
||||
#define read_portable(a, b, c) (recv(a, b, c, 0))
|
||||
#define write_portable(a, b, c) (send(a, b, c, 0))
|
||||
#define bzero(b, len) (memset((b), '\0', (len)), (void)0)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#define read_portable(a, b, c) (read(a, b, c))
|
||||
#define write_portable(a, b, c) (write(a, b, c))
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "Memory.h"
|
||||
#include "System/SysThreads.h"
|
||||
#include "IPC.h"
|
||||
|
||||
SocketIPC::SocketIPC(SysCoreThread* vm)
|
||||
: pxThread("IPC_Socket")
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsa;
|
||||
SOCKET new_socket;
|
||||
struct sockaddr_in server, client;
|
||||
int c;
|
||||
|
||||
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
|
||||
{
|
||||
Console.WriteLn(Color_Red, "IPC: Cannot initialize winsock! Shutting down...");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
|
||||
{
|
||||
Console.WriteLn(Color_Red, "IPC: Cannot open socket! Shutting down...");
|
||||
return;
|
||||
}
|
||||
|
||||
// yes very good windows s/sun/sin/g sure is fine
|
||||
server.sin_family = AF_INET;
|
||||
// localhost only
|
||||
server.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
server.sin_port = htons(PORT);
|
||||
|
||||
if (bind(m_sock, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
|
||||
{
|
||||
Console.WriteLn(Color_Red, "IPC: Error while binding to socket! Shutting down...");
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
struct sockaddr_un server;
|
||||
|
||||
m_sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (m_sock < 0)
|
||||
{
|
||||
Console.WriteLn(Color_Red, "IPC: Cannot open socket! Shutting down...");
|
||||
return;
|
||||
}
|
||||
server.sun_family = AF_UNIX;
|
||||
strcpy(server.sun_path, SOCKET_NAME);
|
||||
|
||||
// we unlink the socket so that when releasing this thread the socket gets
|
||||
// freed even if we didn't close correctly the loop
|
||||
unlink(SOCKET_NAME);
|
||||
if (bind(m_sock, (struct sockaddr*)&server, sizeof(struct sockaddr_un)))
|
||||
{
|
||||
Console.WriteLn(Color_Red, "IPC: Error while binding to socket! Shutting down...");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// maximum queue of SOMAXCONN commands before refusing, which stops the thread
|
||||
listen(m_sock, SOMAXCONN);
|
||||
|
||||
// we save a handle of the main vm object
|
||||
m_vm = vm;
|
||||
|
||||
// we start the thread
|
||||
Start();
|
||||
}
|
||||
|
||||
void SocketIPC::ExecuteTaskInThread()
|
||||
{
|
||||
int msgsock = 0;
|
||||
// for the sake of speed we malloc once a return buffer and reuse it by just
|
||||
// cropping its size when needed, it is 450k long which is the size of 50k
|
||||
// MsgWrite64 replies, should be good enough even if we implement batch IPC
|
||||
// processing. Coincidentally 650k is the size of 50k MsgWrite64 REQUESTS so
|
||||
// we just allocate a 1mb buffer in the end, lul
|
||||
ret_buffer = (char*)malloc(450000 * sizeof(char));
|
||||
ipc_buffer = (char*)malloc(650000 * sizeof(char));
|
||||
while (true)
|
||||
{
|
||||
msgsock = accept(m_sock, 0, 0);
|
||||
if (msgsock == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (read_portable(msgsock, ipc_buffer, 650000) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto res = ParseCommand(ipc_buffer, ret_buffer);
|
||||
if (write_portable(msgsock, res.second, res.first) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SocketIPC::~SocketIPC()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
closesocket(m_sock);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(m_sock);
|
||||
unlink(SOCKET_NAME);
|
||||
#endif
|
||||
free(ret_buffer);
|
||||
free(ipc_buffer);
|
||||
// destroy the thread
|
||||
try
|
||||
{
|
||||
pxThread::Cancel();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
|
||||
char* SocketIPC::MakeOkIPC(char* ret_buffer)
|
||||
{
|
||||
ret_buffer[0] = (unsigned char)IPC_OK;
|
||||
return ret_buffer;
|
||||
}
|
||||
|
||||
char* SocketIPC::MakeFailIPC(char* ret_buffer)
|
||||
{
|
||||
ret_buffer[0] = (unsigned char)IPC_FAIL;
|
||||
return ret_buffer;
|
||||
}
|
||||
|
||||
std::pair<int, char*> SocketIPC::ParseCommand(char* buf, char* ret_buffer)
|
||||
{
|
||||
// currently all our instructions require a running VM so we check once
|
||||
// here, will help perf when/if we implement multi-ipc processing in one
|
||||
// socket roundtrip.
|
||||
if (!m_vm->HasActiveMachine())
|
||||
return std::make_pair(1, MakeFailIPC(ret_buffer));
|
||||
|
||||
// IPC Message event (1 byte)
|
||||
// | Memory address (4 byte)
|
||||
// | | argument (VLE)
|
||||
// | | |
|
||||
// format: XX YY YY YY YY ZZ ZZ ZZ ZZ
|
||||
// reply code: 00 = OK, FF = NOT OK
|
||||
// | return value (VLE)
|
||||
// | |
|
||||
// reply: XX ZZ ZZ ZZ ZZ
|
||||
IPCCommand opcode = (IPCCommand)buf[0];
|
||||
|
||||
// return value
|
||||
std::pair<int, char*> rval;
|
||||
|
||||
// YY YY YY YY from schema above
|
||||
u32 a = FromArray<u32>(buf, 1);
|
||||
switch (opcode)
|
||||
{
|
||||
case MsgRead8:
|
||||
{
|
||||
u8 res;
|
||||
res = memRead8(a);
|
||||
rval = std::make_pair(2, ToArray(MakeOkIPC(ret_buffer), res, 1));
|
||||
break;
|
||||
}
|
||||
case MsgRead16:
|
||||
{
|
||||
u16 res;
|
||||
res = memRead16(a);
|
||||
rval = std::make_pair(3, ToArray(MakeOkIPC(ret_buffer), res, 1));
|
||||
break;
|
||||
}
|
||||
case MsgRead32:
|
||||
{
|
||||
u32 res;
|
||||
res = memRead32(a);
|
||||
rval = std::make_pair(5, ToArray(MakeOkIPC(ret_buffer), res, 1));
|
||||
break;
|
||||
}
|
||||
case MsgRead64:
|
||||
{
|
||||
u64 res;
|
||||
memRead64(a, &res);
|
||||
rval = std::make_pair(9, ToArray(MakeOkIPC(ret_buffer), res, 1));
|
||||
break;
|
||||
}
|
||||
case MsgWrite8:
|
||||
{
|
||||
memWrite8(a, FromArray<u8>(buf, 5));
|
||||
rval = std::make_pair(1, MakeOkIPC(ret_buffer));
|
||||
break;
|
||||
}
|
||||
case MsgWrite16:
|
||||
{
|
||||
memWrite16(a, FromArray<u16>(buf, 5));
|
||||
rval = std::make_pair(1, MakeOkIPC(ret_buffer));
|
||||
break;
|
||||
}
|
||||
case MsgWrite32:
|
||||
{
|
||||
memWrite32(a, FromArray<u32>(buf, 5));
|
||||
rval = std::make_pair(1, MakeOkIPC(ret_buffer));
|
||||
break;
|
||||
}
|
||||
case MsgWrite64:
|
||||
{
|
||||
memWrite64(a, FromArray<u64>(buf, 5));
|
||||
rval = std::make_pair(1, MakeOkIPC(ret_buffer));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
rval = std::make_pair(1, MakeFailIPC(ret_buffer));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Client code example for interfacing with the IPC interface is available
|
||||
* here: https://code.govanify.com/govanify/pcsx2_ipc/ */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/PersistentThread.h"
|
||||
#include "System/SysThreads.h"
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
class SocketIPC : public pxThread
|
||||
{
|
||||
|
||||
typedef pxThread _parent;
|
||||
|
||||
protected:
|
||||
#ifdef _WIN32
|
||||
// windows claim to have support for AF_UNIX sockets but that is a blatant lie,
|
||||
// their SDK won't even run their own examples, so we go on TCP sockets.
|
||||
#define PORT 28011
|
||||
#else
|
||||
// absolute path of the socket. Stored in the temporary directory in linux since
|
||||
// /run requires superuser permission
|
||||
const char* SOCKET_NAME = "/tmp/pcsx2.sock";
|
||||
#endif
|
||||
|
||||
// socket handlers
|
||||
#ifdef _WIN32
|
||||
SOCKET m_sock = INVALID_SOCKET;
|
||||
#else
|
||||
int m_sock = 0;
|
||||
#endif
|
||||
|
||||
// buffers that store the ipc request and reply messages.
|
||||
char* ret_buffer;
|
||||
char* ipc_buffer;
|
||||
|
||||
// possible command messages
|
||||
enum IPCCommand
|
||||
{
|
||||
MsgRead8 = 0,
|
||||
MsgRead16 = 1,
|
||||
MsgRead32 = 2,
|
||||
MsgRead64 = 3,
|
||||
MsgWrite8 = 4,
|
||||
MsgWrite16 = 5,
|
||||
MsgWrite32 = 6,
|
||||
MsgWrite64 = 7
|
||||
};
|
||||
|
||||
// possible result codes
|
||||
enum IPCResult
|
||||
{
|
||||
IPC_OK = 0,
|
||||
IPC_FAIL = 0xFF
|
||||
};
|
||||
|
||||
// handle to the main vm thread
|
||||
SysCoreThread* m_vm;
|
||||
|
||||
/* Thread used to relay IPC commands. */
|
||||
void ExecuteTaskInThread();
|
||||
|
||||
/* Internal function, Parses an IPC command.
|
||||
* buf: buffer containing the IPC command.
|
||||
* ret_buffer: buffer that will be used to send the reply.
|
||||
* return value: pair containing a buffer with the result
|
||||
* of the command and its size. */
|
||||
std::pair<int, char*> ParseCommand(char* buf, char* ret_buffer);
|
||||
|
||||
/* Formats an IPC buffer
|
||||
* ret_buffer: return buffer to use.
|
||||
* return value: buffer containing the status code allocated of size
|
||||
* size */
|
||||
static inline char* MakeOkIPC(char* ret_buffer);
|
||||
static inline char* MakeFailIPC(char* ret_buffer);
|
||||
|
||||
/* Converts an uint to an char* in little endian
|
||||
* res_array: the array to modify
|
||||
* res: the value to convert
|
||||
* i: when to insert it into the array
|
||||
* return value: res_array
|
||||
* NB: implicitely inlined */
|
||||
template <typename T>
|
||||
static char* ToArray(char* res_array, T res, int i)
|
||||
{
|
||||
memcpy((res_array + i), (char*)&res, sizeof(T));
|
||||
return res_array;
|
||||
}
|
||||
|
||||
/* Converts a char* to an uint in little endian
|
||||
* arr: the array to convert
|
||||
* i: when to load it from the array
|
||||
* return value: the converted value
|
||||
* NB: implicitely inlined */
|
||||
template <typename T>
|
||||
static T FromArray(char* arr, int i)
|
||||
{
|
||||
return *(T*)(arr + i);
|
||||
}
|
||||
|
||||
public:
|
||||
/* Initializers */
|
||||
SocketIPC(SysCoreThread* vm);
|
||||
virtual ~SocketIPC();
|
||||
|
||||
}; // class SocketIPC
|
|
@ -436,6 +436,7 @@ void Pcsx2Config::LoadSave( IniInterface& ini )
|
|||
IniBitBool( CdvdShareWrite );
|
||||
IniBitBool( EnablePatches );
|
||||
IniBitBool( EnableCheats );
|
||||
IniBitBool( EnableIPC );
|
||||
IniBitBool( EnableWideScreenPatches );
|
||||
#ifndef DISABLE_RECORDING
|
||||
IniBitBool( EnableRecordingTools );
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "Patch.h"
|
||||
#include "SysThreads.h"
|
||||
#include "MTVU.h"
|
||||
#include "IPC.h"
|
||||
|
||||
#include "../DebugTools/MIPSAnalyst.h"
|
||||
#include "../DebugTools/SymbolMap.h"
|
||||
|
@ -243,6 +244,11 @@ void SysCoreThread::GameStartingInThread()
|
|||
#ifdef USE_SAVESLOT_UI_UPDATES
|
||||
UI_UpdateSysControls();
|
||||
#endif
|
||||
if(EmuConfig.EnableIPC && m_IpcState == OFF)
|
||||
{
|
||||
m_IpcState = ON;
|
||||
m_socketIpc = std::make_unique<SocketIPC>(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool SysCoreThread::StateCheckInThread()
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "Utilities/PersistentThread.h"
|
||||
#include "x86emitter/tools.h"
|
||||
#include "IPC.h"
|
||||
|
||||
|
||||
using namespace Threading;
|
||||
|
@ -170,6 +171,17 @@ protected:
|
|||
bool m_resetVsyncTimers;
|
||||
bool m_resetVirtualMachine;
|
||||
|
||||
// Stores the state of the socket IPC thread.
|
||||
std::unique_ptr<SocketIPC> m_socketIpc;
|
||||
|
||||
// Current state of the IPC thread
|
||||
enum StateIPC
|
||||
{
|
||||
OFF,
|
||||
ON
|
||||
};
|
||||
StateIPC m_IpcState = OFF;
|
||||
|
||||
// Indicates if the system has an active virtual machine state. Pretty much always
|
||||
// true anytime between plugins being initialized and plugins being shutdown. Gets
|
||||
// set false when plugins are shutdown, the corethread is canceled, or when an error
|
||||
|
|
|
@ -123,6 +123,7 @@ enum MenuIdentifiers
|
|||
MenuId_GameSettingsSubMenu,
|
||||
MenuId_EnablePatches,
|
||||
MenuId_EnableCheats,
|
||||
MenuId_EnableIPC,
|
||||
MenuId_EnableWideScreenPatches,
|
||||
MenuId_EnableInputRecording,
|
||||
MenuId_EnableLuaTools,
|
||||
|
|
|
@ -216,6 +216,7 @@ void MainEmuFrame::ConnectMenus()
|
|||
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_EnablePatches_Click, this, MenuId_EnablePatches);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_EnableCheats_Click, this, MenuId_EnableCheats);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_EnableIPC_Click, this, MenuId_EnableIPC);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_EnableWideScreenPatches_Click, this, MenuId_EnableWideScreenPatches);
|
||||
#ifndef DISABLE_RECORDING
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_EnableRecordingTools_Click, this, MenuId_EnableInputRecording);
|
||||
|
@ -368,6 +369,9 @@ void MainEmuFrame::CreatePcsx2Menu()
|
|||
m_GameSettingsSubmenu.Append(MenuId_EnableCheats, _("Enable &Cheats"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
|
||||
m_GameSettingsSubmenu.Append(MenuId_EnableIPC, _("Enable &IPC"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
|
||||
m_GameSettingsSubmenu.Append(MenuId_EnableWideScreenPatches, _("Enable &Widescreen Patches"),
|
||||
_("Enabling Widescreen Patches may occasionally cause issues."), wxITEM_CHECK);
|
||||
|
||||
|
@ -744,6 +748,7 @@ void MainEmuFrame::ApplyConfigToGui(AppConfig& configToApply, int flags)
|
|||
{//these should not be affected by presets
|
||||
menubar.Check( MenuId_EnableBackupStates, configToApply.EmuOptions.BackupSavestate );
|
||||
menubar.Check( MenuId_EnableCheats, configToApply.EmuOptions.EnableCheats );
|
||||
menubar.Check( MenuId_EnableIPC, configToApply.EmuOptions.EnableIPC );
|
||||
menubar.Check( MenuId_EnableWideScreenPatches, configToApply.EmuOptions.EnableWideScreenPatches );
|
||||
#ifndef DISABLE_RECORDING
|
||||
menubar.Check( MenuId_EnableInputRecording, configToApply.EmuOptions.EnableRecordingTools);
|
||||
|
|
|
@ -193,6 +193,7 @@ protected:
|
|||
void Menu_EnableBackupStates_Click(wxCommandEvent &event);
|
||||
void Menu_EnablePatches_Click(wxCommandEvent &event);
|
||||
void Menu_EnableCheats_Click(wxCommandEvent &event);
|
||||
void Menu_EnableIPC_Click(wxCommandEvent &event);
|
||||
void Menu_EnableWideScreenPatches_Click(wxCommandEvent &event);
|
||||
#ifndef DISABLE_RECORDING
|
||||
void Menu_EnableRecordingTools_Click(wxCommandEvent &event);
|
||||
|
|
|
@ -528,6 +528,13 @@ void MainEmuFrame::Menu_EnableCheats_Click( wxCommandEvent& )
|
|||
AppSaveSettings();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_EnableIPC_Click( wxCommandEvent& )
|
||||
{
|
||||
g_Conf->EmuOptions.EnableIPC = GetMenuBar()->IsChecked( MenuId_EnableIPC );
|
||||
AppApplySettings();
|
||||
AppSaveSettings();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_EnableWideScreenPatches_Click( wxCommandEvent& )
|
||||
{
|
||||
g_Conf->EmuOptions.EnableWideScreenPatches = GetMenuBar()->IsChecked( MenuId_EnableWideScreenPatches );
|
||||
|
|
|
@ -188,6 +188,7 @@
|
|||
<ClCompile Include="..\..\gui\DriveList.cpp" />
|
||||
<ClCompile Include="..\..\gui\Panels\MemoryCardListView.cpp" />
|
||||
<ClCompile Include="..\..\IopGte.cpp" />
|
||||
<ClCompile Include="..\..\IPC.cpp" />
|
||||
<ClCompile Include="..\..\IPU\IPUdma.cpp" />
|
||||
<ClCompile Include="..\..\IPU\IPUdither.cpp" />
|
||||
<ClCompile Include="..\..\Linux\LnxConsolePipe.cpp">
|
||||
|
@ -437,6 +438,7 @@
|
|||
<ClInclude Include="..\..\gui\Debugger\DisassemblyDialog.h" />
|
||||
<ClInclude Include="..\..\gui\Panels\MemoryCardPanels.h" />
|
||||
<ClInclude Include="..\..\IopGte.h" />
|
||||
<ClInclude Include="..\..\IPC.h" />
|
||||
<ClInclude Include="..\..\IPU\IPUdma.h" />
|
||||
<ClInclude Include="..\..\Mdec.h" />
|
||||
<ClInclude Include="..\..\Patch.h" />
|
||||
|
@ -624,4 +626,4 @@
|
|||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -888,6 +888,8 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="..\..\gui\DriveList.cpp">
|
||||
<Filter>AppHost</Filter>
|
||||
<ClCompile Include="..\..\IPC.cpp">
|
||||
<Filter>System</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -1343,6 +1345,8 @@
|
|||
</ClInclude>
|
||||
<ClInclude Include="..\..\gui\DriveList.h">
|
||||
<Filter>AppHost\Include</Filter>
|
||||
<ClInclude Include="..\..\IPC.h">
|
||||
<Filter>System\Include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -1428,4 +1432,4 @@
|
|||
<Filter>AppHost\Resources</Filter>
|
||||
</Manifest>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
Loading…
Reference in New Issue