如何用delphi实现外壳扩展(100分)

  • 主题发起人 主题发起人 Xxfeng
  • 开始时间 开始时间
X

Xxfeng

Unregistered / Unconfirmed
GUEST, unregistred user!
请教:
; 1.VC中的variant 是对应Delphi 中的 TVarData吗?
; 2.如何用delphi实现外壳扩展。就是在资源管理器中调用右键菜单时,
; ; 会显示一个"属性"菜单项,点击属性菜单项会显示一个属性页,就是
; ; 在其中添加一个属性页。
 
和注册表打交道!有人发表过此类!
 
转贴一篇:

利用COM技术实现外壳扩展的属性页

当用户在资源管理器中调用右键菜单时,会显示一个"属性"菜单
项,点击属性菜单项会显示一个属性页,用户可以获得甚至修改文
件信息。我们可以定制属性页通过实现属性页扩展。如下图所示,
本文实现了一个显示wave(波形)文件的信息如声道数等信息的属
性页扩展。

属性页扩展通常是同某类文件相关联的来实现同之相关的操作和信
息显示,另外可以同驱动器相关联,我们还可以用属性页扩展来替
换控制面板程序的属性页。象其他外壳扩展程序一样,属性页扩展
也是以动态连接库形式实现的进程内COM对象。它除了IUnknown接口
外还要实现IShellExtInit和IShellPropSheetExt接口。

建立同文件关联的属性页扩展

首先,我们用命令File|New...,创建一个ActiveX Library,然后
新建一个COM Object,实现的接口为IShellExtInit和
IShellPropSheetExt。

同文件建立关联需要注册属性页,要在注册表中同相应文件对应的
表项下添加Shellex/PropertySheetHandlers子键 ,每增加一个页
面就需要注册一个表项,最大可以添加的页面数是24,我们可以用
一个扩展实现多个页面。这里我们通过从TComObjectFactory继承类
实现的UpdateRegistry实现了注册。


type
TCXPropSheetFactory=class(TComObjectFactory)
public
procedure UpdateRegistry(Register: Boolean); override;
end;

procedure TCXPropSheetFactory.UpdateRegistry(Register:
Boolean);
var
ClassID: string;
Str,KeyName : string;
begin
inherited UpdateRegistry(Register);
if Register then
begin
ClassID:=GUIDToString(Class_CXPropSheet);
with TRegistry.Create do
try
RootKey:=HKEY_CLASSES_ROOT;
OpenKey('/.wav',TRUE);
KeyName := ReadString('');
if Keyname = '' then
begin
WriteString('','WaveFile');
OpenKey('/.wav',TRUE);
KeyName := ReadString('');
end;
OpenKey('/'+KeyName+'/shellex/PropertySheetHandlers/Wav',TR
UE);
WriteString('',Classid);
finally
Free;
end;

