1

In a WCE app I’m looking for a way to copy a file (I only have to file name/path of it) to a specific memory address. The file is rather large’ish, ~40MB, so with limited resources, I was hoping to avoid reading the whole file into memory (byte array), by using the answer from this post: Copy data from from IntPtr to IntPtr

[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] 
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); 
static void Main() 
{ 
    const int size = 200; 
    IntPtr memorySource = Marshal.AllocHGlobal(size); 
    IntPtr memoryTarget = Marshal.AllocHGlobal(size);
    CopyMemory(memoryTarget,memorySource,size); 
}

That leaves me to 2 problems. First of all: How do I assign a memory address to an IntPtr?, kind of like: int* startAddr = &0x00180000.

And secondly: How do I obtain the memory address of a file?

With these two questions answered, my code would look something like:

[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
private unsafe void CopyFile()
{
    try
    {
        fixed (Int32* startAddr = /*0x00180000*/)
        {
            fixed(Int32* fileAddr = /*Memory Address of file*/)
            {
                CopyMemory(new IntPtr(startAddr), new IntPtr(fileAddr), (uint)new FileInfo("File name").Length);
            }
        }
    }
    catch { }
}

Would that be a valid way of going about it?

Any help would be greatly appreciated. Thanks in advance!!

Update: CopyMemory is not the way of going about it. So please disregard.

Also, Sorry for not being clearer. Basically I want to move a file to the start of a partition on disk. I thought that IntPtr could also point to a disk address, but in retrospect I can see that of course it can not. Anyway sorry for the confusion.

Community
  • 1
  • 1
Viking
  • 293
  • 4
  • 12
  • You can simply use the ctor of `IntPtr` to assign it an address: `new IntPtr(0x00180000);`, for the second part, the file doesn't have a memory address up until the point you load it - it's on disk, not in RAM. – aevitas Nov 18 '14 at 09:48
  • @aevitas Of course. Thanks a lot. No you are right. CopyMemory might not be the best way to go about it. – Viking Nov 18 '14 at 09:57

1 Answers1

1

Files don't have addresses in memory. So what you are asking for is something of a non-sequitur.

So far as I can tell, you don't need any unsafe code at all. You don't need to call CopyMemory. And you don't need to load the entire file in one go and then copy. What you can do is as follows:

  1. Use a standard file stream to read the file.
  2. Read the file in small chunks into a small buffer. Just to be concrete, you might choose to read the file in 8KB chunks.
  3. Each time you read a chunk of the file, copy it to the unmanaged memory location with a call to Marshal.Copy.

The code might look like this:

static void CopyStreamToMemory(Stream stream, IntPtr addr, int bufferSize)
{
    byte[] buffer = new byte[bufferSize];
    long bytesLeft = stream.Length - stream.Position;
    while (bytesLeft > 0)
    {
        int bytesToCopy = (int)Math.Min(bufferSize, bytesLeft);
        stream.Read(buffer, 0, bytesToCopy);
        Marshal.Copy(buffer, 0, addr, bytesToCopy);
        addr += bytesToCopy;
        bytesLeft -= bytesToCopy;
    }
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • That would be a nice simple way of doing it. Haven’t thought of that. I’ll give it a try, and post whatever I’ll come up with. Thanks a lot. – Viking Nov 18 '14 at 10:02
  • BTW, so what you are saying is that an IntPtr can only point to RAM memory? So 'new IntPtr(0x00180000)' would not give me a pointer to the disk at address 0x00180000? – Viking Nov 18 '14 at 10:17
  • That is correct. Pointers refer to memory. Files can be mapped into memory but that's a rather complex tasks. And not what you need here I believe. – David Heffernan Nov 18 '14 at 10:17
  • I'd certainly use a `Stream` over low level pointer stuff, unless you have a benchmark that shows that this leads to unacceptable performance. The risk of memory corruption in low level parsing code is quite high and often leads to severe security vulnerabilities. – CodesInChaos Nov 18 '14 at 10:20
  • 1
    @David Heffernan. Actually, that is exactly what I want. Basically I want to move a file to the start of a partition on disk. Sorry for not being clearer on that. I’ll update the OP. – Viking Nov 18 '14 at 10:26
  • I don't think we need the question to change. It was clear enough already. What you describe in that comment is a different question. – David Heffernan Nov 18 '14 at 10:28
  • @DavidHeffernan I’ll mark your response as an answer, since you answered my question, although my question was not what I wanted. I’m beginning to believe that what I want is not possible - but I’ll create a new question for that. Again thanks a lot for taking you time to try to help me. – Viking Nov 18 '14 at 11:50
  • OK. I think you are right to doubt that what you want is possible. Move the file to the start of the partition? Well, what if there's something there already? And how will you update the file system meta data. I would be surprised if direct disk access is really what you need. Why do you feel you want to move the file on the disk? – David Heffernan Nov 18 '14 at 12:04
  • @DavidHeffernan The scenario is that, upon booting up my device, the bootloader unzips a WCE image. This image is stored in a certain kernel partition. This image is not used runtime, so it should be possible to override it runtime. And that is exactly what I want to do, and I don’t care what is there already. Does that makes sense? – Viking Nov 18 '14 at 12:36
  • I don't really understand that, but direct access of the disk is possible. You should start with the `CreateFile` API. The sort of coding is possible from C# but is easier from native code. – David Heffernan Nov 18 '14 at 12:42
  • OK - again thanks a lot. I'll most definitely have a look at that API. – Viking Nov 18 '14 at 13:01