.NET代码中PInvoke调用RtlIsNameInExpression方法的实现咨询
如何在.NET控制台应用中调用RtlIsNameInExpression实现Windows原生文件名匹配
我刚好对这个函数的P/Invoke实现有研究,直接给你整理好可用的代码和注意事项,保证你的应用和Windows原生行为完全对齐:
首先,这个函数属于ntdll.dll,需要先定义Windows原生的UNICODE_STRING结构体(因为函数参数用的是这个类型),然后再声明P/Invoke调用:
using System; using System.Runtime.InteropServices; internal static class NativeMethods { // 定义Windows原生UNICODE_STRING结构体 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct UNICODE_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } // RtlIsNameInExpression的P/Invoke声明 [DllImport("ntdll.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal static extern bool RtlIsNameInExpression( ref UNICODE_STRING Expression, ref UNICODE_STRING Name, bool IgnoreCase, IntPtr UpcaseTable ); // 封装一个简化方法,直接接收C#字符串,不用手动处理UNICODE_STRING public static bool IsFileNameMatch(string wildcardPattern, string fileName) { // 将C#字符串转换为UNICODE_STRING var expression = CreateUnicodeString(wildcardPattern); var name = CreateUnicodeString(fileName); try { // 调用原生函数,IgnoreCase设为true(Windows默认不区分大小写),UpcaseTable传空用系统默认 return RtlIsNameInExpression(ref expression, ref name, true, IntPtr.Zero); } finally { // 释放分配的内存,避免泄漏 Marshal.FreeHGlobal(expression.Buffer); Marshal.FreeHGlobal(name.Buffer); } } // 辅助方法:把C#字符串转为UNICODE_STRING private static UNICODE_STRING CreateUnicodeString(string value) { if (string.IsNullOrEmpty(value)) { return new UNICODE_STRING(); } // 分配非托管内存存储Unicode字符串 var buffer = Marshal.StringToHGlobalUni(value); return new UNICODE_STRING { Length = (ushort)(value.Length * 2), // 每个Unicode字符占2字节 MaximumLength = (ushort)(value.Length * 2 + 2), // 预留终止符空间 Buffer = buffer }; } }
使用示例
在你的控制台应用里直接调用封装好的方法就行,完全贴合Windows原生匹配逻辑:
var pattern = "*.txt"; var fileName = "Document1.TXT"; bool isMatch = NativeMethods.IsFileNameMatch(pattern, fileName); Console.WriteLine(isMatch); // 输出True,和Windows资源管理器的匹配结果一致
关键注意事项
IgnoreCase参数:Windows文件名默认不区分大小写,所以这里设为true是符合原生行为的;如果需要严格区分大小写,改成false即可。UpcaseTable参数:传IntPtr.Zero会让函数使用系统默认的大小写转换表,无需自己额外处理。- 内存管理:必须释放
Marshal.StringToHGlobalUni分配的非托管内存,上面的封装方法已经在finally块里做了处理,不用担心内存泄漏。
内容的提问来源于stack exchange,提问作者RobIII
相关产品推荐
相关产品推荐