if(Win32Platform=VER_PLATFORM_WIN32_NT)then
begin
with TRegistry.Create do
try
RootKey:=HKEY_LOCAL_MACHINE;
OpenKey('SOFTWARE/Microsoft/Windows/CurrentVersion/Shell
Extensions', True);
OpenKey('Approved', True);
WriteString(ClassID, 'Wave File Property Sheet');
finally
Free;
end;
end;
end
else
删除注册表项.......................
end;
初始化扩展是通过IShellExtInit实现的,当外壳调用
IShellExtInit.Initialize时,它传递一个数据对象包含来文件对
应的目录的PIDL标识符。Initialize方法需要从数据对象中提取文
件名,并把文件名和PIDL标识符保存起来为了以后使用。


function TCXPropSheet.SEIInitialize(pidlFolder:
PItemIDList;
lpdobj: IDataObject; hKeyProgID: HKEY): HResult;
var
StgMedium: TStgMedium;
FormatEtc: TFormatEtc;
szFile: array[0..MAX_PATH+1]of Char;
filecount: integer;
begin

Result:=E_FAIL;

if(lpdobj=nil)then begin
Result:=E_INVALIDARG;
messagebox(0, '1', '错误', mb_ok);
Exit;
end;

with FormatEtc do begin
cfFormat:=CF_HDROP;
ptd:=nil;
dwAspect:=DVASPECT_CONTENT;
lindex:=-1;
tymed:=TYMED_HGLOBAL;
end;

Result:=lpdobj.GetData(FormatEtc, StgMedium);
if Failed(Result)then
Exit;

// 如果只有一个文件被选中,获得文件名并保存。
filecount:=DragQueryFile(stgmedium.hGlobal, $FFFFFFFF, nil,
0);
if filecount=1 then begin
Result:=NOERROR;
DragQueryFile(stgmedium.hGlobal, 0, szFile,
SizeOf(szFile));
FFilename:=strpas(szFile);
end;
ReleaseStgMedium(StgMedium);
end;
添加页面的操作是通过IShellPropSheetExt接口来实现的。如果属
性页是和文件相关联,外壳会调用 IShellPropSheetExt.AddPages
给属性页添加一个页面。如果属性页同控制面板程序相关联,外壳
调用 IShellPropSheetExt.ReplacePage来替换页面。

IShellPropSheetExt.AddPages方法有两个参数,lpfnAddPage是一
个指向AddPropSheetPageProc 回调函数的指针,回调函数用来提供
要添加的页面信息给外壳。lParam是一个用户自定义的值,这里我
们用它来返回给回调函数对象。

一般的IShellPropSheetExt.AddPages方法实现步骤是:

给PROPSHEETPAGE结构设定正确的值,特别是:
把扩展的对象引用记数变量付值给pcRefParent成员,这可以防止页
面还在显示时,扩展对象被卸载。
实现 PropSheetPageProc 回调函数来处理页面创建和销毁的情况。
调用CreatePropertySheetPage函数来创建页面。
调用lpfnAddPage指向的函数来来添加创建好的页面。

function TCXPropSheet.AddPages(lpfnAddPage:
TFNADDPROPSHEETPAGE;
lParam: LPARAM): HResult;
var
PSP: TPropSheetPage;
HPSP: HPropSheetPage;
begin
result:=E_FAIL;
try
psp.dwSize:=SizeOf(psp);

psp.dwFlags:=PSP_USEREFPARENT or PSP_USETITLE or
PSP_USECALLBACK;
psp.hInstance:=hInstance;
//这里我们使用了事先储存在wave.res中的对话框模板,模板是用
delphi5自带的
//resource workshop编辑的,使用delphi5/bin/brcc32.exe编译
的。
psp.pszTemplate:=MakeIntResource(100);
//标题名
psp.pszTitle:='波文件信息';
//设定回调函数
psp.pfnDlgProc:=@DialogProc;
psp.pfnCallBack:=@PropCallback;
//设定对象引用记数变量
psp.pcRefParent:=@comserver.objectcount;

//用lParam向回调函数传递对象
psp.lParam:=integer(self);

HPSP:=CreatePropertySheetPage(psp);
if HPSP<>nil then begin
if not lpfnAddPage(HPSP, lParam)then begin
DestroyPropertySheetPage(HPSP);
end else begin
_addref;//增加引用记数,否则一脱离这个方法的作用域,delphi
自动释放对象。
result:=S_OK;
end
end
except
on e: exception do begin
e.message:='添加页面 '+e.message;
messagebox(0, pchar(e.message), '错误', mb_ok);
end;
end;
end;

function TCXPropSheet.ReplacePage(uPageID: UINT;
lpfnReplaceWith: TFNADDPROPSHEETPAGE; lParam: LPARAM):
HResult;
begin
Result:=E_NOTIMPL;//同文件关联时,外壳不调用ReplacePage,所
以不用实现
end;
回调函数处理属性页的消息,主要要响应WM_INITDIALOG消息来初始
化页面显示信息,响应WM_COMMAND消息来处理用户交互,响应
WM_NOTIFY消息来处理页面切换或关闭后处理操作结果。


function DialogProc(hwndDlg: HWnd; Msg: UINT; wParam:
wParam;
lParam: LPARAM): Bool; stdcall;
var
PageObj: TCXPropSheet;
filename: string;
displayName : string;
buffer: array[0..255]of char;
SheetHWnd: HWnd;
begin
result:=false;
try
if Msg=WM_INITDIALOG then begin//初始化界面

//获得lparam传递过来的对象
pageObj:=TCXPropSheet(PPropSheetPage(lParam)^.lParam);
//保存对象信息
SetWindowLong(hwndDlg, DWL_USER, integer(pageObj));
//设置界面显示波文件信息
SetDlgItemText(hwndDlg, 100, PChar(ExtractFileName(PageObj.
FFileName)));
OpenMedia(PageObj.FFileName);
SetDlgItemText(hwndDlg, 101,
PChar(IntToStr(GetWavStatus(MCI_WAVE_STATUS_AVGBYTESPERSEC)
)));
SetDlgItemText(hwndDlg, 102,
PChar(IntToStr(GetWavStatus(MCI_WAVE_STATUS_BITSPERSAMPLE))
));
SetDlgItemText(hwndDlg, 103,
PChar(IntToStr(GetWavStatus(MCI_WAVE_STATUS_CHANNELS))));
CloseMedia;
SetWindowLong(hwndDlg, DWL_MSGRESULT, 0);
Result:=TRUE;
end
else if(Msg=WM_COMMAND)then begin
if Lo(wParam)=110 then//用户点击了关于按钮(id=110)
MessageBox(0,'作者:hubdog'+#13#10+'email:hubdog@263.net','
关于...',MB_OK);
end else if(msg=WM_NOTIFY)then begin
sheetHwnd:=getparent(hwndDlg);//获得属性页的窗口句柄
case PNMHdr(lparam)^.code of
//页面失去焦点
PSN_KILLACTIVE:begin
SetWindowLong(hwndDlg, DWL_MSGRESULT, 0);
Result:=TRUE;
end;
end;
end;
except
on e: exception do begin
e.message:='回调处理'+e.message;
messagebox(0, pchar(e.message), '错误', mb_ok);
end;
end;
end;
 
转贴一篇文章:

利用Delphi编写Windows外壳扩展

利用Delphi编写Windows外壳扩展
; 对于操作系统原理比较了解的朋友都会知道,一个完备的操作系统都会提供了一个外壳(Shell),以方便普通的用户
使用操作系统提供的各种功能。Windows(在这里指的是Windows 95/Windows NT4.0以上版本的操作系统)的外壳不但提供
了方便美观的GUI图形界面,而且还提供了强大的外壳扩展功能,大家可能在很多软件中看到这些外壳扩展了。例如在你的
系统中安装了Winzip的话,当你在Windows Explore中鼠标右键点击文件夹或者文件后,在弹出菜单中就会出现Winzip的压
缩菜单。又或者Bullet FTP中在Windows资源管理器中出现的FTP站点文件夹。
; Windows支持七种类型的外壳扩展(称为Handler),它们相应的作用简述如下:

  (1)Context menu handlers:向特定类型的文件对象增添上下文相关菜单;

  (2)Drag-and-drop handlers用来支持当用户对某种类型的文件对象进行拖放操作时的OLE数据传输;

  (3)Icon handlers用来向某个文件对象提供一个特有的图标,也可以给某一类文件对象指定图标;

  (4)Property sheet handlers给文件对象增添属性页(就是右键点击文件对象或文件夹对象后,在弹出菜单中选属性
; 项后出现的对话框),属性页可以为同一类文件对象所共有,也可以给一个文件对象指定特有的属性页;

  (5)Copy-hook handlers在文件夹对象或者打印机对象被拷贝、移动、删除和重命名时,就会被系统调用,通过为Windows
; 增加Copy-hook handlers,可以允许或者禁止其中的某些操作;

  (6)Drop target handlers在一个对象被拖放到另一个对象上时,就会被系统被调用;

  (7)Data object handlers在文件被拖放、拷贝或者粘贴时,就会被系统被调用。

  Windows的所有外壳扩展都是基于COM(Component Object Model) 组件模型的,外壳是通过接口(Interface)来访问对象的。
外壳扩展被设计成32位的进程中服务器程序,并且都是以动态链接库的形式为操作系统提供服务的。因此,如果要对Windows
的用户界面进行扩充的话,则具备写COM对象的一些知识是十分必要的。 由于篇幅所限,在这里就不介绍COM,读者可以参考
微软的MSDN库或者相关的帮助文档,一个接口可以看做是一个特殊的类,它包含一组函数合过程可以用来操作一个对象。
; 写好外壳扩展程序后,必须将它们注册才能生效。所有的外壳扩展都必须在Windows注册表的HKEY_CLASSES_ROOT/CLSID键
之下进行注册。在该键下面可以找到许多名字像{0000002F-0000-0000-C000-000000000046}的键,这类键就是全局唯一类标识
符(Guid)。每一个外壳扩展都必须有一个全局唯一类标识符,Windows正是通过此唯一类标识符来找到外壳扩展处理程序的。
在类标识符之下的InProcServer32子键下记录着外壳扩展动态链接库在系统中的位置。与某种文件类型关联的外壳扩展注册在
相应类型的shellex主键下。如果所处的Windows操作系统为Windows NT,则外壳扩展还必须在注册表中的
HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/ShellExtensions/Approved主键下登记。
; 编译完外壳扩展的DLL程序后就可以用Windows本身提供的regsvr32.exe来注册该DLL服务器程序了。如果使用Delphi,也可
以在Run菜单中选择Register ActiveX Server来注册。

; 下面首先介绍一个比较常用的外壳扩展应用:上下文相关菜单,在Windows中,用鼠标右键单击文件或者文件夹时弹出的那
个菜单便称为上下文相关菜单。要动态地在上下文相关菜单中增添菜单项,可以通过写Context Menu Handler来实现。比如大家
所熟悉的WinZip和UltraEdit等软件都是通过编写Context Menu Handler来动态地向菜单中增添菜单项的。如果系统中安装了
WinZip,那么当用右键单击一个名为Windows的文件(夹)时,其上下文相关菜单就会有一个名为Add to Windows.zip的菜单项。
本文要实现的Context Menu Handler与WinZip提供的上下文菜单相似。它将在任意类型的文件对象的上下文相关菜单中添加一个
文件操作菜单项,当点击该项后,接口程序就会弹出一个文件操作窗口,执行文件拷贝、移动等操作。
;  编写Context Menu Handler必须实现IShellExtInit、IContextMenu和TComObjectFactory三个接口。IShellExtInit实现
接口的初始化,IContextMenu接口对象实现上下文相关菜单,IComObjectFactory接口实现对象的创建。
; 下面来介绍具体的程序实现。首先在Delphi中点击菜单的 File|New 项,在New Item窗口中选择DLL建立一个DLL工程文件。
然后点击菜单的 File|New 项,在New Item窗口中选择Unit建立一个Unit文件,点击点击菜单的 File|New 项,在New Item窗口
中选择Form建立一个新的窗口。将将工程文件保存为Contextmenu.dpr ,将Unit1保存为Contextmenuhandle.pas,将Form保存为
OpWindow.pas。


Contextmenu.dpr的程序清单如下:
library contextmenu;


; uses
; ComServ,


; contextmenuhandle in 'contextmenuhandle.pas',
; opwindow in 'opwindow.pas' {Form2};

exports


; DllGetClassObject,
; DllCanUnloadNow,


; DllRegisterServer,
; DllUnregisterServer;

{$R *.TLB}


;
{$R *.RES}


;
begin


;
end.


;
; Contextmenuhandle的程序清单如下:
unit ContextMenuHandle;


;
interface


; uses Windows,ActiveX,ComObj,ShlObj,Classes;

type


; TContextMenu = class(TComObject,IShellExtInit,IContextMenu)
; private


; FFileName: array[0..MAX_PATH] of Char;
; protected


; function IShellExtInit.Initialize = SEIInitialize; // Avoid compiler warning
; function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
; hKeyProgID: HKEY): HResult; stdcall;
; function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast,
; uFlags: UINT): HResult; stdcall;
; function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
; function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
; pszName: LPSTR; cchMax: UINT): HResult; stdcall;
end;


