Files
TFSImport/TfsExcelImporter/NativeLibraryLoader.cs
T
chenshoulin d055b415fa feat: 增强便携版支持与配置管理
- 更新 .gitignore 文件,添加便携版分发目录和 Fody 生成的配置文件。
- 修改 README.md,详细说明便携版的构建与分发流程,强调单文件分发的优势。
- 在 Config.cs 中实现便携配置管理,优先使用 exe 同目录的 config.json,提升用户体验。
- 更新 ExcelService.cs,优化默认模板的导出逻辑,支持现场替换模板文件。
- 在 MainForm.cs 中加载应用图标,提升界面一致性。
- 调整 Program.cs,确保在单文件分发时正确加载 native DLL。
2026-11-01 20:17:56 +08:00

84 lines
3.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
namespace TfsExcelImporter
{
/// <summary>
/// TFS Client OM 除托管程序集外还依赖两个纯 win32 DLL
/// (Microsoft.WITDataStore32/64.dll)。托管程序集由 Costura 内嵌并从内存加载,
/// native DLL 只能落盘后 LoadLibrary,所以单文件分发时:
/// 启动阶段把内嵌的 native DLL 释放到 %TEMP%\TfsExcelImporter\native\{内容hash},
/// 再 LoadLibrary 预加载 —— 之后 TFS 内部的 DllImport 会直接命中已加载模块。
/// 目录名带 DLL 内容 hash,升级后不会残留旧版本。
/// exe 同目录存在同名 DLL(开发机 bin 目录、绿色解压版)时不做任何处理。
/// </summary>
internal static class NativeLibraryLoader
{
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryW")]
private static extern IntPtr LoadLibrary(string path);
public static void EnsureLoaded()
{
var fileName = Environment.Is64BitProcess
? "Microsoft.WITDataStore64.dll"
: "Microsoft.WITDataStore32.dll";
if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName)))
return;
try
{
var asm = typeof(NativeLibraryLoader).Assembly;
var resourceName = "native." + fileName;
using (var stream = asm.GetManifestResourceStream(resourceName))
{
if (stream == null)
{
Debug.WriteLine("未找到内嵌 native 资源: " + resourceName);
return;
}
byte[] bytes;
using (var buffer = new MemoryStream())
{
stream.CopyTo(buffer);
bytes = buffer.ToArray();
}
var target = Path.Combine(NativeDir(bytes), fileName);
Directory.CreateDirectory(Path.GetDirectoryName(target));
if (!File.Exists(target))
{
try { File.WriteAllBytes(target, bytes); }
catch (IOException)
{
// 同 hash 目录已被另一实例写住,内容等价,直接用
if (!File.Exists(target)) throw;
}
}
if (LoadLibrary(target) == IntPtr.Zero)
Debug.WriteLine("LoadLibrary 失败(" + Marshal.GetLastWin32Error() + "): " + target);
}
}
catch (Exception ex)
{
// 释放失败不阻断启动:TFS 连接时会自行报 DllNotFound,提示仍是可读的
Debug.WriteLine("释放 native DLL 失败: " + ex.Message);
}
}
private static string NativeDir(byte[] bytes)
{
byte[] hash;
using (var sha = SHA256.Create())
hash = sha.ComputeHash(bytes);
var stamp = BitConverter.ToString(hash, 0, 4).Replace("-", "");
return Path.Combine(Path.GetTempPath(), "TfsExcelImporter", "native", stamp);
}
}
}