WriteFile errors

I'm having problems with WriteFile function. Sometimes it happens that the function fails with GetLastError() code 87(ERROR_INVALID_PARAMETER). Here's my code:
1
2
3
4
5
6
7
8
9
10
11
int DiskIO::write(void *buff,uint32_t buffer_size)
{
DWORD dwWritten=0;

if(!WriteFile(hDisk,buff,buffer_size,&dwWritten,0) || dwWritten!=buffer_size)
  {
     return ERR_WRITE;
  }

return 0;
}

It's strange because WriteFile() fails only when I call DiskIO::write from another statically linked DLL. I have no idea what could be wrong. Could be that caused by different calling conventions or structure packing? I'm out of ideas...

Thanks for help.
Check your buff pointer. If you allocate memory in one DLL and then use or free the pointer in another DLL, which are both statically linked against CRT, it could happend that you will NOT get the same memory address when use the pointer, which could lead to "undefined behavior.

There is a Microsoft article which advice against statically link CRT across DLL boundaries (not remember the link right now).
You don't show how you open your file or call the function DiskIO::write()

Is hDisk a member of a DiskIO class?

Are you exposing the whole of the DiskIO class to the client DLL, or are you using a C function / vtable class as an interface?

Andy
Check your buff pointer. If you allocate memory in one DLL and then use or free the pointer in another DLL, which are both statically linked against CRT, it could happend that you will NOT get the same memory address when use the pointer, which could lead to "undefined behavior.
I checked the pointer and it's ok.

You don't show how you open your file or call the function DiskIO::write()
hDisk=CreateFile("\\\\.\\PhysicalDriveX",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);

I did some research and it seems that WriteFile fails when the buffer_size is not divisible by 512.
I didn't realised that you were accessing the physical drive (sorry - people's variable names are rather varied on this site, so I didn't attach any particular signifance to "hDrive")

This is something I've not had cause to use, so there is not much more I can add. But I do recognize that 512 = BytesPerSector for my hard drive.

I assume you have checked the handle as well as the buffer, and that the class is exporting OK.

Andy

P.S. I haven't seen the form "\\.\PhysicalDriveX" with a drive; I do know it's required when using a disk number, but I would have just used "\\.\X:". (I have never written to a drive, but I have opened them so I can dump the file records for diagnostic purposes)
Last edited on
I would have just used "\\.\X:"
\\.\X: is not what I need. The difference is that \\.\PhysicalDriveX is used to open a whole disk while \\.\X: can be used to open a partition.

I came up with this solution:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int DiskIO::write(void *buff,uint32_t buffer_size)
{
DWORD dwWritten=0;

if(buffer_size%disk_geometry.bps==0)
  {
    if(!WriteFile(hDisk,buff,buffer_size,&dwWritten,0) || dwWritten!=buffer_size)
          return ERR_WRITE;
  }
else
  {
    DWORD dwRead;

    // create a new buffer where buffer_size%bytes_per_sector==0
    unsigned size_new=disk_geometry.bps*( (buffer_size/disk_geometry.bps)+1 );
    uint8_t *buff_new=new uint8_t[size_new];

    LARGE_INTEGER seek_pos={0};
    LARGE_INTEGER tmp={0};
    SetFilePointerEx(hDisk,tmp,&seek_pos,FILE_CURRENT);

    if(!ReadFile(hDisk,buff_new,size_new,&dwRead,0) || dwRead!=size_new)
      {
          delete[] buff_new;
          return ERR_READ;
      }
    memcpy(buff_new+seek_pos.QuadPart%disk_geometry.bps,buff,buffer_size);

    SetFilePointerEx(hDisk,seek_pos,0,FILE_BEGIN);
    if(!WriteFile(hDisk,buff_new,size_new,&dwWritten,0) || dwWritten!=size_new)
      {
          delete[] buff_new;
          return ERR_WRITE;
      }
    delete[] buff_new;
  }

return 0;
}

It must be pretty slow (Seek, Read, Copy, Seek, then Write). Well, at least it works.
The difference is that \\.\PhysicalDriveX is used to open a whole disk while \\.\X: can be used to open a partition.


Thanks for the info' - will file that away for future use. Though I think I have a good bit of reading up to do before I'd try what you're doing.
Topic archived. No new replies allowed.