;
const


;
; Class_ContextMenu: TGUID = '{19741013-C829-11D1-8233-0020AF3E97A0}';

{全局唯一标识符(GUID)是一个16字节(128为)的值,它唯一地标识一个接口(interface)}
var


; FileList:TStringList;


implementation


;
uses ComServ, SysUtils, ShellApi, Registry,UnitForm;

function TContextMenu.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
; hKeyProgID: HKEY): HResult;
var


; StgMedium: TStgMedium;
; FormatEtc: TFormatEtc;
; FileNumber,i:Integer;
begin


; file://如果lpdobj等于Nil,则本调用失败
; if (lpdobj = nil) then begin
; Result := E_INVALIDARG;
; Exit;


; end;

; file://首先初始化并清空FileList以添加文件
; FileList:=TStringList.Create;
; FileList.Clear;


; file://初始化剪贴版格式文件
; with FormatEtc do begin
; cfFormat := CF_HDROP;
; ptd := nil;


; dwAspect := DVASPECT_CONTENT;
; lindex := -1;


; tymed := TYMED_HGLOBAL;
; end;


; Result := lpdobj.GetData(FormatEtc, StgMedium);

; if Failed(Result) then Exit;

; file://首先查询用户选中的文件的个数
; FileNumber := DragQueryFile(StgMedium.hGlobal,$FFFFFFFF,nil,0);
; file://循环读取,将所有用户选中的文件保存到FileList中
; for i:=0 to FileNumber-1 do begin
; DragQueryFile(StgMedium.hGlobal, i, FFileName, SizeOf(FFileName));
; FileList.Add(FFileName);
; Result := NOERROR;


