I am using the FileRead API.
I used Windows 7 x64 and my code worked good and correct.
Now I installed a new Windows 7 x86 and VS2008 teamsuit and .NET 2, 3+SP1+SP2, 3.5, 3.5.1.
I run my code as Administrator but still encounter the follwoing error:
AccessViolationException(Attempted to read or write protected memory. This is often an indication that other memory is corrupt.)
int nread = 0;
uint handle;
byte[] buff = new byte[1024];
string driveRoot = string.Concat("\\\\.\\", driveLetter);
uint hRoot = CreateFile(driveRoot,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
if (hRoot != -1)
handle = ReadFile(hRoot, buff, 1024, nread, new System.Threading.NativeOverlapped());
While I'm no C# guru, it appears to me that you're invoking ReadFile() with wrong parameters.
The 4th parameter must be a pointer to an integer that will receive the number of bytes read. You supply the integer itself (nread), not its address (&nread).
And unless you want asynchronous file I/O, the last parameter to ReadFile() must be a NULL pointer (or just 0).
See this example on MSDN.
I suspect that the main problem with your code is that you are requesting overlapped I/O but supplying a buffer that ceases to exist when ReadFile returns. It works on some systems an not others because the system decides whether or not to perform the operation asynchronously, and it may choose not to do async on one system and choose differently on another.
I'm sure you don't want overlapped I/O so you should simply pass NULL to the final parameter of ReadFile.
On the other hand, perhaps your code isn't working at all on the x64 system and never gets as far as an AV. Your handle types are mis-declared as 32 bit integers.
There are many other minor problems with your code. Here's an edited version of the code that corrects these errors. The P/invoke signatures were taken from pinvoke.net.
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(
IntPtr hFile,
[Out] byte[] lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped
);
static void Main(string[] args)
{
string physicalDrive = #"\\.\PhysicalDrive0";
IntPtr hFile = CreateFile(
physicalDrive,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero
);
if (hFile.ToInt64() != INVALID_HANDLE_VALUE)
{
byte[] buff = new byte[1024];
uint nread;
if (ReadFile(hFile, buff, (uint)buff.Length, out nread, IntPtr.Zero))
Console.WriteLine("Read successful");
}
}
To summarise the errors in your code:
Incorrect use of 32 bit integers to store handles.
Your P/invoke declaration of ReadFile declares the lpNumberOfBytesRead incorrectly.
ReadFile does not return a handle, it returns a boolean indicating success of the function call.
Use of overlapped I/O which you do not want, and which cannot work with a marshalled byte[] buffer.
You must never call GetLastError from managed code (you did so in code shown in a comment). Instead call Marshal.GetLastWin32Error. The reasons are explained in the documentation for that method.
Related
I have an issue when calling the 'WinUsb_WritePipe' method.
At first, I start by call 'CreateFile' method that provides me a handle.
Then I call 'WinUsb_Initialize' method to get the WinUsbHandle.
After that, I retrieve some information about my USB device by calling 'WinUsb_QueryDeviceInformation', 'WinUsb_QueryInterfaceSettings' and 'WinUsb_QueryPipe' without any issue.
My problem appends when I have to call the 'WinUsb_WritePipe' method.
In a first library that I have made in C language, it works correctly.
But I have to switch from C to C# for my new library and the method returns False and the last error that I get is INVALID_PARAMETER.
It seems that comes from overlapped parameter. I can't passed NULL to this parameter as indicated in the specification.
I don't see what I am doing wrong.
I've tried already:
I already try to change the type of Overlapped parameter from IntPtr, to Int to put 0 as for C language call.
I have tried to change IntPtr by NativeOverlapped structure. In a first time with a NULL structure but I have the same issue.
If I gave a initialized structure, I try to call GetOverlappedResult method but it just returns INVALID_PARAMETER so the issue is always present.
I have tried to use unsafe to manage the method as a C calling but the issue is still here.
You can find my code below :
[DllImport("winusb.dll", SetLastError = true)]
internal static extern Boolean WinUsb_WritePipe(IntPtr InterfaceHandle, Byte PipeId, Byte[] Buffer, UInt32 BufferLength, ref UInt32 LengthTransferred, IntPtr Overlapped);
Byte[] SendBuffer = new Byte[3];
SendBuffer[0] = 0x01;
SendBuffer[1] = 0x0D;
SendBuffer[2] = 0x00;
UInt32 BytesToWrite = Convert.ToUInt32(SendBuffer.Length);
UInt32 BytesWritten=0;
IntPtr Handle = DeviceUSB.GetHandle(); //corresponding to the WinUsbHandle
Byte Pipe = DeviceUSB.GetPipe(DeviceUSB.GetSelectedMode()).PipeOutId; // 0x04
Success = WinUsbApiCalls.WinUsb_WritePipe(Handle, Pipe, SendBuffer, SizeToSend, ref SizeSent, IntPtr.Zero);
I expect the return value is set to true and SizeSent to be 3. but the actual returns false with lastError set to INVALID_PARAMETER and SizeSent is 0.
I have tried again with my first declaration of DllImport with UInt32 instead of UInt64. There is no exception of stack imbalance but just an error by getting last error which is INVALID_PARAMETER. I think there is an issue with overlapped param and not with types of size parameters. It seems that it is not supported by writepipe method to put IntPtr.Zero into this param overlapped.
If you are using this API https://learn.microsoft.com/en-us/windows/desktop/api/winusb/nf-winusb-winusb_writepipe you need to change your BufferLength and LengthTransferred parameters from UInt32 to UInt64
C++
BOOL WinUsb_WritePipe(
WINUSB_INTERFACE_HANDLE InterfaceHandle,
UCHAR PipeID,
PUCHAR Buffer,
ULONG BufferLength,
PULONG LengthTransferred,
LPOVERLAPPED Overlapped
);
C#
internal static extern Boolean WinUsb_WritePipe(
IntPtr InterfaceHandle,
Byte PipeId,
Byte[] Buffer,
UInt64 BufferLength,
ref UInt64 LengthTransferred,
IntPtr Overlapped);
I'm trying to detect if executable requires UAC elevation so I found this question on SO. with the following answer
Try using the CheckElevation function exported by kernel32.dll. This
is a completely undocumented function, but here's what I've been able
to reverse-engineer:
ULONG CheckElevation(
__in PWSTR FileName,
__inout PULONG Flags, // Have a ULONG set to 0, and pass a pointer to it
__in_opt HANDLE TokenHandle, // Use NULL
__out_opt PULONG Output1, // On output, is 2 or less.
__out_opt PULONG Output2
);
You'll have to do some experimentation to find out how to call the
function properly. What I've been able to work out so far is that if
Output1 is not 0, elevation is required.
So I created the following function
[DllImport("Kernel32.dll")]
static extern uint CheckElevation(
string FileName,
out uint Flags,
IntPtr TokenHandle,
out uint Output1,
out uint Output2
);
And I use it like this
uint flags = 0, output1 =0, output2 = 0;
uint result = CheckElevation(path,
out flags,
IntPtr.Zero,
out output1,
out output2
);
I tested it on some files.
On EXE files result = 123 or 2 and output1 is always 0
I don't know what I'm doing wrong because I can't find any documentation for this function, And I do not have much experience with the Windows API
Please help me.
Thanks in advance.
I'm having a problem with kernal32 Pinvoke functions as they keeps throwing an INVALID_FILE_HANDLE. The program reads the first sector of the current hard disk. I can't see what is wrong with the following code.
class Program
{
const uint GENERIC_READ = 0x80000000;
const uint FILE_SHARE_READ = 0x00000001;
const uint OPEN_EXISTING = 0x00000003;
const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
[DllImport("kernel32.dll", SetLastError = true)]
public static extern SafeFileHandle CreateFile(string Disk, uint Access, uint ShareMode, IntPtr SecurityAttributes, uint CreationDisposition, uint Flags, IntPtr TemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint SetFilePointer([In] SafeFileHandle Handle, [In] int DistanceToMove, [Out] out int DistanceToMoveHigh, [In] int MoveMethod);
[DllImport("kernel32.dll", SetLastError = true)]
unsafe public static extern int ReadFile(SafeFileHandle Handle, [Out] byte[] Buffer, int NumberOfBytesToRead, out int NumberOfBytesRead, IntPtr Overlapped);
unsafe public static void Main(string[] args)
{
string Drive = #"\\.\C";
int SectorSize = 512;
int Sector = 0;
int BytesRead, DistanceToMoveHigh;
byte[] Buffer = new byte[SectorSize];
SafeFileHandle Handle = CreateFile(Drive, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, IntPtr.Zero);
SetFilePointer(Handle, Sector * SectorSize, out DistanceToMoveHigh, 0);
ReadFile(Handle, Buffer, SectorSize, out BytesRead, IntPtr.Zero);
Console.WriteLine(Marshal.GetLastWin32Error()); // It gives 6 which translates to an INVALID_FILE_HANDLE error
Console.ReadKey();
}
}
Your call to CreateFile fails. Of course you cannot know that because you omitted any error checking. Read the documentation. Errors for all three functions that you call are signaled by the return value. Which you ignore.
Your call to CreateFile returns INVALID_HANDLE_VALUE. You need to test for that. When you encounter that, and only then, call GetLastWin32Error. Likely ERROR_ACCESS_DENIED will be returned then.
Passing FILE_FLAG_DELETE_ON_CLOSE is a mistake. Remove that flag.
I believe that the share flags must be FILE_SHARE_READ | FILE_SHARE_WRITE.
The file name must be #"\\.\C:" with a trailing colon.
And you will need the process to be executed elevated.
You use GetLastWin32Error in a wrong way.
The method that fails here is CreateFile and it returns an INVALID_HANDLE_VALUE (indicating that it failed). To determine what went wrong you have to call GetLastWin32Error directly after CreateFile.
When you call it after trying to read, the error is of course ERROR_INVALID_HANDLE (6) as you passed an invalid handle to ReadFile.
If you call GetLastWin32Error directly after the failing CreateFile you get error 2:
The system cannot find the file specified.
That is because the the drive name misses a :
string Drive = #"\\.\C:"; // <- add colon :
I tried with that drive name, but then got the error 32:
The process cannot access the file because it is being used by another process.
I keep trying to figure out how that can be handled...
I'm working on a plug and play version POS for .NET Service Object. I have a FTDI device that has 2 devices on it. One is a MSR and the other is a RFID. For a quick catch up POS for .NET supports Plug in play if you give it a Hardware ID. The FTDI device's hardware id is QUADPORT\QUAD_SERIAL_INTERFACE. So on my Service Object (SO) I start it with this
[HardwareId("QUADPORT\\QUAD_SERIAL_INTERFACE")]
[ServiceObject(DeviceType.Msr, "FTDI Device", "MSR FTDI Device", 1, 8)]
public class FTDIDevice : Msr
{
...
}
In the open method I can query the DevicePath property and it is the correct DevicePath. As a quick test to make sure it was indeed talking to the serial port through the device path I opened a FileStream to this Device Path, then tried to open both of the Virtual Com Ports and sure enough one of them had "Access Denied". Awesome! My next test I did was to write to the RFID device since I know most all of the commands and how to format the byte array to communicate with the RFID device. In fact here is the code I use.
public override void Open()
{
string str = this.DevicePath;
handle_read = Kernel32.CreateExistingRWFile(str);
FS_read = new FileStream(handle_read, FileAccess.ReadWrite, 9);
Console.WriteLine("File Stream Created, Writing Open Sequence");
byte[] open = { 0xAA, 0xBB, 0x04, 0xFB, 0x00, 0x00, 0x03, 0xF8 };
FS_read.Write(open, 0, open.Length);
//byte[] receive = new byte[11];
//var something = FS_read.Read(receive, 0, receive.Length);
//Console.WriteLine(BitConverter.ToString(receive, 0, something));
//Close the FileStream and the SafeFileHandle
close();
}
private SafeFileHandle handle_read;
private FileStream FS_read;
The first time I ran this code I selected the MSR (there are 2 devices with the exact name both in device manager and in the microsoft test app, so I was guessing anyway) and sending that command gave me no response from the MSR (for obvious reasons, its not the RFID Device). According to the MSDN site the Read command blocks until at least one byte is read from my stream. That is a problem since the MSR does not respond to RFID commands. So essentially my program is deadlocked. I force closed the program then fired it up again and selected the RFID and the Read method did indeed return with a successful response from the RFID.
So my question is is how can I query the Stream to see if there was any response from my device? I've tried using the CanRead property (always returns true). I've tried using ReadByte to see if it would return -1 like the document said it is supposed to, but it too hangs. I tried using the Length property but it throws an exception saying that the Stream does not support seeking. It feels like I'm out of options, hence why I'm asking here. Any suggestions?
EDIT
Hans wants to see my how I created my handle
internal class Kernel32
{
internal static SafeFileHandle CreateExistingRWFile(string devicePath)
{
return CreateFile(devicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
}
internal const short FILE_ATTRIBUTE_NORMAL = 0x80;
internal const short INVALID_HANDLE_VALUE = -1;
internal const uint GENERIC_READ = 0x80000000;
internal const uint GENERIC_WRITE = 0x40000000;
internal const uint FILE_SHARE_READ = 0x00000001;
internal const uint FILE_SHARE_WRITE = 0x00000002;
internal const uint CREATE_NEW = 1;
internal const uint CREATE_ALWAYS = 2;
internal const uint OPEN_EXISTING = 3;
[DllImport("kernel32.dll", SetLastError = true)]
private static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadFile(SafeFileHandle hFile, byte[] lpBuffer, uint nNumberOfBytesToRead, ref uint lpNumberOfBytesRead, IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteFile(SafeFileHandle hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, ref uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
}
I was working with a BeginRead when I saw Hans suggest something, so far it EndRead always returns 0 :/
here is the code for that.
byte[] receive = new byte[11];
IAsyncResult iAR = FS_read.BeginRead(receive, 0, receive.Length, ASyncFileCallBack, receive);
byte[] wildGuess = (byte[])iAR.AsyncState;
Console.WriteLine("Guessing:{0}", BitConverter.ToString(wildGuess));
}
private void ASyncFileCallBack(IAsyncResult result)
{
byte[] buffer = (byte[])result.AsyncState;
int length = FS_read.EndRead(result);
if (length > 0)
Console.WriteLine("Response:{0}", BitConverter.ToString(buffer, 0, length));
else
Console.WriteLine("No Resposne");
}
The guessing always just spits out 11 0's almost immediatly. Shortly after "No Response" is put up on the Console.
I am working with a legacy file format.
The file is created using unmanaged C++ that utilizes the WinBase.h CreateFile() & WriteFile() functions (found in the kernel32.dll).
I have been using P/Invoke interop to access these native functions like so:
[DllImport("kernel32.dll")]
public static extern bool WriteFile(
IntPtr hFile,
byte[] lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
[In] ref NativeOverlapped lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteFileEx(
IntPtr hFile,
byte[] lpBuffer,
uint nNumberOfBytesToWrite,
[In] ref NativeOverlapped lpOverlapped,
WriteFileCompletionDelegate lpCompletionRoutine);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateFile(
string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
public delegate void WriteFileCompletionDelegate(
UInt32 dwErrorCode,
UInt32 dwNumberOfBytesTransfered,
ref NativeOverlapped lpOverlapped);
The issue with this is when I call WriteFile(), the file is always overwritten by the proceeding call.
Preferable I would like to use a compatible .NET equivalent that would allow me to produce the exact same format of output.
The C++ code looks like so: (WORKING)
HANDLE hFile = CreateFile(sFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(hFile, &someVar1, sizeof(bool), &dwWritten, NULL);
WriteFile(hFile, &someVar1, sizeof(long), &dwWritten, NULL);
WriteFile(hFile, &someVar2, sizeof(bool), &dwWritten, NULL);
WriteFile(hFile, sStr.GetBuffer(0), dwStrLen*sizeof(TCHAR), &dwWritten, NULL);
CloseHandle(hFile);
The C# is as follows: (OVERWRITES PREVIOUS WRITE i.e. will output file will contain only 'T')
{
var hFile = COMFileOps2.CreateFile(FILE_NAME, (uint) COMFileOps2.FILE_GENERIC_WRITE,
COMFileOps2.FILE_SHARE_WRITE, IntPtr.Zero, COMFileOps2.CREATE_ALWAYS,
COMFileOps2.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
var natOverlap = new NativeOverlapped();
COMFileOps2.WriteFileEx(hFile, new byte[] {(byte) 't'}, 1, ref natOverlap, Callback);
COMFileOps2.WriteFileEx(hFile, new byte[] { (byte)'e' }, 1, ref natOverlap, Callback);
COMFileOps2.WriteFileEx(hFile, new byte[] { (byte)'s' }, 1, ref natOverlap, Callback);
COMFileOps2.WriteFileEx(hFile, new byte[] { (byte)'T' }, 1, ref natOverlap, Callback);
COMFileOps2.CloseHandle(hFile);
}
private static void Callback(uint dwerrorcode, uint dwnumberofbytestransfered, ref NativeOverlapped lpoverlapped)
{
throw new NotImplementedException();
}
UPDATE: The following C# code will write out "Test":
uint written;
uint position = 0;
var natOverlap0 = new NativeOverlapped();
COMFileOps.WriteFile(hFile, new byte[] {(byte) 'T'}, 1, out written, ref natOverlap0);
position += written;
var natOverlap1 = new NativeOverlapped {OffsetLow = (int) position};
COMFileOps.WriteFile(hFile, new byte[] { (byte)'e' }, 1, out written, ref natOverlap1);
position += written;
var natOverlap2 = new NativeOverlapped { OffsetLow = (int)position };
COMFileOps.WriteFile(hFile, new byte[] { (byte)'s' }, 1, out written, ref natOverlap2);
position += written;
var natOverlap3 = new NativeOverlapped { OffsetLow = (int)position };
COMFileOps.WriteFile(hFile, new byte[] { (byte)'t' }, 1, out written, ref natOverlap3);
COMFileOps.CloseHandle(hFile);
Thanks.
WriteFileEx only runs asynchronously, you must provide a SEPARATE instance of OVERLAPPED for each pending call, and you must setup the OVERLAPPED members, such as the file offset. Then you can't call CloseHandle until all the operations finish. And using a local variable for OVERLAPPED and letting it go out of scope? Your data getting overwritten is the least of the things that can go wrong with the code you show.
So that's why your code doesn't work. I don't know why you switched from WriteFile to WriteFileEx in the first place. In addition, calling the Win32 API from C# is quite inconvenient, although occasionally necessary. But first see if the .NET File APIs do what you need.
Since .NET File APIs tend to work with either strings (in textmode, watch for newline conversions and such) or arrays of bytes, you need to turn your other variables into byte[]. The BitConverter class is your friend here.
You didn't explain what format you are trying to handle but isn't File.WriteAllText sufficient?
File.WriteAllText("someFile.txt", "some format");
For binary files you could use File.WriteAllBytes:
File.WriteAllBytes("someFile.bin", new byte[] { 0x1, 0x2, 0x3 });
Look at the System.IO.File and System.IO.FileInfo classes they both provide the methods you are looking for.
There's nothing particularly special about the raw API calls. Just get a System.IO.FileStream and call Write on it. (One way to get the FileStream is to first acquire a System.IO.File first.