Groups | Blog | Home
all groups > dotnet interop > october 2006 >

dotnet interop : Calling a C legacy function with FILETIME* as parameter


fabrizio.viggiani NO[at]SPAM gmail.com
10/11/2006 7:47:23 AM
I have a dll that exports the following entry point:

STDAPI FileSetDate(HANDLE hFile, FILETIME* pft);

I need to call this function from C#.

I define the function as follows:
[DllImport("Some.dll")]
public static extern int FileSetDate(IntPtr handle, ref
System.Runtime.InteropServices.ComTypes.FILETIME fileTime);

then I call it this way:

FileInfo fi = new FileInfo(fileToSubmit);
System.Runtime.InteropServices.ComTypes.FILETIME ft;
long hFT1 = fi.LastWriteTime.ToFileTimeUtc();
ft.dwLowDateTime = (int)(hFT1 & 0xFFFFFFFF);
ft.dwHighDateTime = (int)(hFT1 >> 32);
FileSetDate(handle, ref ft);

At this point I get the following exception:

System.AccessViolationException was unhandled
Message="Attempted to read or write protected memory. This is often
an indication that other memory is corrupt."
Source="ManagedApiTest"
StackTrace:
at ConsoleApplication1.Program.FileSetDate(IntPtr handle,
FILETIME& fileTime)
at ConsoleApplication1.Program.Main(String[] args) in
C:\Documents and Settings\Fabrizio\My Documents\Visual Studio
2005\Projects\Net\ManagedApi\ManagedApiTest\Program.cs:line 74
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[]
args)
at System.AppDomain.ExecuteAssembly(String assemblyFile,
Evidence assemblySecurity, String[] args)
at
Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object
state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

The first argument is OK because I use it in some legacy calls before
and they all go well.

Is there someone that can help me in calling this function?


Fabrizio
William DePalo [MVP VC++]
10/11/2006 7:38:12 PM
[quoted text, click to view]

OK. What's your position on unsafe code? If you are OK with it, it's a
simple matter of passing the address of a FILETIME structure to the native
code.

Now, I don't have your legacy function to test with here, but Windows
provides a kernel function to set last file create, access and write times
which, like your legacy function takes a pointer to a FILETIME structure.
This little hack below shows how to do the job.

Regards,
Will

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace Fabrizio
{
class Class1
{

[STAThread]
static void Main(string[] args)
{
DateTime dt = new DateTime(2006, 1, 1, 0, 0, 0);
FileStream fs = File.Open("c:\\test.dat", FileMode.Open);

AdjustFileTime(fs, dt);
}

[ DllImport("kernel32.dll", SetLastError = true) ]
public unsafe static extern int
SetFileTime(IntPtr handle, long *create, long *access, long *write);

static unsafe void AdjustFileTime(FileStream fs, DateTime dt)
{
long ft;

ft = dt.ToFileTimeUtc();
SetFileTime(fs.Handle, &ft, &ft, &ft);
}

}
}





fabrizio.viggiani NO[at]SPAM gmail.com
10/12/2006 5:37:03 AM
Thanks for your help.
It helped me to discover a different error in my code (I was passing a
different handle to function).
After having used the rigth handle and followed you suggestion now it
works.
Further it also work with
System.Runtime.InteropServices.ComTypes.FILETIME so I do not need to
use unsafe code (that's better).

Thanks again!

Fabrizio


[quoted text, click to view]
AddThis Social Bookmark Button