Codwiz51's Wiki

More Porting to C++/CLI

Modified: 2008/07/03 04:31 by codewiz51 - Categorized as: CLI
Here is another routine, ported to C++/CLI from OpenNetCF. This routine was much quicker using mixed mode code. The reason? A managed structure was passed to an API call in a loop.

Here's the C# code that we ported:

[DllImport("rapi.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal extern static IntPtr CeFindFirstFile(string lpFileName, byte[] lpFindFileData);

[DllImport("rapi.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal static extern int CeFindNextFile(IntPtr hFindFile, byte[] lpFindFileData);

[DllImport("rapi.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal static extern int CeFindClose(IntPtr hFindFile);

/// <summary> 
/// This structure describes a file found by the FindFirstFile or FindNextFile. 
/// </summary> 
/// <seealso cref="M:OpenNETCF.Desktop.Communication.RAPI.EnumFiles(System.String@)"/> 
public class FileInformation //WIN32_FIND_DATA
{
	private byte[] data = new byte[560];

	/// <summary>
	/// Byte representation of FileInformation
	/// </summary>
	public static implicit operator byte[](FileInformation fi)
	{
		return fi.data;
	}

	/// <summary>
	/// File attributes of the file found.
	/// </summary>
	public int FileAttributes
	{
		get
		{
			return BitConverter.ToInt32(data, 0);
		}
	}

	/// <summary>
	/// UTC time at which the file was created.
	/// </summary>
	public DateTime CreateTime
	{
		get
		{
			long time = BitConverter.ToInt64(data, 4);
			return DateTime.FromFileTime(time);
		}
	}

	/// <summary>
	/// UTC time at which the file was last accessed.
	/// </summary>
	public DateTime LastAccessTime
	{
		get
		{
			long time = BitConverter.ToInt64(data, 12);
			return DateTime.FromFileTime(time);
		}
	}

	/// <summary>
	/// UTC time at which the file was modified.
	/// </summary>
	public DateTime LastWriteTime
	{
		get
		{
			long time = BitConverter.ToInt64(data, 20);
			return DateTime.FromFileTime(time);
		}
	}

	/// <summary>
	/// Size, in bytes, of file
	/// </summary>
	public long FileSize
	{
		get
		{
			return BitConverter.ToInt32(data, 28) + (BitConverter.ToInt32(data, 32) << 32);
		}
	}

	/// <summary>
	/// Full name of the file
	/// </summary>
	public string FileName
	{
		get
		{
			return Encoding.Unicode.GetString(data, 40, 256).TrimEnd('\x2A');
		}
	}
}


/// <summary>
/// Provides an ArrayList of FileInformation classes matching the criteria provided in the FileName parameter
/// </summary>
/// <param name="FileName">Long pointer to a null-terminated string that specifies a valid directory or path and filename which can contain wildcard characters (* and ?).</param>
/// <returns>An array of FileInformation objects</returns>
public FileList EnumFiles(string FileName)
{
	CheckConnection();

	FileList fl = null;
	IntPtr hFile = IntPtr.Zero;

	FileInformation fi = new FileInformation();

	hFile = CeFindFirstFile(FileName, fi);

	if(hFile != (IntPtr)INVALID_HANDLE_VALUE)
	{
		fl = new FileList();

		fl.Add(fi);

		fi = new FileInformation();
		while(CeFindNextFile(hFile, fi) != 0)
		{
			fl.Add(fi);
			fi = new FileInformation();
		}

		CeFindClose(hFile);
	}

	return fl;
}

Here is my initial C++/CLI code. It is not efficient, but it works. I'll present the efficient version in another article.

public ref class FileInformation
{
	// Fields
private:
	UInt32 nFileAttributes;
	DateTime dCreationTime;
	DateTime dLastAccessTime;
	DateTime dLastWriteTime;
	UInt32 nFileSizeHigh;
	UInt32 nFileSizeLow;
	UInt32 nOID;
	String^ szFileName;

	// Methods
public:
	// Properties
	property DateTime^ CreateTime
	{
		DateTime^ get(void)
		{
			return dCreationTime;
		}
		void set(DateTime^ value)
		{
			dCreationTime = *value;
		}
	} 

	property UInt32 FileAttributes
	{
		UInt32 get(void)
		{
			return nFileAttributes;
		}
		void set(UInt32 value)
		{
			nFileAttributes = value;
		}
	}

	property String^ FileName
	{
		String^ get(void)
		{
			return szFileName;
		}
		void set(String^ value)
		{
			szFileName = value;
		}
	}

	property long long FileSize
	{
		long long get(void)
		{
			return (((long long) nFileSizeHigh << 32) + nFileSizeLow);
		}
		void set(long long value)
		{
			nFileSizeHigh = (UInt32)(value >> 32);
			nFileSizeLow = (UInt32) (value - ((long long) nFileSizeHigh << 32));
		}
	}

	property DateTime^ LastAccessTime
	{
		DateTime^ get(void)
		{
			return dLastAccessTime;
		}
		void set(DateTime^ value)
		{
			dLastAccessTime = *value;
		}

	}

	property DateTime^ LastWriteTime
	{
		DateTime^ get(void)
		{
			return dLastWriteTime;
		}
		void set(DateTime^ value)
		{
			dLastWriteTime = *value;
		}
	}
};


Here is the primary EnumFiles routine:

FileList^ RAPI::EnumFiles(String^ FileName)
{
	CheckConnection();
	FileList^ ExistingFiles = nullptr;

	pin_ptr pfn = PtrToStringChars(FileName);
	LPCTSTR pFileName = pfn;

	CE_FIND_DATA fi;

	HANDLE hSearch = ::CeFindFirstFile(pFileName, &fi);
	if (INVALID_HANDLE_VALUE != hSearch)
	{
		ExistingFiles = gcnew FileList() ;
		do
		{
			// Convert CE_FIND_DATA to FileInformation
			// TODO Clean this up.
			// I do not need all of the file information structure
			// I can use memcpy to move the data into the FileInformation data buffer.
			FileInformation^ mfi = gcnew FileInformation();
			__int64 c = (((__int64) fi.ftCreationTime.dwHighDateTime) << 32) + (__int64) fi.ftCreationTime.dwLowDateTime;
			mfi->CreateTime = DateTime::FromFileTime(c);
			c = (((__int64) fi.ftLastAccessTime.dwHighDateTime) << 32) + (__int64) fi.ftLastAccessTime.dwLowDateTime;
			mfi->LastAccessTime = DateTime::FromFileTime(c);
			c = (((__int64) fi.ftLastWriteTime.dwHighDateTime) << 32) + (__int64) fi.ftLastWriteTime.dwLowDateTime;
			mfi->LastWriteTime = DateTime::FromFileTime(c);
			mfi->FileSize = (((__int64)fi.nFileSizeHigh << 32) + fi.nFileSizeLow);
			mfi->FileAttributes = fi.dwFileAttributes;
			mfi->FileName = gcnew String(fi.cFileName);
			// Add managed file info to the list
			ExistingFiles->Add(mfi);
		}
		while (::CeFindNextFile(hSearch, &fi));
		
		::CeFindClose(hSearch);
	}
	return ExistingFiles;
}


ScrewTurn Wiki version 2.0.31. Some of the icons created by FamFamFam.