本地Excel粘贴至远程程序失败及内存异常问题求助
本地Excel文件复制到远程桌面程序并保存至临时文件夹的实现方案
问题背景
本地电脑的Excel文件需复制粘贴到远程桌面运行的程序中,后续通过Excel.Interop修改并另存。远程内部复制文件时,使用DataFormats.FileDrop可正常获取文件路径,但跨本地-远程粘贴时只能通过FileGroupDescriptorW获取文件名信息,解析时还会抛出**"An attempt was made to read or write protected memory..."**异常,无法获取文件内容。
解决方案
远程桌面跨会话剪贴板传输文件时,需同时处理FileGroupDescriptorW(文件元数据)和FileContents(文件内容)两个格式。以下是完整的解析与保存代码:
1. 定义Win32结构体(对应FileGroupDescriptorW)
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct FILEDESCRIPTORW { public uint dwFlags; public Guid clsid; public System.Drawing.Size sizel; public System.Drawing.Point pointl; public uint dwFileAttributes; public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; } [StructLayout(LayoutKind.Sequential)] private struct FILEGROUPDESCRIPTORW { public uint cItems; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public FILEDESCRIPTORW[] fgd; }
2. 解析剪贴板数据并保存到临时文件夹
public static List<string> SaveRemoteCopiedFilesToTemp() { List<string> tempFilePaths = new List<string>(); IDataObject dataObject = Clipboard.GetDataObject(); // 检查是否包含文件组描述符 if (!dataObject.GetDataPresent("FileGroupDescriptorW")) return tempFilePaths; // 获取文件组描述符流 using (MemoryStream fgStream = (MemoryStream)dataObject.GetData("FileGroupDescriptorW", true)) { byte[] buffer = new byte[fgStream.Length]; fgStream.Read(buffer, 0, buffer.Length); // 分配非托管内存并复制数据 IntPtr hGlobal = Marshal.AllocHGlobal(buffer.Length); try { Marshal.Copy(buffer, 0, hGlobal, buffer.Length); FILEGROUPDESCRIPTORW fgd = Marshal.PtrToStructure<FILEGROUPDESCRIPTORW>(hGlobal); // 遍历每个文件 for (int i = 0; i < fgd.cItems; i++) { // 计算当前文件描述符的内存偏移 IntPtr fileDescPtr = IntPtr.Add(hGlobal, Marshal.SizeOf(typeof(uint)) + i * Marshal.SizeOf(typeof(FILEDESCRIPTORW))); FILEDESCRIPTORW fileDesc = Marshal.PtrToStructure<FILEDESCRIPTORW>(fileDescPtr); // 获取文件内容流 if (dataObject.GetDataPresent("FileContents", true)) { using (MemoryStream fileStream = (MemoryStream)dataObject.GetData("FileContents", true)) { // 生成临时文件路径 string tempPath = Path.Combine(Path.GetTempPath(), fileDesc.cFileName); // 写入文件 using (FileStream fs = new FileStream(tempPath, FileMode.Create, FileAccess.Write)) { fileStream.CopyTo(fs); } tempFilePaths.Add(tempPath); } } } } finally { // 释放非托管内存,避免内存泄漏 Marshal.FreeHGlobal(hGlobal); } } return tempFilePaths; }
3. 使用示例
// 获取保存到临时文件夹的文件路径 List<string> tempFiles = SaveRemoteCopiedFilesToTemp(); if (tempFiles.Count > 0) { string excelPath = tempFiles[0]; // 取第一个Excel文件 // 后续使用Excel.Interop打开并编辑 Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application(); Microsoft.Office.Interop.Excel.Workbook workbook = excelApp.Workbooks.Open(excelPath); // ... 编辑操作 ... workbook.SaveAs(@"C:\Remote\Edited_File.xlsx"); workbook.Close(); excelApp.Quit(); // 可选:清理临时文件 File.Delete(excelPath); }
关键注意事项
- 内存处理:解析
FileGroupDescriptorW时必须正确处理非托管内存的分配与释放,这是避免保护内存异常的核心。 - 权限:确保远程桌面程序拥有剪贴板访问权限,以及临时文件夹的读写权限。
- 多文件处理:代码支持同时复制多个文件,可根据需求调整逻辑。
内容的提问来源于stack exchange,提问作者NadiaBallshek
相关产品推荐
相关产品推荐

