这个BUG是老早就存在的,在我刚来公司没多久的时候,JACK就跟我说起过这个问题,这个问题的症状很奇怪,正常使用时,它永远不会出现,而当用户把屏幕锁定以后再过若干时间,就会有一长串的弹出窗口,更怪的是,这些窗口有时有,有时没有.
同事最近老是遇上这个问题,要我一定得想想办法,凑了点时间仔细查看了这个问题,发现如下的细节:
- 这个错误出现的前提是: 1. 屏幕锁定, 2. 屏保出现
- 程序的窗口需要是当前窗口,如果仅在后台运行,这个错误不会出现
- 即使是在当前窗口,这个错误也不是每次都会出现,似乎与当前子窗口有关
- 即使是相同子窗口,这个错误也是有时出现,有时不出现
- 根据经验判断应该是定时器中出现的问题
- 这个错误其实包括2个, 1. "A call to an OS function failed.", 2. "Access denied" 错误
由于这个错误只在屏幕锁定且有屏保时出现,我先把计算机的屏保设定为1分钟,以减少浪费的时间,然后用DELPHI打开工程进入DEBUG模式启动程序,再锁上屏幕等屏保出现.如果有效,那么出错时DELPHI应该截获这个出错信息并停留在那里.
1分钟以后,输入密码重新进入桌面,果然,DELPHI报错了,可是,错误的地方不是我的程序,而是进入了Forms.pas这个系统单元,在function TApplication.ProcessMessage这个函数中,停留在这句 TranslateMessage(Msg); 上.
按F8进行DEBUG,进入了ExtCtrls这个系统单元,原来是这里出的错,上面的函数是在 Application.HandleException(Self); 这里调用到的.继续F8,我的程序跳出了错误框,然后就结束了.没有找到哪里出错.不过,这也验证了的确是定时器的问题,但是,是哪个定时器呢?
我把主界面及子窗口中的所有定时器全部关闭,可是这个错误还是照常出现.奇怪了.
procedure TTimer.WndProc的定义如下:
- procedure TTimer.WndProc(var Msg: TMessage);
- begin
- with Msg do
- if Msg = WM_TIMER then
- try
- Timer;
- except
- Application.HandleException(Self);
- end
- else
- Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
- end;
我把断点设在第6行 Timer上,用F7不断进行跟踪,跳转了几次后,发现进入了一个自定义的控件单元,有戏!
进入的函数是OnHintTimer. 看,这就是一个隐藏的TIMER不是.我在这个函数的开始加个EXIT使之禁用,再运行程序,锁屏,等屏保,再进入.果然没有错误了!看来问题就是在这儿.
程序函数中出错的地方居然是取鼠标位置的几句,很奇怪会出这样的错误.我又试了一下,恢复原来的代码,使当前窗口是此程序,如果把鼠标移到此程序窗口之外,再锁屏,等屏保,解锁再进入,果然就是没有错误的.
再次尝试,把出错的一段句子加上try...except....语句.在except中加上Mouse.CursorPos.x,结果...居然就没有错,晕死.
总结一下这个错误:当打开此程序,并激活某个使用特定控件的窗口,使此控件的OnHintTimer可用,并且鼠标指针在此控件上,能引发OnHintTimer事件.在这种情况下,锁定屏幕,使计算机进入屏保(如果不锁屏,只进入屏保也不会引发这个错误),然后再解除屏幕锁定,就会在此控件的OnHintTimer事件中发生错误,而发生的错误是在获得鼠标位置的语句.错误为"A call to an OS function failed.",由系统抛出.
老实说,这个错误非常奇怪,因为在OnHintTimer中只是获得鼠标位置,我甚至已经把此事件中的语句删得仅剩一句
x :=Mouse.CursorPos.x;
了.也还是一样的错误.到底为什么,还是一个谜,我会继续追踪下去.
无论如何,这个错误是找到了,要解决的话,只要在OnHintTimer事件中套上try...except...end语句,那么就不会出现那些烦人的错误框了.
没有特定的属性可以修改,只能修改控件的ONDRAWCELL事件:
- procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
- Rect: TRect; State: TGridDrawState);
- var
- sText: string;
- begin
- with StringGrid1 do
- begin
- sText := Cells[ACol, ARow];
- if sText <> ' ' then
- begin
- Canvas.FillRect(Rect);
- DrawText(Canvas.Handle, PChar(sText), Length(sText), Rect, DT_CENTER or DT_VCENTER or DT_SINGLELINE);
- end;
- end;
- end;
这样修改的一个结果是,第一行标题栏也变成了白色背景居中显示,偷个懒,把第一行改成灰色背景吧:
- procedure TSolidDepositionPrograssForm.StringGrid1DrawCell(Sender: TObject;
- ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
- var sText: string;
- begin
- with StringGrid1 do
- begin
- sText := Cells[ACol, ARow];
- if sText <> ' ' then
- begin
- if ARow=0 then begin
- Canvas.Brush.Color:=clBtnface;
- end else
- Canvas.Brush.Color:=clWhite;
- Canvas.FillRect(Rect);
- DrawText(Canvas.Handle, PChar(sText), Length(sText), Rect, DT_CENTER or DT_VCENTER or DT_SINGLELINE);
- end;
- end;
- end;
DELPHI开发WEB SERVICE, 有几种选项, 我开始选ISAPI,但是编译出来的DLL在被APACHE运行过后就被驻留在内存里,不能替换删除,不利于我这种初学者:我要不停地替换这个DLL看结果的.因此用了CGI格式输出.编辑出来的CGI文件如何使用在另一文中已经记录了.
一个WEB SERVICE可以有多个ACTION,对应不同的信息处理动作,每个ACTION都有其对应的PathInfo属性,在object Inspector中可以看到,修改对应的PathInfo可以按不同的URL实现对同一个CGI文件不同ACTION的调用,比如说:
Action1的PathInfo设置为"/": http://localhost/cgi-bin/webservice.exe?name=abc
Action2的PathInfor设置为"/act2": http://localhost/cgi-bin/webservice.exe/act2?name=abc
Delphi的指针操作和C的指针操作对比比较全面,转帖收录备用
浅谈Object Pascal的指针
大家都认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是C语言的灵魂,一点都不为过。同时,这种说法也让很多人产生误解,似乎只有C语言的指针才能算指针。Basic不支持指针,在此不论。其实,Pascal语言本身也是支持指针的。从最初的Pascal发展至今的Object Pascal,可以说在指针运用上,丝毫不会逊色于C语言的指针。
以下内容分为八个部分,分别是
一、类型指针的定义
二、无类型指针的定义
三、指针的解除引用
四、取地址(指针赋值)
五、指针运算
六、动态内存分配
七、字符数组的运算
八、函数指针
一、类型指针的定义。对于指向特定类型的指针,在C中是这样定义的:
int *ptr;
char *ptr;
与之等价的Object Pascal是如何定义的呢?
var
ptr : ^Integer;
ptr : ^char;
其实也就是符号的差别而已。
二、无类型指针的定义。C中有void *类型,也就是可以指向任何类型数据的指针。Object Pascal为其定义了一个专门的类型:Pointer。于是,
ptr : Pointer;
就与C中的
void *ptr;
等价了。
三、指针的解除引用。要解除指针引用(即取出指针所指区域的值),C 的语法是 (*ptr),Object Pascal则是 ptr^。
四、取地址(指针赋值)。取某对象的地址并将其赋值给指针变量,C 的语法是
ptr = &Object;
Object Pascal 则是
ptr := @Object;
也只是符号的差别而已。
五、指针运算。在C中,可以对指针进行移动的运算,如:
char a[20];
char *ptr=a;
ptr++;
ptr+=2;
当执行ptr++;时,编译器会产生让ptr前进sizeof(char)步长的代码,之后,ptr将指向a[1]。ptr+=2;这句使得ptr前进两 个sizeof(char)大小的步长。同样,我们来看一下Object Pascal中如何实现:
var
a : array [1..20] of Char;
ptr : PChar; //PChar 可以看作 ^Char
begin
ptr := @a;
Inc(ptr); // 这句等价于 C 的 ptr++;
Inc(ptr, 2); //这句等价于 C 的 ptr+=2;
end;
六、动态内存分配。C中,使用malloc()库函数分配内存,free()函数释放内存。如这样的代码:
int *ptr, *ptr2;
int i;
ptr = (int*) malloc(sizeof(int) * 20);
ptr2 = ptr;
for (i=0; i<20; i++){
*ptr = i;
ptr++;
}
free(ptr2);
Object Pascal中,动态分配内存的函数是GetMem(),与之对应的释放函数为FreeMem()(传统Pascal中获取内存的函数是New()和 Dispose(),但New()只能获得对象的单个实体的内存大小,无法取得连续的存放多个对象的内存块)。因此,与上面那段C的代码等价的 Object Pascal的代码为:
var ptr, ptr2 : ^integer;
i : integer;
begin
GetMem(ptr, sizeof(integer) * 20);
//这句等价于C的 ptr = (int*) malloc(sizeof(int) * 20);
ptr2 := ptr; //保留原始指针位置
for i := 0 to 19 do
begin
ptr^ := i;
Inc(ptr);
end;
FreeMem(ptr2);
end;
对于以上这个例子(无论是C版本的,还是Object Pascal版本的),都要注意一个问题,就是分配内存的单位是字节(BYTE),因此在使用GetMem时,其第二个参数如果想当然的写成 20,那么就会出问题了(内存访问越界)。因为GetMem(ptr, 20);实际只分配了20个字节的内存空间,而一个整形的大小是四个字节,那么访问第五个之后的所有元素都是非法的了(对于malloc()的参数同样)。
七、字符数组的运算。C语言中,是没有字符串类型的,因此,字符串都是用字符数组来实现,于是也有一套str打头的库函数以进行字符数组的运算,如以下代码:
char str[15];
char *pstr;
strcpy(str, "teststr");
strcat(str, "_testok");
pstr = (char*) malloc(sizeof(char) * 15);
strcpy(pstr, str);
printf(pstr);
free(pstr);
而在Object Pascal中,有了String类型,因此可以很方便的对字符串进行各种运算。但是,有时我们的Pascal代码需要与C的代码交互(比如:用 Object Pascal的代码调用C写的DLL或者用Object Pascal写的DLL准备允许用C写客户端的代码)的话,就不能使用String类型了,而必须使用两种语言通用的字符数组。其实,Object Pascal提供了完全相似C的一整套字符数组的运算函数,以上那段代码的Object Pascal版本是这样的:
var str : array [1..15] of char;
pstr : PChar; //Pchar 也就是 ^Char
begin
StrCopy(@str, 'teststr'); //在C中,数组的名称可以直接作为数组首地址指针来用
//但Pascal不是这样的,因此 str前要加上取地址的运算符
StrCat(@str, '_testok');
GetMem(pstr, sizeof(char) * 15);
StrCopy(pstr, @str);
Write(pstr);
FreeMem(pstr);
end;
八、函数指针。在动态调用DLL中的函数时,就会用到函数指针。假设用C写的一段代码如下:
typedef int (*PVFN)(int); //定义函数指针类型
int main()
{
HMODULE hModule = LoadLibrary("test.dll");
PVFN pvfn = NULL;
pvfn = (PVFN) GetProcAddress(hModule, "Function1");
pvfn(2);
FreeLibrary(hModule);
}
就我个人感觉来说,C语言中定义函数指针类型的typedef代码的语法有些晦涩,而同样的代码在Object Pascal中却非常易懂:
type PVFN = Function (para : Integer) : Integer;
var
fn : PVFN;
//也可以直接在此处定义,如:fn : function (para:Integer):Integer;
hm : HMODULE;
begin
hm := LoadLibrary('test.dll');
fn := GetProcAddress(hm, 'Function1');
fn(2);
FreeLibrary(hm);
end;
补充(蓝蓝) 其他指针(类似的指针)
接口是什么 接口就是指针
事件是什么 事件也是指针,
我们可以这样申明
type
OnMouseOn=procedure of object;//使用object关键字定义一个 过程或者函数的指针,让他来关联事件
TClass1=class
public
OnMouse:procedure of object;
end;
如果写成
class.onmouse:=form1.onmousedown//这里进行了过程指针指向了。form1的一个具体事件的
2006-7-10 10:09:17 指针详细。
指针的表达方法
Const
const PI: ^Integer = @I;
^integer=@I=Pointer=@MyProc
都是指针
而
Data^是指针的具体内容。
请举例如何定义指针常量和常量指针
参数传递中的指针常量就不必说了吧——和非指针的常量一样的。
这是一个标准的Const Pointer的例子:
var
A:Integer=100;
const
PA:PInteger=@A;
procedure TForm1.Button1Click(Sender: TObject);
begin
Caption:=IntToHex(Integer(PA),8);
end;
下面是一个用函数来模拟无法预先决定值的常量指针的例子:
Unit A;
interface
function PointerA:Pointer;
implementation
var
ObjA:TXXX; //ObjA运行后才能被动态的创建
function PointerA:Pointer;
begin
Result:=@ObjA;
end;
...
这样,在UnitA之外的地方,PointerA地返回值就是常量了:)
DELPHI开发调用WEBSERVICE的一个简单例子,先转帖过来,代码还没有验证其正确性
原帖地址: http://kb.cnblogs.com/a/1505053/
========================================================
Webservice技术的出现将各种开发技术和语言完全的融合了,下面就这种融合在C#和delphi之间的交互做一次全面的体现
1.使用C#创建一个Webservice服务。
使用vs2005的模板创建C#的webservice非常容易。原文件如下:
[WebService(Namespace = "http://localhost/webserver/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
public Service () {
//如果使用设计的组件,请取消注释以下行
InitializeComponent();
}
#region Component Designer generated code
private void InitializeComponent()
{
}
//Web 服务设计器所必需的
private IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
//这个是自动生成的一个webservice函数,可以不要。
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
//这个才是我们自己创建的,
[WebMethod]
public int addnumber(int a, int b)
{
return = a + b;
}
}
2.使用delphi创建一个dll(非com的dll),该dll调用上面的webserivce服务。
使用delphi调用C#的webservice过程也很容易,但是对于新手可能比较麻烦(我就是这么过来的)
第一步:创建一个dll单元:
{$R *.res}
function GetNum(a,b:integer):integer stdcall; [Page]
var
ireturn :Integer;
begin
ireturn:=GetServiceSoap().addnumber(a,b); //这个GetServiceSoap是什么,看后面...
result:=ireturn;
end;
exports
GetNum name ’GetNum’;
begin
end.
//如果是delphi调用该dll必须使用下面的代码。C#调用则不需要了(C#还是要牛一些,呵呵)
initialization
coinitialize(nil);
finalization
counInitializ
第二步:将webserivce的WSDL导入到该dll工程中,如何导,方法至少有两种,我说简单的一种:
file->new->other->WebService->WSDL Importer,(将C#的WSDL输入)然后delphi会自动给你生成了一个pas文件,
function GetServiceSoap(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): ServiceSoap;
const
defWSDL = ’http://localhost/webserver/Service.asmx?WSDL’;
defURL = ’http://localhost/webserver/Service.asmx’;
defSvc = ’Service’;
defPrt = ’ServiceSoap’;
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = ’’) then
begin
if UseWSDL then
Addr := defWSDL
else
Addr := defURL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
//RIO.HTTPWebNode.UseUTF8InHeader:=True; //在此添加一句,修改编码方案。
Result := (RIO as ServiceSoap);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;
RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;
initialization
InvRegistry.RegisterInterface(TypeInfo(ServiceSoap), ’http://localhost/webserver/’, ’utf-8’); [Page]
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(ServiceSoap), ’http://localhost/webserver/%operationName%’);
//对于无法识别传入的参数的问题,需要手工加上这一句>......
InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);
这段代码基本上你不用关心,但是,有两个地方需要特别注意:
1.RIO.HTTPWebNode.UseUTF8InHeader:=True;对于中文参数必须加上
2.InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);
如果传入的参数不能被webservice识别时,多半是因为你没有加上这一句。
3.使用delphi调用上面的dll
就一个函数,没有什么好说的:
procedure TForm1.Button1Click(Sender: TObject);
type
GetNumTotal=function(a,b:integer):integer;stdcall;
var
Th:Thandle;
Tf:GetNumTotal;
Tp:TFarProc;
begin
Th:=LoadLibrary(’mywebservice.dll’); {装载DLL}
if Th>0 then
try
Tp:=GetProcAddress(Th,PChar(’GetNum’));
if Tp<>nil
then begin
Tf:=GetNumTotal(Tp);
Edit1.Text:=IntToStr(Tf(1,3)); {调用GetNumTotal函数}
end
else
ShowMessage(’GetNumTotal函数没有找到’);
finally
FreeLibrary(Th); {释放DLL}
end
else
ShowMessage(’mywebservice.dll没有找到’);
end;
4.使用C#调用上面的dll
[DllImport("mywebservice.dll", EntryPoint = "GetNum")]
public static extern int GetNum(int a, int b);
private void button1_Click(object sender, EventArgs e)
{
int a,b,i;
a=10;
b =20;
i=GetNum(a,b); //第一次比较慢(webserivce的唯一弊端!!!!)
textBox1.Text = i.ToString();
}