; end;

; ReleaseStgMedium(StgMedium);
end;


;
function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
; idCmdLast, uFlags: UINT): HResult;
begin


; Result := 0;
; if ((uFlags and $0000000F) = CMF_NORMAL) or
; ((uFlags and CMF_EXPLORE) <> 0) then begin
; // 往Context Menu中加入一个菜单项 ,菜单项的标题为察看位图文件
; InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst,
; PChar('文件操作'));


; // 返回增加菜单项的个数
; Result := 1;


; end;
end;


;
function TContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
var


; frmOP:TForm1;
begin


; // 首先确定该过程是被系统而不是被一个程序所调用
; if (HiWord(Integer(lpici.lpVerb)) <> 0) then
; begin


; Result := E_FAIL;
; Exit;


; end;
; // 确定传递的参数的有效性
; if (LoWord(lpici.lpVerb) <> 0) then begin
; Result := E_INVALIDARG;
; Exit;


; end;

; file://建立文件操作窗口
; frmOP:=TForm1.Create(nil);
; file://将所有的文件列表添加到文件操作窗口的列表中
; frmOP.ListBox1.Items := FileList;
; Result := NOERROR;


end;


function TContextMenu.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
; pszName: LPSTR; cchMax: UINT): HRESULT;
begin


; if (idCmd = 0) then begin
; if (uType = GCS_HELPTEXT) then
; {返回该菜单项的帮助信息,此帮助信息将在用户把鼠标
; 移动到该菜单项时出现在状态条上。}
; StrCopy(pszName, PChar('点击该菜单项将执行文件操作'));
; Result := NOERROR;


