Windows Server 2019/2012 R2中MFC程序MSI自定义动作下编辑框无法粘贴
问题核心原因
你的MFC程序在MSI自定义动作调用时,默认以系统账户权限运行,处于Windows的会话0隔离环境中;而用户通过Ctrl+C复制的内容存储在当前交互式用户的会话剪贴板中——系统会话与用户会话的剪贴板完全隔离,因此程序无法读取到用户复制的内容,导致粘贴失败;但程序自身的内容可以写入系统会话的剪贴板,部分用户应用能跨会话读取这部分内容,所以复制功能看似正常。
解决方案
1. 修改MSI自定义动作的运行上下文(优先推荐)
将自定义动作改为以当前交互式用户权限运行,让程序处于用户会话中,直接访问用户剪贴板:
- 用Orca打开你的MSI安装包,找到
CustomAction表 - 定位到调用你MFC程序的自定义动作条目,修改
Type列的值:- 如果当前Type值包含
msidbCustomActionTypeNoImpersonate(即值带有0x0004标记),移除该标记(比如原Type是3073,改为3069) - 确保自定义动作的
Impersonate属性设置为yes,让程序以当前用户身份执行
- 如果当前Type值包含
2. 跨会话访问剪贴板(必须系统权限运行时)
如果业务需求要求程序必须以系统权限运行,需要通过Windows终端服务API(WTS)获取用户会话的令牌,在用户会话中启动程序:
#include <Wtsapi32.h> #pragma comment(lib, "Wtsapi32.lib") void LaunchAppInUserSession() { DWORD dwSessionId = WTSGetActiveConsoleSessionId(); HANDLE hUserToken = NULL; // 获取用户会话令牌 if (WTSQueryUserToken(dwSessionId, &hUserToken)) { STARTUPINFO si = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION pi; TCHAR szAppPath[] = _T("你的MFC程序路径.exe"); // 在用户会话中创建进程 if (CreateProcessAsUser( hUserToken, NULL, szAppPath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } CloseHandle(hUserToken); } }
将这段代码加入你的自定义动作逻辑中,让实际处理剪贴板的程序在用户会话中启动,即可正常读取剪贴板内容。
3. 完善剪贴板读取的错误检查
在尝试读取剪贴板时,增加格式校验和错误判断,避免因格式不匹配导致的读取失败:
void PasteFromClipboard(CEdit& editCtrl) { if (!OpenClipboard(editCtrl.GetSafeHwnd())) return; // 优先检查Unicode文本格式(适配现代系统) if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { HANDLE hClipData = GetClipboardData(CF_UNICODETEXT); if (hClipData) { wchar_t* pText = static_cast<wchar_t*>(GlobalLock(hClipData)); if (pText) { editCtrl.SetWindowTextW(pText); GlobalUnlock(hClipData); } } } // 兼容ANSI格式 else if (IsClipboardFormatAvailable(CF_TEXT)) { HANDLE hClipData = GetClipboardData(CF_TEXT); if (hClipData) { char* pText = static_cast<char*>(GlobalLock(hClipData)); if (pText) { editCtrl.SetWindowTextA(pText); GlobalUnlock(hClipData); } } } CloseClipboard(); }
内容的提问来源于stack exchange,提问作者TS12345
相关产品推荐
相关产品推荐

