Ding 据微软公司说IE4的URL支持RES协议,具体的语法为:"res://resource file[/resourcetype]/resource id" ,我试过"res://c:\windows\system\shdocvw.dll/navcancl.htm",没问题;但如自己用VC作个DLL,就怎么也不行,不知何故?
李海:由于你没有说你是如何制作DLL和调用你自己的DLL的。这里只好详细地介绍一下res://协议的详细用法。Res://协议是IE 4.0预定义的一个协议,它的基本语法正如你所说的。其中resource file指的是含有资源的模块的文件名,请注意这里的路径分隔符只能使用“\”,而不能使用“/”。 Resourcetype是资源类型,它是一个字符串或数字。常用的资源类型都对应着一个数,比如BITMAP对应着RT_BITMAP=2,这些常数定义在VC++的WINUSER.H可以找到,如果资源类型是数字,要在数字前面加上“#”号。Resourcetype可以省略,默认为RT_HTML=23,即HTML文件。RT_HTML在VC++ 5.0中没有定义,但现在已经广泛使用。 Resource id表示资源的ID号。在这里要注意一个问题:在VC++中定义资源的时候,通常是使用数字常量,比如ID_BITMAP1,它代表的数字可能是101。而在使用res://协议时,不能使用ID_BITMAP1(在DLL中并没有这个符号),而必须使用#101来代表资源。例如要显示一个位图资源,其ID号为101,应为res://mydll.dll/#2/#101。
如果在VC++制作的DLL中加入HTML资源文件,可以这样做:选择Import资源,然后选择一个HTML文件,当VC++提示资源类型时输入23(图1)。然后修改该属性的ID,例如"MYHTML.HTM"。这里的引号是必须输入的,如果不输入引号,VC++会指定一个数字给这个资源,调用的方法会有所不同。这样你可以使用res://mydll.dll/myhtml.htm来调用这个HTML文件。HTML文件中包含的图形文件也应该以这种方式插入。
图1 当VC++提示HTML文件的资源类型时输入23
广州 郏军波 我在用VB 5.0编写一个屏幕保护程序时, 调用ShowCursor关闭指针, 但未能找到对任务栏的关闭函数. VB 5.0能否调用有关函数实现对任务栏的控制? 如果可以, 如何实现?
李海:可以使用FindWindow和ShowWindow来控制任务栏。下面给出一个例子程序。首先建立一个窗体和两个按钮。在窗体声明部分输入如下定义:
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As Any) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Const SW_HIDE = 0
Const SW_SHOWNORMAL = 1
然后在按钮的事件中输入如下代码:
Private Sub Command1_Click()
Dim hTaskBar As Integer
hTaskBar = FindWindow("Shell_TrayWnd", 0&)
ShowWindow hTaskBar, SW_HIDE
End Sub
Private Sub Command2_Click()
Dim hTaskBar As Integer
hTaskBar = FindWindow("Shell_TrayWnd", 0&)
ShowWindow hTaskBar, SW_SHOWNORMAL
End Sub
你按Command1将隐藏任务栏,而按Command2将显示任务栏。
另外,还有一个办法可以使VB的窗体可以遮住任务栏。你可以在设计时将窗体的WindowState属性设为2,MaxButton设为False。这样,你的程序运行时,窗体会遮住任务栏,即使任务条被设置为“总在最前”。这本是VB的一个Bug,但可能更适合于你的屏幕保护程序。
梁寒刚
我的机器里装有Paint shop pro 5,我用VFP 3.0编写的应用程序中所有表单文件*.sct的文件类型均被改成了Paint shop pro 5 Image文件类型。所有的表单文件均可在VFP 3.0中使用,但无法编译成*.app或*.exe文件,提示为Not a table,但在项目管理器能够见到所有的文件。如何将这些文件的类型再改回sct类型?
李海:你当然可以使用程序管理器修改文件的关联,但我想你的问题并不是因为文件关联所产生的。我的机器与你类似,但在编译的时候没有任何问题,而且Visual FoxPro 3.0在安装时也没有建立同*.sct文件的关联。VFP 3.0的表单文件实际上是一种表,*.scx相当于*.dbf,而*.sct相当于*.fpt,你可以把表单文件当作数据库表打开浏览。VFP的其他很多文件也是如此,包括项目文件本身。从你的提示信息来看,应该是在编译时发现某个文件不是合法的表文件的格式。由于你的所有的表单文件均可在VFP 3.0中使用,所以可能是其他文件可能有损坏。看来你需要另外寻找原因。
ShiWei 我听说用Borland C++的Workshop可以修改Installshield Express使其呈现中文安装界面,但不知道具体做法,希望给予帮助。
李海:在Installshield Express的Lang\Eng目录下包含着英文资源文件。其中的_ISRES16.DLL和_ISRES32.DLL分别是16位和32位版本的资源文件。Installshield Express所使用的对话框资源都在这两个文件中,而Installshield Express显示的错误信息和提示信息也都以字符串资源的形式包含在这两个文件中。你可以使用Borland C++的Workshop修改DLL的资源,改为你喜欢的方式。注意,有些字符串中包含有%s等符号,修改时必须保留。
华文生 在 VB 的 PictureBox 控件里,可以用 Circle, Line, Point 等方式在图象表面绘图,然后用 Cls 的方式擦除先前用 Circle, Line, Point 等方式画上的图形。在 Delphi 3.0 中,采用 TCanvas 对象可以在图象上绘图,但却找不到类似 VB 的 Cls 方式来擦除已画上的图形。请问有什么方法可以解决这个问题?
李海:Delphi 3.0没有Cls方法。你可以使用画矩形的办法来擦除图象,如:
Canvas.Brush.Color := ClWhite;
Canvas.FillRect(Canvas.ClipRect);
你可以指定Canvas.Brush.Color为你希望的颜色。
qqboy 在Visual Basic 5.0中,怎么样才能把可执行文件(如.EXE文件、.DLL文件等)中包含的图标显示在Picture Box中?要是该文件包含有多个图标,怎样显示指定的一个?能举一个程序例子说明吗?
李海:可以使用Windows API的ExtractIcon可以完成这个任务。ExtractIcon的定义如下:
Declare Function ExtractIcon Lib "shell32.dll" Alias "ExtractIconA" (ByVal hInst As Long, ByVal lpszExeFileName As String, ByVal nIconIndex As Long) As Long
第一个参数是调用这个函数的实例句柄,在VB中可以使用App.hInstance得到这个句柄。第二个参数是包含图标的文件名。当该文件包含有多个图标,第三个参数指定该图标的索引。使用时,首先使用ExtractIcon(App.hInstance, filename, -1)得到文件中图标的个数。然后,再次使用hIcon = ExtractIcon(App.hInstance, filename, i)来获得第i个图标的句柄。然后使用DrawIcon(Picture1.hDC, 0, 0, hIcon)可以将图标显示在Picture Box中。
广东广州 陈永福 我用Delphi 3进行数据库编程时,希望能有一种简单且直接的方法永久地删除数据库表中带有删除标记的记录,就如使用Foxpro或Dbase中的PACK命令那样,而不希望要通过中间数据库过渡的形式,如 TABLE1.BatchMove方法),以节省宝贵的空间。
李海:对于各种数据库类型,只有xBase和Paradox采用这种删除方式,为了释放空间你必须借助BDE API中。关于BDE API的详细介绍参见Delphi的BDE API Help。对于Paradox,使用DBIDoRestructure语句,而对于xBase采用DBIPackTable语句。下面是一个永久地删除Paradox数据库表中带有删除标记的记录的例子:
procedure TForm1.PackParadoxTable( TableName, Alias : String);
{TableName should be with extension - .DB}
var
hDB :hDBIDb;
hCursor :hDBICur;
DBResult :DBIResult;
PdoxStruct :CRTblDesc;
szTableName : PChar;
szAlias : PChar;
PathLength : Integer;
ErrMsg : String;
begin
PathLength := 120;
GetMem(szTableName, PathLength);
GetMem(szAlias, 20);
StrPCopy(szTableName, TableName);
StrPCopy(szAlias, Alias);
Try
{First you need to initialize the Borland Database Engine}
DBResult := DBIInit(nil);
if DBResult <> DBIERR_NONE then begin
MessageDlg('Error Initializing BDE',mtError,[mbOk],0);
DBIExit;
Exit;
end;
{If the Initializing was OK then Open the Database}
DBResult := DBIOpenDatabase(szAlias,'STANDARD',DBIREADONLY,DBIOPENSHARED,'',0,nil,nil,hDB);
if DBResult <> DBIERR_NONE then begin
case DBResult of
DBIERR_INVALIDFILENAME : ErrMsg := 'Invalid FileName';
DBIERR_NOSUCHFILE : ErrMsg := 'No Such File';
DBIERR_TABLEREADONLY : ErrMsg := 'Table is READ ONLY';
DBIERR_NOTSUFFTABLERIGHTS : ErrMsg := 'Not Sufficent Table Rights';
DBIERR_INVALIDHNDL : ErrMsg := 'Invalid Handle';
DBIERR_LOCKED : ErrMsg := 'Table Locked';
DBIERR_DIRBUSY : ErrMsg := 'Directory Busy';
else
ErrMsg := 'Unknown Error';
end;
MessageDlg(ErrMsg,mtError,[mbOk],0);
DBIExit;
Exit;
end;
{Opening the table returns a Handle to the table's cursor. So now Open the Table}
DBResult := DBIOpenTable(hDB,szTableName,'','','',0,DBIREADWRITE,DBIOPENEXCL,
xltNONE,False,nil,hCursor);
if DBResult <> DBIERR_NONE then begin
case DBResult of
DBIERR_INVALIDFILENAME : ErrMsg := 'Invalid FileName';
DBIERR_NOSUCHFILE : ErrMsg := 'No Such File';
DBIERR_TABLEREADONLY : ErrMsg := 'Table is READ ONLY';
DBIERR_NOTSUFFTABLERIGHTS : ErrMsg := 'Not Sufficent Table Rights';
DBIERR_INVALIDHNDL : ErrMsg := 'Invalid Handle';
DBIERR_LOCKED : ErrMsg := 'Table Locked';
DBIERR_DIRBUSY : ErrMsg := 'Directory Busy';
DBIERR_OPENTBLLIMIT : ErrMsg := 'Open Tables Limit';
DBIERR_INVALIDINDEXNAME : ErrMsg := 'Invalid Index Name';
DBIERR_NOSUCHTABLE : ErrMsg := 'No Such Table';
else
ErrMsg := 'Unknown Error';
end;
MessageDlg(ErrMsg,mtError,[mbOk],0);
DBICloseDatabase(hDB);
DBIExit;
Exit;
end;
Try
DBICloseCursor(hCursor); {Table Cursor needs to be closed}
{Initialize the record Structure CRTblDesc}
FillChar(PdoxStruct, SizeOf(CRTblDesc),0);
StrPCopy(PdoxStruct.szTblName, TableName);
PdoxStruct.bPack := True;
DBResult := DBIDoRestructure(hDB,1,@PdoxStruct,nil,nil,nil,False);
if DBResult <> DBIERR_NONE then
MessageDlg('Failed to Pack Table',mtError,[mbOk],0);
Finally
DBICloseCursor(hCursor);
DBICloseDatabase(hDB);
DBIExit;
end;
Finally
FreeMem(szTableName, PathLength);
FreeMem(szAlias, 20);
end;
end;
四川 邓世学 如何在VB 5.0的应用程序中获得外来的参数?如用VB 5.0的应用程序生成Programm.exe,在Win95环境中选择运行,输入“Program.exe MyString”。那对于Programm.exe这个程序如何获得“My String”这个参数。
李海:VB 5.0的Command函数就是用来获取命令行参数的。如果你在命令行输入“Program.exe MyString”,该函数返回“MyString”。该函数返回的字符串是区分大小写的,如果你对命令行的处理是不区分大小写的,别忘了使用Ucase或Lcase函数处理一下。为了方便在集成环境中调试,你可以在Project Properties对话框的Make标签中设置命令行参数(下图)。
图 在Project Properties对话框中可以设置命令行参数以方便调试
四川 邓世学 如何在VB 5.0的应用程序中修改Windows 95的注册表信息,如建立一个主键,须在注册表中加入语句:
Hkey_Classses_Root\映象文件\Shell\打开\Command=D:\\tools\\Program.exe %1
李海:、虽然VB提供了GetSetting、SaveSetting等函数,但它们只能处理HKEY_CURRENT_USER\Software\VB and VBA Program Settings下面的子键。所以要实现对注册簿的修改,通常需要调用Windows API。在Windows API中有一系列函数专门处理注册簿操作,这些函数基本上都以Reg开头。一般读写一个键值的步骤是
为了方便在VB中使用,我们采用了如下的形式进行封装:
Global Const REG_SZ As Long = 1
Global Const REG_DWORD As Long = 4
Global Const HKEY_CLASSES_ROOT = &H80000000
Global Const HKEY_CURRENT_USER = &H80000001
Global Const HKEY_LOCAL_MACHINE = &H80000002
Global Const HKEY_USERS = &H80000003
Global Const KEY_ALL_ACCESS = &H3F
Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long
Declare Function RegCreateKeyEx Lib "advapi32.dll" Alias "RegCreateKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, ByVal Reserved As Long, ByVal lpClass As String, ByVal dwOptions As Long, ByVal samDesired As Long, ByVal lpSecurityAttributes As Long, phkResult As Long, lpdwDisposition As Long) As Long
Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, ByVal samDesired As Long, phkResult As Long) As Long
Declare Function RegSetValueExString Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal Reserved As Long, ByVal dwType As Long, ByVal lpValue As String, ByVal cbData As Long) As Long
Declare Function RegSetValueExLong Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal Reserved As Long, ByVal dwType As Long, lpValue As Long, ByVal cbData As Long) As Long
Public Function CreateNewKey(lPredefinedKey As Long, sNewKeyName As String)
Dim hNewKey As Long 'handle to the new key
Dim lRetVal As Long 'result of the RegCreateKeyEx function
lRetVal = RegCreateKeyEx(lPredefinedKey, sNewKeyName, 0&, vbNullString, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0&, hNewKey, lRetVal)
RegCloseKey (hNewKey)
End Function
Public Function SetValueEx(ByVal hKey As Long, sValueName As String, lType As Long, vValue As Variant) As Long
Dim lValue As Long
Dim sValue As String
Select Case lType
Case REG_SZ
sValue = vValue
SetValueEx = RegSetValueExString(hKey, sValueName, 0&, lType, sValue, Len(sValue))
Case REG_DWORD
lValue = vValue
SetValueEx = RegSetValueExLong(hKey, sValueName, 0&, lType, lValue, 4)
End Select
End Function
Public Function SetKeyValue(lPredefinedKey As Long, sKeyName As String, sValueName As String, vValueSetting As Variant, lValueType As Long)
Dim lRetVal As Long 'result of the SetValueEx function
Dim hKey As Long 'handle of open key
'open the specified key
lRetVal = RegOpenKeyEx(lPredefinedKey, sKeyName, 0, KEY_ALL_ACCESS, hKey)
lRetVal = SetValueEx(hKey, sValueName, lValueType, vValueSetting)
RegCloseKey (hKey)
End Function
调用时,可以使用如下的语法;
CreateNewKey HKEY_CLASSES_ROOT, "映象文件\Shell\打开\"
SetKeyValue HKEY_CLASSES_ROOT, "映象文件\Shell\打开\", "Command", " D:\tools\Program.exe %1", REG_S
如果您有任何建议,请给我发电子邮件:
。
版权所有 李海,热情软件屋 1997-2006