读内存 16进制显示(500分)(100分)

  • 主题发起人 未来107
  • 开始时间

未来107

Unregistered / Unconfirmed
GUEST, unregistred user!
打开一个内存镜像文件如pmem ,他保存的内容应该是char *类型的(pchar).现在如何读取
他并让他以16进制显示如下形式:
01 02 03 04 05.......
00001 AB 0D DD
00002 45 54 55
读取映像文件代码如下:
procedure TForm1.Mymessage(var Message:TMessage);
var
m:string;
hfilemap:hwnd;
pmem:pointer;
begin
hFileMap:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,10000,'Share');
if hFileMap=0 then
begin
CloseHandle(hFileMap);
ShowMessage('打开内存映射文件错误');
end;
//读取
pmem:=MapViewOfFile(hFileMap,File_Map_All_Access,0,0,0);// 访问整个映象文件
if pMem=nil then
begin
CloseHandle(hFileMap);
UnmapViewOfFile(pMem);
ShowMessage('读取存映射文件错误');
end;
m := PChar(pmem);//从共享内存读出内容
listbox2.Items.add(m);//接受数据并显示。
UnmapViewOfFile(pMem);
CloseHandle(hFileMap);
好友一个问题是好像读取得内容好像少了一部分?



 
不好意思,问题分数搞成了100分!但是只要解决问题,我会另开一个问题给分的
 
procedure TDeviceMonitor.WriteLn(const Buffer; Count: Integer);
var
P : PByteArray;
B : Byte;
C : Char;
S : String;
I : Integer;
J : Integer;
begin
P := @Buffer;
for I := 0 to (Count+15) div 16 -1 do
begin
S := Format(' %0.8X ', [I*$10]);
for J := 0 to $F do //每行以十六进制数显示16个字节
begin
if I*$10+J < Count then
begin
B := P^[I*$10+J];
if J = 7 then //第8个字符后显示一个分隔符
S := S + IntToHex(B, 2) + '-'
else
S := S + IntToHex(B, 2) + ' ';
end
else
S := S + ' '; //没有数据时以空格填充
end;

for J := 0 to $F do //显示16个字节对应的字符
begin
C := ' ';
if I*$10+J < Count then C := Chr(P^[I*$10+J]);
if (C < ' ') or (C > '~') then C := '.'; //不可见字符以"."显示

S := S + C;
end;

Self.WriteLn(S);
end;
end;
 
to tseug
怎么让他在一个memo1中显示出来呢!能举个例子吗!
 
没测试,只读7个字节,自己改改,不行再说。
procedure TfrmMain.btnReadClick(Sender: TObject);
var
i: Integer;
t:Byte;
s: TMemoryStream;
begin
if not OpenDialog1.Execute then exit;
s := TMemoryStream.Create;
s.LoadFromFile(OpenDialog1.FileName);

s.Seek($0, soFromBeginning); //定位
for i := 1 to 7 do // 读取7字节
begin
s.Read(t, 1); // 读出一字节
Memo1.Text:= Memo1.Text + IntToHex(t, 2);
end;

s.Free;
end;
 
m := PChar(pmem);//从共享内存读出内容
listbox2.Items.add(m);//接受数据并显示。

我对内存镜像文件一翘不通!但我知道你的代码不对哦!
如果不是文本文件,你显示出来的是乱码!
应该一一取出每个字节,把它转化成2个“0到F”的字符后
合成STRING后才能正确显示,
 
Self.WriteLn(S); 改为
Memo.Lines.Add(S); 就可以了
 
你的内存中还没有内容,以下是调试过的代码:

procedure TForm1.Button1Click(Sender: TObject);
const MEMSIZE=100;
var
s:string;
hfilemap:hwnd;
pmem:pointer;
p:pchar;
c:char;
i:integer;
begin
hFileMap:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,memsize,'Share');
if hFileMap=0 then
begin
CloseHandle(hFileMap);
ShowMessage('打开内存映射文件错误');
end;
//读取
pmem:=MapViewOfFile(hFileMap,File_Map_All_Access,0,0,0);// 访问整个映象文件
if pMem=nil then
begin
CloseHandle(hFileMap);
UnmapViewOfFile(pMem);
ShowMessage('读取存映射文件错误');
end;

//放一些内容
for i:=0 to MEMSIZE-1 DO
(pChar(integer(pmem)+i))^:=char(i mod 256);
////////////////////////////

for i:=0 to MEMSIZE-1 DO
begin
if (i mod 16)=0 then s:=inttohex(i div 16,4)+' ';
p:=pChar(integer(pmem)+i);//从共享内存读出内容
c:=p^;
s:=s+' '+inttoHex(integer(c),2);
if (i=MEMSIZE-1) or ((i mod 16)=15) then
listbox2.Items.add(s);//接受数据并显示。
end;
UnmapViewOfFile(pMem);
CloseHandle(hFileMap);
end;
 
