各位大虾, 本人需要在win2000下用delphi6写一个读写软盘扇区的程序,该程序要求用virtualalloc分配内存作为扇区数据保存区,令人百思不得其解的是,读写该内存区竟然会出现access violation at 0xXXXX:read address 0xXXXX 这样的异常(而读写用Getmem分配的内存或用字节数组却不会出现这种错误),不知为什么?请指点指点!
delphi6 (试过delphi2,delphi4都不行)代码如下:
procedure TForm1.Button1Click(Sender: TObject);//下面的注解摘自Microsoft的support网站,大意是读扇区的时候必须按扇区字节数的倍数读取,缓冲区的地址也必须是扇区字节数的倍数,用virtualalloc来实现是一种较简便的方法(是不是还有其他方法可实现这些扇区读写要求?)
{With floppy and hard disks, all sector reads must start on sector boundaries on the disk and must be an integral number of sectors long. Furthermore, the buffers used for the reads must be aligned on addresses that fall on sector boundaries. For example, because a sector on a floppy disk is normally 512 bytes, the buffer that receives the sector data must be a multiple of 512 and must start on an address that is a multiple of 512. An easy way to guarantee that the buffer will start on a multiple of 512 is to allocate it with VirtualAlloc.}
//本代码读出软盘第0、1扇区并保存到硬盘的Sector.dat文件下type
LPBYTE = ^BYTE;var
hFD, hFile: THANDLE;
dwNotUsed: DWORD;
lpSector: LPBYTE;
dwSize:DWORD;begin
// 创建 Sector.dat 以保存读出的扇区数据.
hFile := CreateFile ('Sector.dat',
GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0); // 打开软驱a:
hFD := CreateFile ('\\.\a:', GENERIC_READ,
FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFD <> INVALID_HANDLE_VALUE) then BEGIN //如果成功打开 dwSize := 2*512; // 2个扇区
//用virtualAlloc分配内存,把内存指针保存到lpSector
lpSector := LPBYTE(VirtualAlloc (nil, dwSize,
MEM_COMMIT or MEM_RESERVE,
PAGE_READWRITE)); // 把文件指针移到需要读取的软盘扇区.
SetFilePointer (hFD, 0, nil, FILE_BEGIN) ; //读扇区,如成功则把读出的数据写到Sector.dat.
if ReadFile (hFD, lpsector, dwSize, dwNotUsed, nil) //在这里发生AV异常
then WriteFile (hFile, lpsector, dwSize, dwNotUsed, nil); VirtualFree(lpSector, 0, MEM_RELEASE);
END ; CloseHandle (hFD);
CloseHandle (hFile);
END; //End of Delphi code更为奇怪的是,如把上述代码翻译为c++代码,并在c++builder6下,在同样的机器上执行则不会发生任何异常。
我的电脑配置:cpu:Celeron 433, mem:128M,os:win2000
delphi6 (试过delphi2,delphi4都不行)代码如下:
procedure TForm1.Button1Click(Sender: TObject);//下面的注解摘自Microsoft的support网站,大意是读扇区的时候必须按扇区字节数的倍数读取,缓冲区的地址也必须是扇区字节数的倍数,用virtualalloc来实现是一种较简便的方法(是不是还有其他方法可实现这些扇区读写要求?)
{With floppy and hard disks, all sector reads must start on sector boundaries on the disk and must be an integral number of sectors long. Furthermore, the buffers used for the reads must be aligned on addresses that fall on sector boundaries. For example, because a sector on a floppy disk is normally 512 bytes, the buffer that receives the sector data must be a multiple of 512 and must start on an address that is a multiple of 512. An easy way to guarantee that the buffer will start on a multiple of 512 is to allocate it with VirtualAlloc.}
//本代码读出软盘第0、1扇区并保存到硬盘的Sector.dat文件下type
LPBYTE = ^BYTE;var
hFD, hFile: THANDLE;
dwNotUsed: DWORD;
lpSector: LPBYTE;
dwSize:DWORD;begin
// 创建 Sector.dat 以保存读出的扇区数据.
hFile := CreateFile ('Sector.dat',
GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0); // 打开软驱a:
hFD := CreateFile ('\\.\a:', GENERIC_READ,
FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFD <> INVALID_HANDLE_VALUE) then BEGIN //如果成功打开 dwSize := 2*512; // 2个扇区
//用virtualAlloc分配内存,把内存指针保存到lpSector
lpSector := LPBYTE(VirtualAlloc (nil, dwSize,
MEM_COMMIT or MEM_RESERVE,
PAGE_READWRITE)); // 把文件指针移到需要读取的软盘扇区.
SetFilePointer (hFD, 0, nil, FILE_BEGIN) ; //读扇区,如成功则把读出的数据写到Sector.dat.
if ReadFile (hFD, lpsector, dwSize, dwNotUsed, nil) //在这里发生AV异常
then WriteFile (hFile, lpsector, dwSize, dwNotUsed, nil); VirtualFree(lpSector, 0, MEM_RELEASE);
END ; CloseHandle (hFD);
CloseHandle (hFile);
END; //End of Delphi code更为奇怪的是,如把上述代码翻译为c++代码,并在c++builder6下,在同样的机器上执行则不会发生任何异常。
我的电脑配置:cpu:Celeron 433, mem:128M,os:win2000
MEM_COMMIT or MEM_RESERVE,
PAGE_READWRITE));
改为
lpSector := LPBYTE(VirtualAlloc (nil, dwSize,
MEM_COMMIT, PAGE_READWRITE));看看如何
#include <windows.h>void __fastcall TForm1::Button1Click(TObject *Sender)
{/*
This code reads sectors 0 and 1 from a floppy disk and writes
the contents to a disk file named Sector.dat
*/{
HANDLE hFD, hFile;
DWORD dwNotUsed; // Disk file that will hold the floppy disk sector data.
hFile = CreateFile ("Sector.dat",
GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL); // For the purposes of this sample, drive A: is the floppy drive.
hFD = CreateFile ("\\\\.\\a:", GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL); // If the floppy disk was successfully opened, read sectors 0
// and 1 from it and write their contents out to a disk file.
if (hFD != INVALID_HANDLE_VALUE)
{
LPBYTE lpSector;
DWORD dwSize = 2 * 512; // 2 sectors //The following sentence comes from Microsoft developer support web page
// "Allocate buffer to hold sectors from floppy disk. Note that
// the buffer will be allocated on a sector boundary because the
// allocation granularity is larger than the size of a sector on a
// floppy disk."
lpSector = (LPBYTE)VirtualAlloc (NULL, dwSize,
MEM_COMMIT|MEM_RESERVE,
PAGE_READWRITE); // Move to the sector intended to read.
SetFilePointer (hFD, 0,
NULL, FILE_BEGIN); // Read sectors from the floppy disk and write them to a file.
if (ReadFile (hFD, lpSector, dwSize, &dwNotUsed, NULL)) //without any exception
WriteFile (hFile, lpSector, dwSize, &dwNotUsed, NULL); VirtualFree (lpSector, 0, MEM_RELEASE);
}
CloseHandle (hFD);
CloseHandle (hFile);
}
}
FileName:string='C:\Sector.dat';
Driver:string='\\.\C:';
var
hFD, hFile: THANDLE;
dwNotUsed: DWORD;
lpSector: PBYTE;
dwSize:DWORD;
begin
asm
// 创建 Sector.dat 以保存读出的扇区数据.
PUSH 0
PUSH FILE_ATTRIBUTE_NORMAL
PUSH CREATE_ALWAYS
PUSH 0
PUSH 0
PUSH GENERIC_WRITE
PUSH FileName
CALL CreateFile
MOV hFile,EAX
// 打开软驱a:
PUSH 0
PUSH FILE_ATTRIBUTE_NORMAL
PUSH OPEN_EXISTING
PUSH 0
PUSH FILE_SHARE_READ OR FILE_SHARE_WRITE
PUSH GENERIC_READ
PUSH DRIVER
CALL CreateFile
MOV hFD,EAX
CMP EAX,INVALID_HANDLE_VALUE
JE @Error
//如果成功打开
MOV dwSize,2*512 // 2个扇区
//用virtualAlloc分配内存,把内存指针保存到lpSector
PUSH PAGE_READWRITE
PUSH MEM_COMMIT
PUSH dwSize
PUSH 0
CALL VirtualAlloc
MOV lpSector,EAX
// 把文件指针移到需要读取的软盘扇区.
PUSH FILE_BEGIN
PUSH 0
PUSH 0
PUSH hFD
CALL SetFilePointer
//读扇区,如成功则把读出的数据写到Sector.dat.
PUSH 0
LEA EAX,dwNotUsed
PUSH EAX
PUSH dwSize
// LEA EAX,lpSector
// PUSH EAX
PUSH lpSector
PUSH hFD
CALL ReadFile
CMP EAX,0
JE @Release
PUSH 0
LEA EAX,dwNotUsed
PUSH EAX
PUSH dwSize
PUSH lpSector
PUSH hFile
CALL WriteFile
@Release:
PUSH MEM_RELEASE
PUSH 0
PUSH lpSector
CALL VirtualFree
@Error:
PUSH hFD
CALL CloseHandle
PUSH hFile
CALL CloseHandle
END; //End of Delphi code
end;
Eastunfail是“东方不败”的意思吗?为什么专家分再高也加不了星星呢?