E
Einar Høst
Hi,
I'm reading data from a tape device using p/invoke. It's working pretty
well, but when I'm trying to get data about the tape device, I'm doing
something wrong. I believe it has something to do with the struct I'm
passing in, but I just can't figure out what. Any help would be much
appreciated. I'm an absolute interop newbie, so please bear with me.
The Win32 API signature looks like this:
DWORD GetTapeParameters(
HANDLE hDevice,
DWORD dwOperation,
LPDWORD lpdwSize,
LPVOID lpTapeInformation
);
I've translated that into the following import signature:
[DllImport("kernel32.dll", SetLastError=true)]
static extern uint GetTapeParameters(
IntPtr hDevice, // Handle to tape device.
uint dwOperation, // Parameter type (media/drive).
out uint lpdwSize, // Size of parameter buffer.
IntPtr lpTapeInformation // Pointer to parameter struct.
);
The media parameter struct originally looks like this:
typedef struct _TAPE_GET_MEDIA_PARAMETERS {
LARGE_INTEGER Capacity;
LARGE_INTEGER Remaining;
DWORD BlockSize;
DWORD PartitionCount;
BOOLEAN WriteProtected;
} TAPE_GET_MEDIA_PARAMETERS,
* PTAPE_GET_MEDIA_PARAMETERS;
Consulting winnt.h (I've never programmed Windows pre-.NET), I found that
LARGE_INTEGER was a 64-bit signed integer, DWORD a 32-bit unsigned integer,
and BOOLEAN a single byte. So I translated the struct into the following:
[StructLayout(LayoutKind.Sequential)]
internal struct MediaParameters
{
internal Int64 Capacity;
internal Int64 Remaining;
internal UInt32 BlockSize;
internal UInt32 PartitionCount;
internal Byte WriteProtected;
}
I try to make all this work from a C# wrapper method that calls the imported
Win32 API method.
internal MediaParameters GetTapeMediaParameters()
{
// Keep object alive for the remainder of this method.
GC.KeepAlive(this);
MediaParameters param = new MediaParameters();
IntPtr paramPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(param));
Marshal.StructureToPtr(param, paramPtr, false);
uint size;
// Call imported Win32 API method to populate struct.
// 0 specifies media parameters (as opposed to drive parameters).
SystemErrorCode code = (SystemErrorCode) GetTapeParameters(_hTape, 0, out
size, paramPtr);
Debug.Assert(code == SystemErrorCode.NO_ERROR,
"Failed trying to get tape media parameters!",
"Error code: " + code.ToString());
// Should I call Marshal.PtrToStructure here?
Marshal.FreeCoTaskMem(paramPtr);
}
However, the Assert statement fails, giving me system error code 234
(ERROR_MORE_DATA).
If someone could help me, I'd be very very grateful!
Regards,
Einar
I'm reading data from a tape device using p/invoke. It's working pretty
well, but when I'm trying to get data about the tape device, I'm doing
something wrong. I believe it has something to do with the struct I'm
passing in, but I just can't figure out what. Any help would be much
appreciated. I'm an absolute interop newbie, so please bear with me.
The Win32 API signature looks like this:
DWORD GetTapeParameters(
HANDLE hDevice,
DWORD dwOperation,
LPDWORD lpdwSize,
LPVOID lpTapeInformation
);
I've translated that into the following import signature:
[DllImport("kernel32.dll", SetLastError=true)]
static extern uint GetTapeParameters(
IntPtr hDevice, // Handle to tape device.
uint dwOperation, // Parameter type (media/drive).
out uint lpdwSize, // Size of parameter buffer.
IntPtr lpTapeInformation // Pointer to parameter struct.
);
The media parameter struct originally looks like this:
typedef struct _TAPE_GET_MEDIA_PARAMETERS {
LARGE_INTEGER Capacity;
LARGE_INTEGER Remaining;
DWORD BlockSize;
DWORD PartitionCount;
BOOLEAN WriteProtected;
} TAPE_GET_MEDIA_PARAMETERS,
* PTAPE_GET_MEDIA_PARAMETERS;
Consulting winnt.h (I've never programmed Windows pre-.NET), I found that
LARGE_INTEGER was a 64-bit signed integer, DWORD a 32-bit unsigned integer,
and BOOLEAN a single byte. So I translated the struct into the following:
[StructLayout(LayoutKind.Sequential)]
internal struct MediaParameters
{
internal Int64 Capacity;
internal Int64 Remaining;
internal UInt32 BlockSize;
internal UInt32 PartitionCount;
internal Byte WriteProtected;
}
I try to make all this work from a C# wrapper method that calls the imported
Win32 API method.
internal MediaParameters GetTapeMediaParameters()
{
// Keep object alive for the remainder of this method.
GC.KeepAlive(this);
MediaParameters param = new MediaParameters();
IntPtr paramPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(param));
Marshal.StructureToPtr(param, paramPtr, false);
uint size;
// Call imported Win32 API method to populate struct.
// 0 specifies media parameters (as opposed to drive parameters).
SystemErrorCode code = (SystemErrorCode) GetTapeParameters(_hTape, 0, out
size, paramPtr);
Debug.Assert(code == SystemErrorCode.NO_ERROR,
"Failed trying to get tape media parameters!",
"Error code: " + code.ToString());
// Should I call Marshal.PtrToStructure here?
Marshal.FreeCoTaskMem(paramPtr);
}
However, the Assert statement fails, giving me system error code 234
(ERROR_MORE_DATA).
If someone could help me, I'd be very very grateful!
Regards,
Einar