宁波·忻孝委 (E-mail):(1)Office软件能否在Windows NT Workstation下运行?(2)如何在VC++ 5.0中激活控制面板或拨号网络中的属性(如调制解调器和连接)?(3)在PowerBuilder中菜单对象有一个Select事件,而在VC++中却没有,如何实现相应功能?(4)一些程序既不在启动菜单中也不在Win.ini的Load=项中,却和Windows 95一起启动,如RealPlayer,这是如何实现的?
李海:(1) Office软件可以在Windows NT Workstation下运行。
(2)表面上看,控制面板和拨号网络中的属性对话框是相同的,但实际在调用时有所不同。调用控制面板的属性对话框比较简单。在Shell32.dll中有一个函数Control_RunDLL,该函数可以激活控制面板的属性对话框。不过调用这个函数通常借助Windows 95的命令行命令rundll32.exe。rundll32.exe在Windows 95目录下,它可以用来调用DLL中的函数。例如,要调用控制面板中的Modem属性,执行下面的命令就行了:
rundll32.exe shell32.dll,Control_RunDLL modem.cpl 常用的还有以下这些: 桌面属性: 背景: rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0 外观:rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,2 屏幕保护程序:rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,1 设置:rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,3 常规:rundll32.exe shell32.dll,Control_RunDLL access.cpl,,5 显示:rundll32.exe shell32.dll,Control_RunDLL access.cpl,,3 键盘:rundll32.exe shell32.dll,Control_RunDLL access.cpl,,1 鼠标:rundll32.exe shell32.dll,Control_RunDLL access.cpl,,4 声音:rundll32.exe shell32.dll,Control_RunDLL access.cpl,,2要调用拨号网络中或其它文件的属性对话框,需要调用IContextMenu接口(interface)的InvokeCommand方法。具体内容可以看VC++的帮助文件。
(3)我想你说的是Selected事件,Select大概是笔误。Selected事件对应的Windows消息是WM_MENUSELECT,当用户用方向键在菜单项上移动或按住鼠标左键在菜单上移动鼠标箭头时,Windows发送这条消息。VC++的MFC类库的成员函数为CWnd::OnMenuSelect。这个函数的原型是:
afx_msg void OnMenuSelect( UINT nItemID, UINT nFlags HMENU hSysMenu );
其中nItemID是用户选中的菜单项的ID,如果该菜单项属于一个弹出式菜单,hSysMenu是该弹出式菜单的句柄,具体内容可以参见VC++的帮助文件。这个消息实际上只有一个作用,就是当用户在菜单项上移动时,程序在状态条上显示相应的帮助信息。VC++中有一个范例程序DLGCBR32演示了如何利用这一消息来显示帮助信息。
(4)我没有安装RealPlayer,但我相信它和许多软件一样是通过修改注册簿(registry)来实现这一功能的。你可以使用RegEdit修改注册簿(如下图所示),在HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run下,你可以添加自己的软件。具体的方法是在这个主键(key)下新建一个串值(string),该串值的名字是无所谓的,数据部分是你要运行的软件的名字(最好使用全路径)。这样,每次Windows 95在启动时就会调用该软件了。这种方法不见得比启动菜单好多少,但在图中你可能注意到了另一个主键RunOnce,倒是非常有用。如同其字面的意思,在RunOnce主键定义的软件只在Windows 95启动时运行一次,运行后Windows 95就清除该主键下的所有值,以后再启动时就不运行这些程序了。许多安装程序都会修改这一键值,然后重新启动用户的机器,由RunOnce指定的程序来完成剩余的安装任务。
北京·Ace (E-mail):请问如何在VB 5.0中使用超文本连接?怎样让鼠标变成“手”形光标?
李海:在VB 5.0中使用超文件链接有两种常用方法。一种是使用VB 5.0自身的WebBrowser控件,具体的作法是在控件列表中选择Microsoft
Internet Controls。加入控件后,使用WebBrowser1.Navigate *http://www.zdnet.cn.net/pcc*语句,你就可以访问我们杂志的主页了。这个控件实际是调用Internet
Explorer,所以它支持IE的所有特性,但前提是你的机器必须装有IE 3.0或更高版本。另一种办法是采用Windows API中的ShellExecute语句。首先加入如下声明:
Private Declare Function ShellExecute Lib _ "shell32.dll" Alias "ShellExecuteA"
_ (ByVal hwnd As Long, ByVal lpOperation _ As String, ByVal lpFile As String,
ByVal _ lpParameters As String, ByVal lpDirectory _ As String, ByVal nShowCmd
As Long) As Long
在调用超文件链接时,使用下面的语句:
ShellExecute hwnd, "Open", *http://www.zdnet.cn.net/pcc*, 0, 0, 0 这个语句调用默认的浏览器(可以是Netscape
Navigator,或其它的浏览器)打开该超链接。具体采用哪种方法要看你的需要。
至于如何让鼠标变成“手”形光标就简单多了,首先修改控件的MousePointer改为99,然后在MouseIcon属性中加入“手”形光标文件(*.ico或*.cur格式)。
北京·刘治开(E-mail):我想请问在VC++ 5.0中如何通过OLE或ActiveX技术访问Excel对象的资源?例如获取单元格中的内容、控制Excel菜单中的某些功能等等。
李海:在VC++ 中调用Excel对象的技术叫OLE Automation(现在叫ActiveX Automation,但无实质的不同)。它实技上是用VC++ 5.0编写OLE Automation的客户机,而让Excel作为OLE Automation服务器。当然,VC++ 5.0也可以用来编写OLE Automation的服务器,让Excel作为客户机。Automation技术是一项非常重要的技术,它使得你可以在不同的软件之间进行非常方便的调用,比如可以让FoxPro、Delphi、VB去调用Excel。Excel是从5.0版开始支持Automation技术,客户程序调用Excel的过程类似于使用VBA(Visual Basic for Application)进行编程,所以要想实现Automation技术,你不单要掌握VC++,还要了解VBA。Word虽然从Word 97才开始支持VBA,但从6.0版就已经支持Automation技术了,只不过使用的是Word Basic。其它的Office软件也支持Automation技术。 在VC++中编写Automation客户程序是非常容易的。在ClassWizard中选择Automation标签,然后按Add Class按钮,再选择From a type lib,然后去找Excel的type lib文件。该文件在Excel目录下,Excel 5.0为XL50EN.OLB(英文版)和XL50CHS.OLB(简体中文版),Excel 97为XL5EN32.OLB和XL5CHS32.OLB,选择其一即可。此时,ClassWizard会显示所有可用的Excel对象供选择(见图)。如果你要获取单元格中的内容,可以选择Worksheet等对象,当你选择了相应的对象后,ClassWizard将建立C++的类,你可以在程序中调用该类的成员。
上海·李波涛 (E-mail):在VB 5.0中,能否利用VB所附带的报表生成器Crystal Reports将Data控件的Recordset对象的虚拟表打印出来?怎样通过Recordset对象的虚拟表制作出美观的报表?
李海:VB 5.0附带的Crystal Reports 4.x提供了对Recordset对象的支持。若要实现数据控件的报表输出,需要使用Crystal Reports的ActiveX控件。所以,你需要先从控件列表中选择Crystal Reports Control 4.6,放一个控件在Form中,并设置好Data控件的有关属性。 设置Crystal Reports控件的DataSource属性为Data控件(如Data1),再设置ReportSource属性为3。若ReportSource属性为0,表示使用报表文件,若为3表示数据控件。在运行时,调用CrystalReport1.Action = 1就可以输出报表。与此相关的属性还有BoundReportFooter和BoundReportHeading,它们决定是否打印页眉和页脚。当然,采用这种形式输出的报表绝对称不上美观。 若要使报表美观,需要对报表格式进行修改。如果在设计时改变报表格式,在完成对Crystal Reports控件的设计后,选择Custom属性,在属性对话框中选择Data-Bound Report标签(见图),按Save Report As按钮,将数据保存为报表样板。在Crystal Reports Desiner中打开该样板,修改字体等属性,使报表更美观。打印修改后的报表的方法同前面的方法不同,应将ReportSource属性为0,将ReportFileName设为报表样板文件。报表样板也可以在程序运行时生成。首先如前设置好Crystal Reports控件,将打印输出Destination属性设为0,即Preview Window,运行程序,在打印预览窗口选Export按钮,以.RPT格式输出。编辑和打印该报表样本的方法同前。Crystal Report对于这种自定义格式的报表有一个限制,就是Data控件的RecordSource属性在报表修改前后不能改变。
南京·靖磊 (E-mail):我在VB 5中使用Input(number, [#]filenumber)时,用LOF([#]filenumber)来表示文件长度;但执行中VB 5提示错误:“输出超出文件尾”。用FileLen(filepath)得出文件长度也一样。这是怎么回事?
Private Sub Command3_Click() Dim TextLine As String Dim filenum1 As Integer,filenum2 As Integer Dim ds As Double Dim de As Double filenum1 = FreeFile() Open "d:\test1.txt" For Input As filenum1 ' 打开文件。 Dim l As Integer l = FileLen("d:\test1.txt") ' 用FileLen查询文件长度 filenum2 = FreeFile() ' 取下一个空文件号 Open "d:\output.txt" For Output As filenum2 ds = Timer TextLine = Input(LOF(filenum1), filenum1) ' 出错 Write #filenum2, TextLine '——————————————————————————以下代码可正常使用 Do While Not EOF(filenum1) ' 循环至文件尾。 Line Input #filenum1, TextLine ' 读入一行数据并将其赋予某变量。 'Debug.Print TextLine ' 在调试窗口中显示数据。 Print #filenum2, TextLine ' 写入新建的文件 Loop '—————————————————————————————————— de = Timer Debug.Print de - ds Close filenum1 Close filenum2 ' 关闭文件。 End Sub
李海:首先感谢你寄来了相关的程序片断。我经常收到一些关于程序设计的问题,可连一行代码都没提供,只有出错信息,真不知如何下手。正是借助你的程序,我一下子就看出了问题,否则我的解答可能是一堆废话了。很明显问题出在Input语句,但我们得从VB处理字符串的方式讲起。早期的VB是采用单字节处理方式(通常也称为ANSI方式),也就说一个英文字母用一个字节表示,一个汉字算两个字节,当然这样就可能出现半个汉字的问题。从VB 4.0起,VB采用了一种新的处理方式,即内部采用Unicode方式,即不论英文字母还是汉字,一律用两个字节表示,但Unicode还不够普及,所以VB只是在其内部完全使用Unicode,而在外部仍转换为人们习惯的ANSI方式,但在字符串处理上与先前的版本有所不同。例如:在中文Windows或英文Windows外挂RichWin 97中,Len(*电子&电脑*)=5(这里的&号为半角字符),而在以前的版本或纯英文Windows中Len(*电子&电脑*)=9。除了Len、Left、Right等字符串函数受此影响外,Input函数也受此影响。Input函数的第一个参数是要读入的字符数,它采用的是和Len一样的计数方式,即一个英文字母算一个字符,而一个汉字(两个字节)算一个字符。这看起来是个好主意,你不会读入半个汉字,但实际上糟透了,因为VB的LOF函数和FileLen函数都返回的是字节数,VB中没有一个能区分汉字和英文字母的LOF函数或FileLen函数!如果你测试文件d:\test1.txt全部是英文,那么你的这段程序可以正确运行,尽管你没有寄来测试文件,但我可以和你打赌,这个文件中有中文。如果你的文件中有100个汉字,那么LOF函数和FileLen函数返回文件长度200个字符,执行Input(200, filenum1),VB读到第100个汉字时就把文件读完了,所以提示错误:“输出超出文件尾”。可能会有人想,把LOF函数和FileLen函数返回文件长度除以2不就行了。是的,如果你的文件中只包括全角字符,那么这么改就对了,但我们平时接触的很多文件都是全角半角混杂的。VB提供了InputB函数,它可以按字节数读入文件,但实际上这个函数有错误,如果你用它读入的文件,那么你得到的可能是象“??????”这样的字符串。我想很多用户都见过这种奇怪的情况。Line Input语句就没有这个问题,因为它不计数,只看文件中是否有回车和换行,但Line Input语句比Input语句慢得多。怎么解决这个问题呢,我有一个办法不见得好,但可以应急。把Open打开文件的方式由Input改为Binary方式,即 Open "d:\test1.txt" For Binary As filenum1 然后,使用Get语句代替Input语句: TextLine = Space(LOF(filenum1)) Get filenum1, , TextLine 这个语句速度同Input函数相当,而没有前述的问题。
马大明 (E-mail):在Visaul Basic 3.0中使用通信控件comm.input时,当接收一个高位为1(ASCII码 > 128)的字节时,可以正确接收;但在Visaul Basic 4.0中却出现异常,接收到的字节的高位为0,导致不能正常接收汉字,在发送端汉字不能按字节传送(使用comm.output),只能传送完整的一个汉字或一串字符。由于在通信中经常是以字节为单位发送,所以给传送汉字带来麻烦。我在Visaul Basic 4.0中写的程序如下:
dim i as integer for i=0 to 255 print i,chr(i),asc(chr(i)) next i 高位为1的字节输出的是: 126 126 127 127 128 0 129 0 ... 254 0 255 255 奇怪的是255竟然是正确的。 使用: len("123汉字")=5 为真, 而: len("123汉字")=7 为假。这在处理汉字时确实很方便,但在涉及到API函数时又很不一致。上述问题可能是Visaul Basic 4.0对UNICODE的支持造成的,但我还是想得到Visaul Basic 3.0的效果,不知如何解决?(操作系统是:Windows 95 中文版。)
李海:在上一个问题,我简单地说明了VB 4.0处理字符串的原理。Visual Basic 4.0对于绝大多数字符串函数都提供了相对应的单字节处理函数,如同Len函数相对应的LenB,Right与RightB、Left与LeftB、Mid与MidB等等。不过Visual Basic在这种单字节处理中仍可能存在这样那样的问题。
如果您有任何建议,请给我发电子邮件:
。
版权所有 李海,热情软件屋 1997-2006