; end
; else


; Result := E_INVALIDARG;
end;


;
type


; TContextMenuFactory = class(TComObjectFactory)
; public


; procedure UpdateRegistry(Register: Boolean); override;
end;


;
procedure TContextMenuFactory.UpdateRegistry(Register: Boolean);
var


; ClassID: string;
begin


; if Register then begin
; inherited UpdateRegistry(Register);
; ClassID := GUIDToString(Class_ContextMenu);
; file://当注册扩展库文件时,添加库到注册表中
; CreateRegKey('*/shellex', '', '');
; CreateRegKey('*/shellex/ContextMenuHandlers', '', '');
; CreateRegKey('*/shellex/ContextMenuHandlers/FileOpreation', '', ClassID);

; file://如果操作系统为Windows NT的话
; if (Win32Platform = VER_PLATFORM_WIN32_NT) then
; with TRegistry.Create do
; try


; RootKey := HKEY_LOCAL_MACHINE;
; OpenKey('SOFTWARE/Microsoft/Windows/CurrentVersion/Shell Extensions', True);
; OpenKey('Approved', True);
; WriteString(ClassID, 'Context Menu Shell Extension');
; finally


; Free;
; end;


; end
; else begin


; DeleteRegKey('*/shellex/ContextMenuHandlers/FileOpreation');
; inherited UpdateRegistry(Register);
; end;


