vc问答
  问:我想知道如何在自己的程序中向Windows 3.x和95/98中添加程序组。最好能给出一个同时适合于16位和32位Windows的代码,因为我这里不得不继续使用Windows 3.2中文版。
答:如果是单为Windows 95/98,那么只需要用ShellAPI中的几个函数就可以完成要求。但是如果要一种同时适合16位和32位Windows的方法,则应该通过DDE编程来实现。下面给出一个使用Borland Pascal 7编写的程序,它可以添加程序组和程序项。由于是采用OWL编程,因此这个程序很容易移植到Borland C++中去。
  program PMDemo;
  {$R pmrun.res}
  uses WinTypes, WinProcs, OWindows, Strings, OStdDlgs;
  {$I pmrun.inc}
  const
   maxBufLen = 80;
   serverName = 'PROGMAN'; { 指定DDE服务器,对于这个例子,该服务器必须是PROGMAN }
   serverTopic = serverName;
  type
   PMRunApp = object(TApplication)
   procedure InitMainWindow; virtual;
   end;
   PPMRunWindow = ^PMRunWindow;
   PMRunWindow = object(TWindow)
   LinkEstablished: boolean; { DDE是否处于连接中 }
   HWndPM: HWnd;
   constructor Init(AParent: PWindowsObject; ATitle: PChar);
  function CanClose: boolean; virtual;
  function GetCommand(Prompt, Buffer: PChar): boolean;
   function Linked: boolean;
   procedure SendPMCommand(P: PChar);
   procedure Execute(Prompt, Command: PChar);
   procedure WMDDEAck(var Msg: TMessage);
   virtual wm_First + wm_DDE_Ack; { DDE确认消息 }
   procedure WMDDETerminate(var Msg: TMessage);
   virtual wm_First + wm_DDE_Terminate; { DDE终止消息 }
   procedure CMCreateGroup(var Msg: TMessage);
   virtual cm_First + cm_CreateGroup;
   procedure CMAddItem(var Msg: TMessage);
   virtual cm_First + cm_AddItem;
   procedure CMShowGroup(var Msg: TMessage);
   virtual cm_First + cm_ShowGroup;
   procedure CMQuit(var Msg: TMessage);
   virtual cm_First + cm_ExitPro;
   end;
  
  procedure PMRunApp.InitMainWindow;
  begin
   MainWindow := New(PPMRunWindow, Init(NIL, 'PMRun'));
  end;
  
  constructor PMRunWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  begin
   TWindow.Init(AParent, ATitle);
   Attr.Menu := LoadMenu(HInstance, PChar(Menu_1));
   MessageBox(HWindow, 'PMDemo - Written by Jiang Hong', 'About', mb_OK);
   LinkEstablished := FALSE; { DDE此时没有连接 }
  end;
  
  function PMRunWindow.CanClose: boolean;
  begin
   { 当DDE正在连接时不能直接关闭应用程序,应该先使得DDE对话结束 }
   if LinkEstablished and IsWindow(HWndPM) then
   PostMessage(HWndPM, wm_DDE_Terminate, HWindow, 0);
   CanClose := TRUE;
  end;
  
  function PMRunWindow.GetCommand(Prompt, Buffer: PChar): boolean;
  begin
   Buffer[0] := #0;
   GetCommand :=
   (Application^.ExecDialog(New(PInputDialog,
   Init(@Self, 'Program Manager Command', Prompt,
   Buffer, maxBufLen + 1))) = id_OK) and (Strlen(Buffer) > 0);
  end;
  
  procedure PMRunWindow.WMDDEAck(var Msg: TMessage);
  var
   AppAtom, AppTopic: TAtom;
   HMem: THandle;
   DDEStatus: word;
  begin
   if not LinkEstablished then begin
   LinkEstablished := TRUE;
   AppTopic := HiWord(Msg.LParam);
   AppAtom := LoWord(Msg.WParam);
   HWndPM := Msg.WParam;
   if AppAtom <> 0 then
   GlobalDeleteAtom(AppAtom);
   if AppTopic <> 0 then
   GlobalDeleteAtom(AppTopic);
   end else begin
   DDEStatus := LoWord(Msg.LParam);
   if (DDEStatus and DDE_Ack) <> DDE_Ack then
   MessageBox(HWindow, 'Command rejected by Program Manager',
   'Error', mb_OK);
   HMem := HiWord(Msg.LParam);
   if HMem <> 0 then
   GlobalFree(HMem);
   end;
  end;
  
  procedure PMRunWindow.WMDDETerminate(var Msg: TMessage);
  begin
   LinkEstablished := FALSE;
  end;
  
  { 判断DDE是否连接 }
  function PMRunWindow.Linked: boolean;
  var
   AppAtom, AppTopic: TAtom;
  begin
   if not LinkEstablished then begin
   AppAtom := GlobalAddAtom(serverName);
   AppTopic := GlobalAddAtom(serverTopic);
   SendMessage(Word(-1), wm_DDE_Initiate, HWindow,
   MakeLong(AppAtom, AppTopic));
   GlobalDeleteAtom(AppAtom);
   GlobalDeleteAtom(AppTopic);
   end;
   Linked := LinkEstablished;
  end;
  
  procedure PMRunWindow.SendPMCommand(P: PChar);
  var
   HCmd: THandle;
   PCmd: PChar;
  begin
   if Linked then begin
   HCmd := GlobalAlloc(gmem_Moveable or gmem_DDEShare, Strlen(P) + 1);
   if HCmd <> 0 then begin
   PCmd := GlobalLock(HCmd);
   if PCmd = NIL then
   GlobalFree(HCmd)
   else begin
   StrCopy(PCmd, P);
   GlobalUnlock(HCmd);
   if not PostMessage(HWndPM, wm_DDE_Execute, HWindow,
   MakeLong(0, HCmd)) then
   GlobalFree(HCmd);
   end;
   end;
   end else
   MessageBox(HWindow, 'Link to Program Manager failed', 'Note', mb_OK);
  end;
  
  procedure PMRunWindow.Execute(Prompt, Command: PChar);
  var
   P: PChar;
   Len: integer;
   Buffer: array[0..maxBufLen] of char;
  begin
   if GetCommand(Prompt, Buffer) then begin
   Len := 5 + Strlen(Command) + Strlen(Buffer);
   GetMem(P, Len);
   if P = NIL then
   MessageBox(HWindow, 'Out of memory', 'Error', mb_OK)
   else begin
   StrCopy(P, '[');
   StrCat(P, Command);
   StrCat(P, '(');
   StrCat(P, Buffer);
   StrCat(P, ')]');
   SendPMCommand(P);
   FreeMem(P, Len);
   end;
   end;
  end;
  {
  下面几个函数中调用Execute函数的第一个参数是实际使用时的格式。举例来说,如果要建立一个新的程序组My Group,该组位于C:\WIN31下,就要这样来写:
  My Group,C:\WIN31
  }
  
  procedure PMRunWindow.CMCreateGroup(var Msg: TMessage);
  begin
   Execute('GroupName[,GroupPath]', 'CreateGroup');
  end;
  
  procedure PMRunWindow.CMAddItem(var Msg: TMessage);
  begin
   Execute('CmdLine[,Name[,IconPath[,IconIndex[,X,Y]]]]', 'AddItem');
  end;
  
  procedure PMRunWindow.CMShowGroup(var Msg: TMessage);
  begin
   Execute('GroupName,Command(1-8)', 'ShowGroup');
  end;
  
  procedure PMRunWindow.CMQuit(var Msg: TMessage);
  begin
   CloseWindow;
  end;
  
  { Main }
  
  var
   PRApp: PMRunApp;
  
  begin
   PRApp.Init('PMRunApp');
   PRApp.Run;
   PRApp.Done;
  end.
  实际上,上面程序所用的方法几乎是每一个基于Win16的安装程序所必须完成的步骤。
  《电子与电脑》99年2期 问与答