使用API如何写出稳定的系统托盘程序?
我想要写一个系统托盘程序,只需要显示一个小图标,然后如果用右键点击一下就弹出一个菜单,找到了一段这样的代码,我试验过后发现这样确实可以实现我想要的功能,但是程序运行一、两个小时后右键菜单就显示不出来了,在显示不出右键菜单时TrackPopupMenu函数虽然返回True,但是我通过GetLastError函数发现有错误ERROR_INVALID_HANDLE,而前面CreatePopupMenu却没有任何错误。代码中的MyDll.dll只需要LoadLibrary就会开启两个线程用TextOutA函数在屏幕上不断的输出文字。
program Shell;
uses
Windows,ShellAPI,Messages,SysUtils;
{$R ShellCPU.res}
const
ClassName='myownclassname';
var
msg:TMsg;
WndClass:TWndClassA;
hWnd,hPop:THandle;
hMap:THandle;
pBool:Pointer;
ShowUsage:BOOL;
WM_TASKBARCREATED:Cardinal;
PopText:PChar;
NotifyData: NOTIFYICONDATA;
bInit:BOOL;
procedure Shell_AddICON(Add:Boolean=True);
begin
with NotifyData do
begin
cbSize:=SizeOf(NotifyData);
Wnd:=hWnd;
uID:= 0;
uFlags:=NIF_MESSAGE or NIF_ICON;
uCallbackMessage:=WM_USER+888;
end;
if Add then
Shell_NotifyIcon(NIM_ADD,@NotifyData)
else
Shell_NotifyIcon(NIM_DELETE,@NotifyData);
end;
procedure InitShare;
begin
hMap:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,SizeOf(Bool),'myinformation');
pBool:=MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);
CopyMemory(pBool,@ShowUsage,SizeOf(BOOL));
end;
procedure WriteShare;
begin
CopyMemory(pBool,@ShowUsage,SizeOf(BOOL));
end;
function MainWndProc(HWin: THandle; MsgID: UINT; wParam, lParam: Integer): LRESULT; stdcall;
var
iButton:Integer;
hdcS:HDC;
dwErr:DWORD;
tpCurrentPoint:TPoint;
begin
case MsgID of
WM_CREATE:
begin
WM_TASKBARCREATED:=RegisterWindowMessage('TaskbarCreated');
end;
WM_CLOSE:
begin
UnmapViewOfFile(pBool);
CloseHandle(hMap);
DestroyWindow(hWnd);
end;
WM_DESTROY:
begin
PostQuitMessage(0);
end;
WM_USER+888:
begin
if ((wParam=0) and (lParam=$201)) then
begin
ShowUsage:=not ShowUsage;
WriteShare;
end;
if ((wParam=0) and (lParam=$205)) then//在图标上按了右键
begin
hPop:=CreatePopupMenu;
AppendMenu(hPop,MF_STRING,1,'退出');
AppendMenu(hPop,MF_SEPARATOR,9,nil);
SetForegroundWindow(HWin);
GetCursorPos(tpCurrentPoint);
if ShowUsage=True then
PopText:=PChar('不显示')
else
PopText:=PChar('显示');
AppendMenu(hPop,MF_CHANGE or MF_STRING,2,PopText);
iButton:=Integer(TrackPopupMenu(hPop,
TPM_LEFTALIGN or TPM_LEFTBUTTON,
tpCurrentPoint.X,
tpCurrentPoint.y,
0,
hWnd,
nil));
DestroyMenu(hPop);
end;
end;
end;
if MsgID= WM_COMMAND then
begin
iButton:=wParam;
if iButton=1 then
begin
Shell_AddICON(False);
ExitProcess(0);
end
else if iButton=2 then
begin
ShowUsage:=not ShowUsage;
WriteShare;
if ShowUsage then
NotifyData.hIcon:=LoadIcon(HInstance,'TRAYH')
else
NotifyData.hIcon:=LoadIcon(HInstance,'TRAYS');
end;
Shell_NotifyIcon(NIM_MODIFY,@NotifyData);
end;
if MsgID=WM_TASKBARCREATED then
begin
Shell_AddICON;
end;
Result:=DefWindowProc(HWin,MsgID,wParam,lParam);
end;
begin
if ParamStr(1)='f' then
begin
ShowUsage:=False;
NotifyData.hIcon:=LoadIcon(HInstance,'TRAYS');
end
else
begin
ShowUsage:=True;
NotifyData.hIcon:=LoadIcon(HInstance,'TRAYH');
end;
with WndClass do
begin
style:=CS_HREDRAW or CS_VREDRAW;
lpfnWndProc:=@MainWndProc;
hInstance:= sysinit.HInstance;
hIcon:=LoadIcon(0,PChar(IDI_APPLICATION));
hCursor:=LoadCursor(0,IDC_ARROW);
hbrBackground:=GetStockObject(WHITE_BRUSH);
lpszClassName:=ClassName;
end;
if RegisterClass(WndClass)=0 then
ExitProcess(0);
hWnd:=CreateWindowEx(0,PChar(ClassName),'Shell',WS_OVERLAPPED,0,0,100,100,0,0,hInstance,nil);
if hWnd=0 then
begin
MessageBox(0,'无法创建窗口!','错误',0);
ExitProcess(0);
end;
InitShare;
Shell_AddICON;
LoadLibrary('MyDll.dll');
while GetMessage(msg,0,0,0) do
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
end.
[解决办法]
CoolTrayIcon VCL组件源码是公开的,可以下载一个看一下。
[解决办法]
如好用请结贴快一点