C#中调用WriteFile()修改文件首字节报错,求助解决方案
问题:C#调用WriteFile修改文件头报错的解决方法
问题背景
我原本用C语言实现了修改转储文件前几个字节的功能,代码如下:
SetFilePointer(hDmpFile, 0, 0, FILE_BEGIN); WriteFile(hDmpFile, "AA", 2, NULL, NULL);
现在想在C#里实现同样功能,但调用WriteFile时抛出NotImplementedException,我的C#代码片段如下:
public enum EMoveMethod : uint { Begin = 0, Current = 1, End = 2 } [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern uint SetFilePointer( [In] SafeFileHandle hFile, [In] int lDistanceToMove, [Out] out int lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod); [DllImport("kernel32.dll", BestFitMapping = true, CharSet = CharSet.Ansi)] public static extern bool WriteFile( IntPtr hFile, System.Text.StringBuilder lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, [In] ref System.Threading.NativeOverlapped lpOverlapped); // 调用部分 int moveDistanceHighBits = 0; uint test = SetFilePointer(hDmpFile, 0, out moveDistanceHighBits, EMoveMethod.Begin); uint test2 = WriteFile(hDmpFile, "AA", 2, null, null); hDmpFile.Dispose();
报错信息:
Unhandled Exception: System.NotImplementedException: The method or operation is not implemented. at Foo.Program.WriteFile(SafeFileHandle hDmpFile, String v1, Int32 v2, Object value1, Object value2) at Foo.Program.Execute(String[] args) at Foo.Program.Main(String[] args)
注:我完全不懂编程,也从未接触过C#。
错误原因
你的WriteFile调用存在多处参数不匹配问题:
- 参数类型不匹配:传入的
SafeFileHandle和声明的IntPtr不匹配;传入字符串"AA"和声明要求的StringBuilder不匹配;最后两个参数直接传null,但声明要求的是out uint和ref NativeOverlapped,不能直接传空值。 - 返回值类型不匹配:WriteFile实际返回
bool,但你用uint类型接收。
最简单的解决方法(用C#原生API,无需调用Windows底层接口)
对于完全不懂C#的人,直接用C#自带的FileStream类更简单,代码直观且无需处理复杂的API声明:
using System.IO; // 替换成你的转储文件路径 string filePath = "your_dump_file_path.dmp"; // using块会自动释放文件资源,不用手动处理 using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { // 定位到文件开头 fs.Seek(0, SeekOrigin.Begin); // 把"AA"转成ASCII字节(和C代码行为一致) byte[] bytes = System.Text.Encoding.ASCII.GetBytes("AA"); // 写入文件 fs.Write(bytes, 0, bytes.Length); }
如果非要用P/Invoke的修复方案
如果坚持要调用Windows底层API,修正后的代码如下:
using System; using System.Runtime.InteropServices; using System.Text; using Microsoft.Win32.SafeHandles; public enum EMoveMethod : uint { Begin = 0, Current = 1, End = 2 } [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern uint SetFilePointer( [In] SafeFileHandle hFile, [In] int lDistanceToMove, [Out] out int lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod); // 修正WriteFile的API声明,匹配参数类型 [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool WriteFile( SafeFileHandle hFile, byte[] lpBuffer, // 用字节数组直接传递,避免字符串编码问题 uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped); // 用IntPtr可以传IntPtr.Zero表示空指针 // 调用部分 int moveDistanceHighBits = 0; SetFilePointer(hDmpFile, 0, out moveDistanceHighBits, EMoveMethod.Begin); // 把"AA"转成ASCII字节 byte[] buffer = Encoding.ASCII.GetBytes("AA"); uint bytesWritten; // 最后一个参数传IntPtr.Zero对应C代码里的NULL bool writeSuccess = WriteFile(hDmpFile, buffer, 2, out bytesWritten, IntPtr.Zero); hDmpFile.Dispose();
修复点说明:
- 将WriteFile的第一个参数改为
SafeFileHandle,和你持有的文件句柄类型匹配 - 用
byte[]代替StringBuilder,避免字符串转码的额外问题,和C代码行为一致 - 最后一个参数改为
IntPtr,传IntPtr.Zero即可表示C代码中的NULL - 用
bool类型接收返回值,符合API实际返回类型 - 必须声明
out uint lpNumberOfBytesWritten变量,不能直接传null
内容的提问来源于stack exchange,提问作者Darktortue
相关产品推荐
相关产品推荐