是这样的,我通过本地向dll发送一些字符如"中国人民" ,用send
s:='中国';
send(0,s,0,0);
然后再dll中创建内存镜像,拷贝收到的字符到内存镜像中(pmem),然后用
上面的代码打开这个映像文件读取内容,没想到不对了,不管怎样只能读
4个字符。而且都变成了不可见字符!
 
这是完整的...

procedure TForm1.WriteLn(const Buffer; Count: Integer);
var
P : PByteArray;
B : Byte;
C : Char;
S : String;
I : Integer;
J : Integer;
begin
P := @Buffer;
for I := 0 to (Count+15) div 16 -1 do
begin
S := Format(' %0.8X ', [I*$10]);
for J := 0 to $F do //每行以十六进制数显示16个字节
begin
if I*$10+J < Count then
begin
B := P^[I*$10+J];
if J = 7 then //第8个字符后显示一个分隔符
S := S + IntToHex(B, 2) + '-'
else
S := S + IntToHex(B, 2) + ' ';
end
else
S := S + ' '; //没有数据时以空格填充
end;

for J := 0 to $F do //显示16个字节对应的字符
begin
C := ' ';
if I*$10+J < Count then C := Chr(P^[I*$10+J]);
if (C < ' ') or (C > '~') then C := '.'; //不可见字符以"."显示

S := S + C;
end;

Memo1.Lines.Add(S);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const MEMSIZE=100;
var
s:string;
hfilemap:hwnd;
pmem:pointer;
p:pchar;
c:char;
i:integer;
begin
hFileMap:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,memsize,'Share');
if hFileMap=0 then
begin
CloseHandle(hFileMap);
ShowMessage('打开内存映射文件错误');
end;
//读取
pmem:=MapViewOfFile(hFileMap,File_Map_All_Access,0,0,0);// 访问整个映象文件
if pMem=nil then
begin
CloseHandle(hFileMap);
UnmapViewOfFile(pMem);
ShowMessage('读取存映射文件错误');
end;

//放一些内容
for i:=0 to MEMSIZE-1 DO
(pChar(integer(pmem)+i))^:=char(i mod 256);
////////////////////////////

Self.WriteLn(pMem^, MEMSIZE);

UnmapViewOfFile(pMem);
CloseHandle(hFileMap);
end;
 
而且,我发送过去的是 "fasdfasdfa" 从内存镜像文件中读取得却变成了 l.f
 
我估计是收到了S的4字节地址,DLL中用了那个什么SHARE……什么吗(我望了);还
有看看SEND有什么问题吗!还可以试试PCHAR;
也有可能是 m := PChar(pmem);不对!
 
dll是c++写的,下面是c++写的代码
void MemMap(HWND hWnd,char* membuff)
{
//建立名为 Share_Memory_JiaJia 的内存映射文件
hFileMap=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,DATA_SIZE,"Share");
if(hFileMap==NULL)
{
CloseHandle(hFileMap);
MessageBox(hWnd,"创建内存映射文件错误","错误",MB_OK);
}

//提交文件
pMem=MapViewOfFile(hFileMap,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
if(pMem==NULL)
{
CloseHandle(hFileMap);
UnmapViewOfFile(pMem);
MessageBox(hWnd,"写内存映射文件错误","错误",MB_OK);
}

//复制内容
memset(pMem,0,DATA_SIZE);
strcpy((char *)pMem,membuff);


//CopyMemory(pMem,membuff,DATA_SIZE);
//删除文件
UnmapViewOfFile(pMem);
}

//----------------------------------------------------------------
// SpyMsg
//
// 调用MemMap建立文件
// 象调用进程发送自定义消息,以便读取内容
//----------------------------------------------------------------

void SpyMsg(LPTSTR szBuff)
{
MemMap(hWnd_display,szBuff);
hWin_Main=FindWindow(NULL,"mail"); // 对象窗口的名称
if(hWin_Main)
SendMessage(hWin_Main,WM_DATA,0,0);
}
 
俺对C++很菜啦!,研究了半天MSDN,
好像
pMem=MapViewOfFile(hFileMap,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
也要设置文件偏一量把它改成 :
pMem=MapViewOfFile(hFileMap,FILE_MAP_READ|FILE_MAP_WRITE,0,DATA_SIZE,0);
试试!
strcpy((char *)pMem,membuff);中的(char *)pMem要加‘(’吗!俺C++不熟!
 
在dll中直接传递字符串则一切正常
 
为什么直接传递字符就能够读取,而如果传递的数据中包括不可见字符则只能读取一点点内容
,好像是碰到某些字符就结束了!
 
如果是字符串,碰到#0(C中是"/0",就认为结束。)。所以如果某个字节是0,会认为是
字符串结束。
 
所以你除了传一个pchar外,还应传递一个长度参数。
 
现在可以肯定的是dll中传递的数据是正确的,只是在delphi中无法正确读出!特别是汉字
 
pchar就是以#0(/0)作为结束符,
如果你用来发送字符串就用不着长度参数,如果发送数据就要了!
SendMessage(hWin_Main,WM_DATA,DATA_SIZE,0);
 
顶部