Delphi下使用指针的简单总结
2007-05-27 16:21:08
版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。
http://fxh7622.blog.51cto.com/63841/28207
由于最近公司太忙,好久没有更新我的BLOG了。原来想着写写关于HOOK驱动的文章,可是最后想想好久已经没有做驱动的东西了,怕写出来有错误,于是作罢。开发游戏也有一段时间了,发现使用DELPHI来开发网络游戏不了解DELPHI下指针的使用是完全不行的。所以今天我简单总结以下我使用DELPHI指针的心得。希望对大家有所帮助。
记得在大学学习C语言的时候在谭浩强编写的书中,关于指针一章的开始就说“指针是C语言的精华”,可见指针对于C语言的重要性。其实在Pascal语言中指针也占据着重要的位置。
1:指针的赋值。
type
RTestInfo = record
Age:Integer;
end;
PtestInfo = ^ RtestInfo;
var
Test1,Test2:PtestInfo;
Begin
New(Test1);
New(Test2);
Test1^.Age:=12;
Test2:=Test1;
Application.MessageBox(Pchar(IntToStr(Test2^.Age)),’测试’,MB_OK);
Test1^.Age:=13;
Application.MessageBox(Pchar(IntToStr(Test2^.Age)),’测试’,MB_OK);
DisPose(Test1);
DisPose(Test2);
End;
上面的代码中使用了Test2:=Test1;进行指针的赋值,也就是说进行赋值以后两个变量指向的相同的地址,所以当Test1的Age发送变化以后Test2的Age也随之发生了变化。反过来也是一样。那如果我们要将Test1中的内容放在Test2中并且当Test1中的内容发生变化的时候Test2的内容不会发生变化有如何来做呢?其实很简单,使用Test2^:=Test1^;就可以了,这个时候变量Test1和变量Test2指向的是两个不同的地址,当一方的内容发生变化的时候另外一方不会受到影响。
2:数组和指针的转换。
曾使用过API函数来编写网络通信的都知道,网络传输过程中传输的都是char类型的数组。而我们经常需要将自己定义的一个结构通过网络传输出去,并且当对方接收到这个数据以后又能将其转换为相应的结构来处理。以前我是使用添加标记位来解决这个问题。其实使用数组和指针转换是很简单的。
type
RtestInfo = record
Age:Integer;
End;
Var
Test: RtestInfo;
Data:array[0..1024] of Char;
Begin
Test.Age:=13;
Fillchar(Data,SizeOf(Data),#0);
StrMove(Data,@ Test,sizeof(Test));
//数据发送
End;
在上面的例子中首先我们将我们定义数组Data清空,然后使用函数StrMove将结构Test的内容复制到Data中去。这个时候就可以将数据发送出去。当对方接受到数据以后,可以用以下的代码进行还原。
type
RtestInfo = record
Age:Integer;
End;
Var
Test: RtestInfo;
Begin
StrMove(@Test,Data,sizeof(Test));
//处理数据
End;
这个时候就可以对发送过来的数据进行相应的处理了。
3:函数指针的使用。
在分模块开发的过程中,DLL占据着重要的位置。在我开发游戏的服务端也是使用DLL的方式。在开发的时候遇见这样的一个问题,例如我在一个EXE中编写了一个功能非常复杂的函数,在DLL中我想使用到它,如何做呢?其实使用函数的指针就可以很方便的实现。
我们知道DLL的运行空间是和调用它的EXE在一起的。也就是说在这个空间中的资源理论上DLL是都可以使用。所以只要将exe中的函数指针传给DLL,那么DLL就可以使用这个函数了。
例如在DLL中有函数ModuleSendData作用是让EXE中传入函数的指针链表,这个链表中的函数都是DLL中可能用到的。
SendDataFun: procedure(Casetype: Byte; UserSocket: RUserSocket; Data: array of char; DataLen: Integer);
function ModuleSendData(FunPList: TList): Boolean; stdcall; export;
begin
SendDataFun := FunPList.Items[0];
end;
在EXE中的代码是:
Linstance:=LoadLibrary(Pchar(Temp));
if Linstance>0 then
begin
//将发送数据的指针传入DLL插件中
@GiveModuleFun:=GetProcAddress(Linstance,'ModuleSendData');
if @GiveModuleFun<>NIl then
begin
m_FunList:=TList.Create;
//发送数据
t_Pointer:=@DllSendData;
m_FunList.Add(t_Pointer);
GiveModuleFun(m_FunList);
End;
End;
其中DllSendData就是我们想传入给DLL的函数。
这个时候在DLL中使用SendDataFun就和一般的函数一样了。
这里注意的一点是Exe中的函数DllSendData我定义的是一个全局函数。原因是这样取得函数的指针的时候比较简单(关于类里面的函数指针如何取得我不了解,希望有了解的朋友不吝赐教,感激不尽)。
本文出自 “狗窝” 博客,请务必保留此出处
http://fxh7622.blog.51cto.com/63841/28207
文章评论
[匿名]花朵
2007-05-27 20:10:37
学习啦,总结的真够全面的,辛苦啦
[匿名]seewind
2007-05-29 16:35:01
获取类里面的函数指针。类或者对象的函数指针,delphi是特殊处理的。可以定义函数类型,如:
TObjProc = procedure of Object;
那TObjProc就是对象的函数类型,其实际是TMethod记录类型,看看TMethod定义,可以知道有两个内容:Data, Code: Pointer;
你可以用强制类型转换将TObjProc 的类型转换成TMethod,其中Data是Self的引用,Code就是函数的指针。
fxh7622
2007-06-04 11:51:39
seewind说的方法我倒是没有试过,改天我试试看。谢谢seewind。
[匿名]路过
2007-10-23 14:22:45
忘记在那个网站上看到,原理也差不多。不知道有没有用
Callbacks and objects
Undertitle: 如何 call back an instance of a class
Category: Win API
Uploader: Peter Morris
Question: Windows uses callbacks in quite a few places (EnumWindows, EnumFonts, EnumSystemLocales etc). The problem is that a callback is always an address of a standard procedure or function.
The reason for this is that windows does not pass back any reference to SELF (ie, the instance of the class), which is used by classes when deciding which instance to work with.
Well, the good news is that SysUtils.pas has an example of how to get a callback to work with an instance of a class, here is how they do it.
Answer: //First they make a record structure, which mimmicks some ASM code.
type
TCallbackThunk = packed record
POPEDX: Byte;
MOVEAX: Byte;
SelfPtr: Pointer;
PUSHEAX: Byte;
PUSHEDX: Byte;
JMP: Byte;
JmpOffset: Integer;
end;
//A variable is declared of this type. Instead of calling back
//a procedure, we are going to pass this variable as the
//address to call back. This acts as a kind of "pretend"
//procedure, which is aware of SELF.
var
Callback: TCallbackThunk;
begin
//Next, the record is populated with the actual values
//needed to create the actual ASM code. For example
//In the following line $5A is the binary value for POPEDX
Callback.POPEDX := $5A;
Callback.MOVEAX := $B8;
//Here is the reference to self
Callback.SelfPtr := Self;
Callback.PUSHEAX := $50;
Callback.PUSHEDX := $52;
Callback.JMP := $E9;
//Here is how to declare where to jump to (which procedure)
//All you do is change "LocalesCallBack" with the name of
//the method in your class that you wish to be used as the
//callback
Callback.JmpOffset := Integer(@TLanguages.LocalesCallback) - Integer(@Callback.JMP) - 5;
//Here is an example of how to use it, you could call
//EnumWindows are whatever you like instead
EnumSystemLocales(TFNLocaleEnumProc(@Callback), LCID_SUPPORTED);