end;

;


;
initialization


;TContextMenuFactory.Create(ComServer, TContextMenu, Class_ContextMenu,
; '', 'Context Menu Shell Extension', ciMultiInstance,tmApartment);

end.


;

; 在OpWindow窗口中加入一个TListBox控件和两个TButton控件,OpWindows.pas的程序清单如下:
unit opwindow;


;
interface


;
uses


; Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
; ExtCtrls, StdCtrls,shlobj,shellapi,ActiveX;

type


; TForm1 = class(TForm)
; ListBox1: TListBox;


; Button1: TButton;
; Button2: TButton;


; procedure FormCreate(Sender: TObject);
; procedure FormClose(Sender: TObject; var Action: TCloseAction);
; procedure Button1Click(Sender: TObject);
; procedure Button2Click(Sender: TObject);
; private


; { Private declarations }
; public


; FileList:TStringList;
; { Public declarations }
; end;


;
var


; Form1: TForm1;

implementation


;
{$R *.DFM}


;
procedure TForm1.FormCreate(Sender: TObject);
begin


; FileList:=TStringList.Create;
; Button1.Caption :='复制文件';
; Button2.Caption :='移动文件';
; Self.Show;


end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin


; FileList.Free;
end;


;
procedure TForm1.Button1Click(Sender: TObject);
var


; sPath:string;
; fsTemp:SHFILEOPSTRUCT;
; i:integer;


begin
; sPath:=InputBox('文件操作','输入复制路径','c:/windows');
; if sPath<>''then begin
; fsTemp.Wnd := Self.Handle;
; file://设置文件操作类型
; fsTemp.wFunc :=FO_COPY;
; file://允许执行撤消操作
; fsTemp.fFlags :=FOF_ALLOWUNDO;
; for i:=0 to ListBox1.Items.Count-1 do begin
; file://源文件全路径名
; fsTemp.pFrom := PChar(ListBox1.Items.Strings);
; file://要复制到的路径
; fsTemp.pTo := PChar(sPath);
; fsTemp.lpszProgressTitle:='拷贝文件';
; if SHFileOperation(fsTemp)<>0 then
; ShowMessage('文件复制失败');
; end;


; end;
end;


;
procedure TForm1.Button2Click(Sender: TObject);
var


; sPath:string;
; fsTemp:SHFILEOPSTRUCT;
; i:integer;


begin
; sPath:=InputBox('文件操作','输入移动路径','c:/windows');
; if sPath<>''then begin
; fsTemp.Wnd := Self.Handle;
; fsTemp.wFunc :=FO_MOVE;
; fsTemp.fFlags :=FOF_ALLOWUNDO;
; for i:=0 to ListBox1.Items.Count-1 do begin
; fsTemp.pFrom := PChar(ListBox1.Items.Strings);
; fsTemp.pTo := PChar(sPath);
; fsTemp.lpszProgressTitle:='移动文件';
; if SHFileOperation(fsTemp)<>0 then
; ShowMessage('文件复制失败');
; end;


