Search code examples
c#windows-cemarshalling

c# FindFirstDevice Marshaling


I have a c# application running on winCE 6.0 version. I need to unload/reload the SD card driver at run time. I am attempting to do this via calling FindFirstDevice, then DeactivateDevice/ActivateDeviceEX calls. My problem is the FindFirstDevice() call always fails. I believe it to be a problem with the way I am marshalling the second parameter to it. Can anyone tell me what I am doing wrong? Here is the code:

  [DllImport("coredll.dll", SetLastError = true)]
  public static extern int FindFirstDevice(DeviceSearchType
  searchType, IntPtr searchParam, ref DEVMGR_DEVICE_INFORMATION pdi);

  public bool MountSDCardDrive(string mRegPath)
  {
     const int INVALID_HANDLE_VALUE = -1;

     int handle = INVALID_HANDLE_VALUE;
     DeviceSearchType searchType = DeviceSearchType.DeviceSearchByDeviceName;

     DEVMGR_DEVICE_INFORMATION di = new DEVMGR_DEVICE_INFORMATION();
     di.dwSize = (uint)Marshal.SizeOf(typeof(DEVMGR_DEVICE_INFORMATION));

     string searchParamString = "*";
     IntPtr searchParam = Marshal.AllocHGlobal(searchParamString.Length);
     Marshal.StructureToPtr(searchParamString, searchParam, false);

     handle = FindFirstDevice(searchType, searchParam, ref di);
     if (handle == INVALID_HANDLE_VALUE)
     {
        // Failure - print error
        int hFindFirstDeviceError = Marshal.GetLastWin32Error();

        using (StreamWriter bw = new StreamWriter(File.Open(App.chipDebugFile, FileMode.Append)))
        {
           String iua = "DevDriverInterface: error from FindFirstDevice: " + hFindFirstDeviceError.ToString();
           bw.WriteLine(iua);
        }
        return false;
     }

... (rest of code)

If I change the line Marshal.StructureToPtr(searchParamString, searchParam, false); to searchParam = Marshal.StringToBSTR(searchParamString);"I end up with error 1168 (ERROR_NOT_FOUND) instead of 18 (no more files).

Note my intent is to use a searchParamString of "SDH1" when I get this working. I am currently using searchParamString of "*" in order to see something returned and rule out the particular string value.

Thanks for any help you can give - Lynn


Solution

  • FindFirstDevice must be used together with FindNextDevice (it uses the handle returned by FindFirstDevice as its first argument and returns TRUE if another device has been found) because you have to iterate all the devices to find the good one... and in order to to this you have to compare szLegacyName values in your structure.

    Remove:

    IntPtr searchParam = Marshal.AllocHGlobal(searchParamString.Length);
    

    And use only:

    IntPtr searchParam = Marshal.StringToBSTR(searchParamString);
    

    As that method already provides to allocate necessary memory (remember to use Marshal.FreeBSTR() in a finally block to free that memory space after).

    Your structure should look like:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    public struct DEVMGR_DEVICE_INFORMATION 
    { 
        public UInt32 dwSize; 
        public IntPtr hDevice; 
        public IntPtr hParentDevice; 
    
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)] 
        public String szLegacyName; 
    
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
        public String szDeviceKey; 
    
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
        public String szDeviceName; 
    
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
        public String szBusName; 
    }