From: djnewman on 5 May 2010 15:51 Hi, First let me state that I posted this to Technet and got no help there. I know this is not the best code but I would like to get some pointers. I've been working on controlling a tape library using IOCTL commands. I'm working in C# and so far I can get the product data and the changer device status. I would now like to send commands to the changer to move the transport so I can move media. Obviously, I'm facing an uphill battle using C type control structures with C#, but I'm marshalling the data and it appears to be correct when I look at it in memory. I do have the IOCTL_CHANGER_GET_PARAMETERS and IOCTL_CHANGER_GET_PRODUCT_DATA working. I do not intend to use the overlapped process until I get all of these working in a non threaded process. The problem is that I'm getting Error 1 - Incorrect function when I call either IOCTL_CHANGER_REINITIALIZE_TRANSPORT or IOCTL_CHANGER_SET_POSITON. The changer is open. These are the first 2 commands I have tried becuse they seem simple. Below is a snippet to show the command, structure and call. I know this would be easier in C or C++, but I'm doing my best to learn C# and hard problems are the best way. This is running on a Windows Server 2003 R2 system. The library is an HP SURESTOREDAT 24x6 and the library and tape drive work normally with NTBackup. I have stopped the removable storage service. I am coding in C# using VS 2010 in .Net 4.0 as a windows forms application, but the below code is in a class by itself. The structures are taken from _ntddchgr.h and the types converted to managed types where it made sense. Any help is appreciated. Dave Newman djnewman(a)pacbell.net [Flags] private enum EIOControlCode : uint { // STORAGE StorageBase = EFileDevice.MassStorage, StorageCheckVerify = (StorageBase << 16) | (0x0200 << 2) | EMethod.Buffered | (FileAccess.Read << 14), StorageCheckVerify2 = (StorageBase << 16) | (0x0200 << 2) | EMethod.Buffered | (0 << 14), // FileAccess.Any StorageMediaRemoval = (StorageBase << 16) | (0x0201 << 2) | EMethod.Buffered | (FileAccess.Read << 14), StorageEjectMedia = (StorageBase << 16) | (0x0202 << 2) | EMethod.Buffered | (FileAccess.Read << 14), StorageLoadMedia = (StorageBase << 16) | (0x0203 << 2) | EMethod.Buffered | (FileAccess.Read << 14), StorageLoadMedia2 = (StorageBase << 16) | (0x0203 << 2) | EMethod.Buffered | (0 << 14), StorageReserve = (StorageBase << 16) | (0x0204 << 2) | EMethod.Buffered | (FileAccess.Read << 14), StorageRelease = (StorageBase << 16) | (0x0205 << 2) | EMethod.Buffered | (FileAccess.Read << 14), StorageFindNewDevices = (StorageBase << 16) | (0x0206 << 2) | EMethod.Buffered | (FileAccess.Read << 14), StorageEjectionControl = (StorageBase << 16) | (0x0250 << 2) | EMethod.Buffered | (0 << 14), StorageMcnControl = (StorageBase << 16) | (0x0251 << 2) | EMethod.Buffered | (0 << 14), StorageGetMediaTypes = (StorageBase << 16) | (0x0300 << 2) | EMethod.Buffered | (0 << 14), StorageGetMediaTypesEx = (StorageBase << 16) | (0x0301 << 2) | EMethod.Buffered | (0 << 14), StorageResetBus = (StorageBase << 16) | (0x0400 << 2) | EMethod.Buffered | (FileAccess.Read << 14), StorageResetDevice = (StorageBase << 16) | (0x0401 << 2) | EMethod.Buffered | (FileAccess.Read << 14), StorageGetDeviceNumber = (StorageBase << 16) | (0x0420 << 2) | EMethod.Buffered | (0 << 14), StoragePredictFailure = (StorageBase << 16) | (0x0440 << 2) | EMethod.Buffered | (0 << 14), StorageObsoleteResetBus = (StorageBase << 16) | (0x0400 << 2) | EMethod.Buffered | ((FileAccess.Read | FileAccess.Write) << 14), StorageObsoleteResetDevice = (StorageBase << 16) | (0x0401 << 2) | EMethod.Buffered | ((FileAccess.Read | FileAccess.Write) << 14), // CHANGER ChangerBase = EFileDevice.Changer, ChangerGetParameters = (ChangerBase << 16) | (0x0000 << 2) | EMethod.Buffered | (FileAccess.Read << 14), ChangerGetStatus = (ChangerBase << 16) | (0x0001 << 2) | EMethod.Buffered | (FileAccess.Read << 14), ChangerGetProductData = (ChangerBase << 16) | (0x0002 << 2) | EMethod.Buffered | (FileAccess.Read << 14), ChangerSetAccess = (ChangerBase << 16) | (0x0004 << 2) | EMethod.Buffered | ((FileAccess.Read | FileAccess.Write) << 14), ChangerGetElementStatus = (ChangerBase << 16) | (0x0005 << 2) | EMethod.Buffered | ((FileAccess.Read | FileAccess.Write) << 14), ChangerInitializeElementStatus = (ChangerBase << 16) | (0x0006 << 2) | EMethod.Buffered | (FileAccess.Read << 14), ChangerSetPosition = (ChangerBase << 16) | (0x0007 << 2) | EMethod.Buffered | (FileAccess.Read << 14), ChangerExchangeMedium = (ChangerBase << 16) | (0x0008 << 2) | EMethod.Buffered | (FileAccess.Read << 14), ChangerMoveMedium = (ChangerBase << 16) | (0x0009 << 2) | EMethod.Buffered | (FileAccess.Read << 14), ChangerReinitializeTarget = (ChangerBase << 16) | (0x000A << 2) | EMethod.Buffered | (FileAccess.Read << 14), ChangerQueryVolumeTags = (ChangerBase << 16) | (0x000B << 2) | EMethod.Buffered | ((FileAccess.Read | FileAccess.Write) << 14) } [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct CHANGER_ELEMENT { /// ELEMENT_TYPE->_ELEMENT_TYPE public ELEMENT_TYPE ElementType; /// DWORD->unsigned int public uint ElementAddress; } [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct CHANGER_SET_POSITION { // Indicates which transport to move. public CHANGER_ELEMENT Transport; // Indicates the final destination of the transport. public CHANGER_ELEMENT Destination; // Indicates whether the media currently carried by Transport, should be flipped. public int Flip; //!0 == true 0 == false } [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true)] internal static extern bool DeviceIoControl( [System.Runtime.InteropServices.In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice, [System.Runtime.InteropServices.In] int dwIoControlCode, [System.Runtime.InteropServices.In] IntPtr lpInBuffer, [System.Runtime.InteropServices.In] int nInBufferSize, [System.Runtime.InteropServices.Out] IntPtr lpOutBuffer, [System.Runtime.InteropServices.In] int nOutBufferSize, out int lpBytesReturned, [System.Runtime.InteropServices.In] IntPtr lpOverlapped ); public Boolean ChangerSetPosition(uint position, Boolean flip) { bool status = false; if (hDevice == null) return false; IntPtr pChgSetPos = IntPtr.Zero; CHANGER_SET_POSITION chSetPos = new CHANGER_SET_POSITION(); CHANGER_ELEMENT transp = new CHANGER_ELEMENT(); CHANGER_ELEMENT dest = new CHANGER_ELEMENT(); transp.ElementType = ELEMENT_TYPE.ChangerTransport; //This should be the element address the transport wants to be called from ChangerGetParms transp.ElementAddress = ChangerParms.FirstTransportNumber; dest.ElementType = ELEMENT_TYPE.ChangerSlot; dest.ElementAddress = position; //move it to where? chSetPos.Transport = transp; chSetPos.Destination = dest; if (flip) chSetPos.Flip = 1; //C true else chSetPos.Flip = 0; //C false Type structType = typeof(CHANGER_SET_POSITION); int structSize = System.Runtime.InteropServices.Marshal.SizeOf(structType); nInBufferSize = (uint)structSize; //This is now a pointer to a buffer the size of of CHANGER_SET_POSITION pChgSetPos = System.Runtime.InteropServices.Marshal.AllocHGlobal(structSize); // move the above structure into the pointer location //as the structure is really just 5 ints we'll copy it using offsets. int x = 0; System.Runtime.InteropServices.Marshal.WriteInt32(pChgSetPos, x * sizeof(Int32), (int)chSetPos.Transport.ElementType); x = 1; System.Runtime.InteropServices.Marshal.WriteInt32(pChgSetPos, x * sizeof(Int32), (int)chSetPos.Transport.ElementAddress); x = 2; System.Runtime.InteropServices.Marshal.WriteInt32(pChgSetPos, x * sizeof(Int32), (int)chSetPos.Destination.ElementType); x = 3; System.Runtime.InteropServices.Marshal.WriteInt32(pChgSetPos, x * sizeof(Int32), (int)chSetPos.Destination.ElementAddress); x = 4; System.Runtime.InteropServices.Marshal.WriteInt32(pChgSetPos, x * sizeof(Int32), (int)chSetPos.Flip); //@ this point, the unmanaged pointer data should match the changer_set_position struct. status = DeviceIoControl( hDevice, (int)EIOControlCode.ChangerSetPosition, pChgSetPos, (int)nInBufferSize, IntPtr.Zero, 0, out lpBytesReturned, IntPtr.Zero ); //do something with the result. //Nothing here yet because the call to DeviceIoControl returns false. //free the memory. System.Runtime.InteropServices.Marshal.FreeHGlobal(pChgSetPos); pChgSetPos = IntPtr.Zero; lastError = GetLastError(); lastErrorMessage = GetLastErrorMessage(lastError); return status; }
|
Pages: 1 Prev: disinclude from xml serialization Next: Microsoft closing their newsgroups?? |