; end;
end;


;
end.


;
; 点击菜单的 Project | Build ContextMenu 项,Delphi就会建立Contextmenu.dll文件,这个就是上下文相关菜单程序了。
使用,Regsvr32.exe 注册程序,然后在Windows的Explore 中在任意的一个或者几个文件中点击鼠标右键,在上下文菜单中就会
多一个文件操作的菜单项,点击该项,在弹出窗口的列表中会列出你所选择的所有文件的文件名,你可以选择拷贝文件按钮或者
移动文件按钮执行文件操作。
 
to:YB_unique
; 这篇文章我看过,可是我照做了一个,在添加属性页时出现访问违规(if not lpfnAddPage(HPSP, lParam) then),你可以给我一个示例吗。

to:卷起千堆雪tyn
; 这个我已经试出来过了。

第一个问题有哪位大侠知道吗?我看到有篇“实现HTML对话框(就是象IE的ABOUT对话框那种)”
是用VC++写的,我想把它改成Delphi,可是在参数传送时总是出现“Invaild variant conversion”。
函数原形是这样的:
typedef HRESULT STDAPICALLTYPE SHOWHTMLDIALOGFN(
; ; HWND hwndParent,
; ; IMoniker *pmk,
; ; VARIANT *pvarArgIn,
; ; TCHAR* pchOptions,
; ; VARIANT *pvarArgOut
);

我转换成:
Function ShowHTMLDialog(
; ; hwndParent: HWND;
; ; pmk: PIMoniker;
; ; pvarArgIn: PVariant; // 这里转换成 Variant 或 TVarData 都会出现上面的错误。
; ; pchOptions: PChar;
; ; pvarArgOut :PVariant //// 这里转换成 Variant 或 TVarData 都会出现上面的错误。
; ; ):HRESULT; stdcall;external 'mshtml.dll' name 'ShowHTMLDialog';

调用是这样的:
v: Variant;

ShowHTMLDialog(null,@imk,@v,nil,@v);
 
多谢 tyn的回答,也帮了我的忙。
我在
http://211.101.4.25/delphibbs/dispq.asp?lid=655117
问了类似的问题一直没有得到满意的答案。
tyn,你可以到我那个问题取分! [:D]
Xxfeng我借此地再问个问题,[8D]
就是如果我要是想在上下文菜单中多做几个菜单项如何解决?
我看了上面的例子,又查了help没有将这种情况试出来。
并且我想在上下文菜单中列出一个类似软件名的项,当
鼠标选中时出现其子菜单。我看help中有实现子菜单的函数
CreatePopupMenu,但我试了几次不知如何和 InsertMenu、
QueryContextMenu、InvokeCommand等一起用。谁有这方面的经验
指点一下,多谢多谢!
回答在这里或到
http://211.101.4.25/delphibbs/dispq.asp?lid=655117
均可。
取分一定要到
http://211.101.4.25/delphibbs/dispq.asp?lid=655117
这里喽。[:)]
 
...........................
 
哪位大侠帮着看看,如果分少我可以再加。
 
xxfeng,最近这里大侠太少,自己找书看吧!
 
大侠都开始冬眠了??[:(]
 
在Delphi中也有variant变量(数据类型)啊!对VC我不熟,没有发言权!
在Delphi里使用该变量没什么特别的,只是使用完以后要指的释放变量,如:yourvariant:=Unassigned;
我想你只是要实现HTML对话框,呵呵!我特意还去看了一下IE的About对话框效果(还从未留意过)!
没什么特别啊!用Delphi可以做出比这好一百倍的效果!
"添加属性页时出现访问违规"问题让我先看看想想!
 
问题1
; ; 我已解决了。是调用时的参数错了:ShowHTMLDialog(null,pointer(imk),@v,nil,@v);
问题2
; ;还是没有试出来。

提前。
 
多人接受答案了。
 
后退
顶部