Problem with Rapi. EnumFiles

Jul 13, 2009 at 9:01 AM

Good afternoon.

I have started to use recently OpenNETCF.Desktop. Communication also has faced one unpleasant problem. When I try to receive the list of files from the device often enough I receive an exception "An unhandled exception of type ' System. ExecutionEngineException ' occurred in OpenNETCF.Desktop. Communication.dll". It arises approximately through time. Can sometimes work quite normally. For me it is impossible to avoid this error. As I cannot catch it it in a construction try, catch.

More low I result a code piece.

_myRapi.Connect(true);
     if (_myRapi.Connected)
        {
                 try
                 {
                       lst = _myRapi.EnumFiles("*.*");
                 }
                   catch (System.Exception ex)
                   {
                          MessageBox.Show(ex.Message);
                     }
          }

 

Please, prompt that I do not correctly. And how it can be avoided? Thanks.

Jul 14, 2009 at 9:22 AM

I was able to reproduce the error but it occured pretty random after several calls to Rapi.EnumFiles().

It seems to have something todo with the CeFindNextFile() call in EnumFiles();

Maybe something is going wrong with the FileInformation class beeing passed as an argument (no sequential data layout ?).

However, changing the P/Invoke signature of CeFindNextFile() to

[DllImport("rapi.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern bool CeFindNextFile(int handle, ref CE_FIND_DATA lpFindFileData);

and implenting it appropriately seemed to fix the problem.

Define  CE_FIND_DATA as followed:

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
 public struct CE_FIND_DATA {
  uint dwFileAttributes;
  System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
  System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
  System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
  uint nFileSizeHigh;
  uint nFileSizeLow;
  uint dwOID;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
  public string cFileName;
 }

You may want to wrap the struct to FileInformation for comfort.

Jul 14, 2009 at 9:48 AM

Thanks big for the answer.

I have changed CeFindNextFile and have added CE_FIND_DATA. But now for me does not work EnumFiles.
I have an error in a place
while (CeFindNextFile (hFile, fi)! = 0)

In a place "hFile" it - Error    2    Argument '1': cannot convert from 'System.IntPtr' to 'int'    D:\Downloads\.Net\OpenNETCF.Desktop.Communication\RAPI.cs    956    39    OpenNETCF.Desktop.Communication

And In a place "fi" it - Error    3    Argument '2': cannot convert from 'ref OpenNETCF.Desktop.Communication.FileInformation' to 'ref OpenNETCF.Desktop.Communication.RAPI.CE_FIND_DATA'    D:\Downloads\.Net\OpenNETCF.Desktop.Communication\RAPI.cs    956    50    OpenNETCF.Desktop.Communication

It can be necessary to add something else?

Thanks.

Jul 14, 2009 at 11:33 AM

Well yes, EnumFiles() needs to be rewritten if you want to use that signature.

But i think i found the problem with the previous implementation. Since using CE_FIND_DATA to request the data worked, i took another look at the FileInformation class.

The problem probably was that it contains a byte[512] array to hold the data but CeFindNextFile() (and CeFindFirstFile()) seem to copy 560 bytes on each operation. Revert the P/Invoke signature to the original one and in class FileInformation change

private byte[] data = new byte[512];

to

private byte[] data = new byte[560];

Please report back if that works, i don't have time to test it ;)

Jul 14, 2009 at 11:50 AM

You were right. Now it really works. Many thanks.

I only wished to ask. What would you advise to use? Your first variant (I have already rewrite procedure EnumFiles) or corrected new byte [560]?

Once again thanks.

Jul 14, 2009 at 2:22 PM

Ah good to hear that it helped :)

Hmm, public static extern bool CeFindNextFile(int handle, ref CE_FIND_DATA lpFindFileData) is the signature that is documented on MSDN but i don't see why the original implementation shouldn't be safe to use. And its easier to handle since it directly wraps the data in a class where the data can be accesed like needed.

I just know the P/Invoke basics but passing the "struct by ref" and passing the underlying byte[] of the FileInformation class should be basically the same thing in that case.

Rev

Jul 14, 2009 at 2:26 PM

Well. I have understood. Once again many thanks for the help.