《电脑编程技巧与维护》2009年合订本(精华版) - 万水书苑-出版资源网
全文
(2) 《电脑编程技巧与维护》2009 年合订本(精华版). 198. public static extern bool DhcpNotifyConfigChange( string lpwszServerName, // 本地机器为 NULL string lpwszAdapterName, // 适配器名称 bool bNewIpAddress, // TRUE 表示更改 IP long dwIpIndex, // 指明第几个 IP 地址,如果只有 //该接口只有一个 IP 地址则为 0 long dwIpAddress, // IP 地址 long dwSubNetMask, //子网掩码 long nDhcpAction ); //对 DHCP 的操作 0:不修 //改, 1:启用 DHCP,2:禁用 DHCP. 在 C++中通过动态调用 DLL 中 API 函数的操作就 可以使用了。 2.1.3 使 用 WMI ( Windows Management Instrumentation)中 Win32_NetworkAdapterConfiguration 类实现 IP 地址管理. SetGateways 方法设置网关; 通过 SetDNSServerSearchOrder 方法设置 DNS 服务器地址。 由于 WMI 使用了 CIM 作为实现基础,因此在以上 的类和方法均使用一种接口定义语 MOF(Managed object Format,受管对象格式)来准确描述模型中的类 和关联,以上的方法 MOF 描述如下: uint32 EnableStatic( [in] string IPAddress[], [in] string SubnetMask[] ); uint32 SetGateways( [in] string DefaultIPGateway[], [in] uint16 GatewayCostMetric[] ); uint32 SetDNSServerSearchOrder( [in] string DNSServerSearchOrder[] );. Windows Management Instrumentation (WMI) 是 Microsoft WBEM 的实现,通过企业网络为访问和共享 管理信息主动建立的标准。WMI 符合 WBEM 标准,. 以上三种方案均可以实现在 Windows 环境中不重 新启动修改网络适配器参数,但是使用 netsh 命令行在 C++程序中调用效率不高,而使用微软未公开得 API. 并为“公用信息模型(CIM)”(它是描述存在于管理环 境中的对象的数据模型)提供完整的支持。WMI 可以 被 Microsoft 技术和工具使用,如可以与编程或脚本系 统(如 Windows 脚本宿主)一起使用 WMI 来检索大. 实现可能会受到操作系统变更的影响,为了支持个不 同版本的 Windows 本方案使用 WMI 作为本程序实现 的基础。. 部分计算机系统方面的详细配置信息(包括服务器应用 程序) ,或者对系统的配置进行更改。 在 WMI 中 Win32_NetworkAdapterConfiguration 类 实现了大多数的网络适配器的配置工作,可以通过. 2.2 程序开发 通过以上的分析,本程序主要需要实现的功能是在 Windows 环境中根据给定的配置参数对指定的网络适 配器进行配置,程序流图如下:. EnableStatic 方 法 设 置 IP 地 址 和 子 网 掩 码 ; 通 过 开始. 选择配置参数. IP地址确定. N. 随机生成根据 给定要求的IP. 设置IP并成功. N. ++IP%256. Y Y. 配置网络参数. 结束. 图1 图 1 所示的程序流图中表明了程序开始首先等待用 户的输入,即选择接入网络的物理地址,然后程序根据. 程序流图 配置文件中的数据选择恰当的配置参数,这些参数被预 先存放在 Config.ini 文件中,需要注意的是 IP 地址参数.
(3) 第四篇 网络与通信. 199. 分为两种情况,一种是确定的 IP 地址,另一种是仅提 供 IP 地址的前 3 部分,最后一部分为 0,如 192.168.1.0。. 那么程序将对原 IP 进行自增一的操作后尝试 IP 设置, 直到成功配置一个合法的 IP 地址。. 因为在实际网络中不可能配置这样的 IP 地址,程序会 自动判断参数,如果 IP 不确定那么会随机生成 IP 的最 后一部分,然后程序尝试配置,如果发生 IP 地址冲突. 为了便于使用 WMI,这里将所有的有关 WMI 的操 作封装到 CWMI 类中,如图 2 所示。. 图2 在图 2 中,chAdapter、ClassPath 等成员变量均为 CWMI 类中成员函数的功能实现使用的公共变量,具体 功能可以参考源代码。需要指出的是为了方便使用, CWMI 类仅提供了 SetIP、SetDns 和 SetGate 三个公共成 员函数分别实现 IP 地址设置、DNS 服务器设置和网关 设置。 SetIP、SetDns 和 SetGate 三个成员函除均是通过 C++调用 WMI 组件中对应的方法实现的,其实现基本 类似,这里仅以 SetIP 作简要说明,源码如下: void CWMI::SetIP(LPWSTR IPAddress, LPWSTR SubnetMask){ setIndexByAdapterName(); EnableStatic(IPAddress,SubnetMask); }. setIndexByAdapterName 是 CWMI 类实现的成员函 数,实现了对当前主机的网络适配器的选择操作。. CWMI 类 ULONG Status=0; NetWorkResource = SysAllocString(L"root\\cimv2"); WCHAR AdapterIndex[128]; wsprintf(AdapterIndex, L"Win32_NetworkAdapterConfiguration=%ld",index); InstancePath = SysAllocString(AdapterIndex); ClassPath = SysAllocString(L"Win32_Network AdapterConfiguration"); MethodName = SysAllocString(L"EnableStatic"); LPCWSTR Arg1Name = L"IPAddress"; VARIANT var1; LPCWSTR Arg2Name = L"SubnetMask"; VARIANT var2; hr = CoInitializeEx(NULL,COINIT_ MULTITHREADED); if(FAILED(hr)){. EnableStatic 成 员 函 数 是 对 WMI 中 Win32_ NetworkAdapterConfiguration 类中 EnanleStatic 方法的封 装,源代码如下:. MessageBox(NULL,L"CoInitializeEx", L"Error",MB_OK); Clean(); return hr;. HRESULT CWMI::EnableStatic(LPWSTR IPAddress,LPWSTR SubnetMask){. }.
(4) 《电脑编程技巧与维护》2009 年合订本(精华版). 200. CreateOneElementBstrArray(&var1,IPAddress);. if(SUCCEEDED(pOutInst->Get(L"ReturnValue",0, &resultParameter,NULL,NULL))){. CreateOneElementBstrArray(&var2,SubnetMask);. Status = resultParameter.ulVal; VariantClear(&resultParameter); TRACE1("返回值:%lu\n",Status);. CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_ INPROC_SERVER, IID_IWbemLocator, }. (void**)&pLocator);. else{ TRACE0("参数未能获得");. hr = pLocator->ConnectServer(NetWorkResource,NULL, NULL, NULL, 0, NULL, NULL, &pNamespace);. MessageBox(NULL,L"ExecMethod",. hr = CoSetProxyBlanket(pNamespace,. L"Error",MB_OK);. RPC_C_AUTHN_WINNT, }. RPC_C_AUTHZ_NONE, }. NULL, RPC_C_AUTHN_LEVEL_CALL,. VariantClear(&var1);. RPC_C_IMP_LEVEL_IMPERSONATE,. VariantClear(&var2);. NULL,. Clean();. EOAC_NONE);. return Status; if(FAILED(hr)). { Clean();MessageBox(NULL,. L"CoSetProxyBlanket",L"Error",MB_OK); return hr; } else hr = pNamespace->GetObject(ClassPath, 0, NULL, &pClass, NULL);. }. 其中 CreateOneElementBstrArray 是 CWMI 类的成 员函数,实现了封装一个 BSTR 数组,代码如下: void CWMI::CreateOneElementBstrArray(VARIANT* v, LPCWSTR s){ SAFEARRAYBOUND bound[1]; SAFEARRAY* array;. if(FAILED(hr)){Clean();MessageBox(NULL,. bound[0].lLbound = 0;. L"GetObject",L"Error",MB_OK);return hr; }. bound[0].cElements = 1;. else. array = SafeArrayCreate(VT_BSTR, 1, bound);. hr = pClass->GetMethod(MethodName, 0, &pInClass,. long Index = 0;. NULL);. BSTR bstr = SysAllocString(s); SafeArrayPutElement(array, &Index, bstr);. if(FAILED(hr)){ Clean();MessageBox(NULL,. SysFreeString(bstr);. L"GetMethod",L"Error",MB_OK);return hr; }. VariantInit(v);. else. v->vt = VT_BSTR | VT_ARRAY;. hr = pInClass->SpawnInstance(0, &pInInst);. v->parray = array; }. if(FAILED(hr)) { Clean();MessageBox(NULL,L"SpawnInstance", L"Error",MB_OK);return hr; } else hr = pInInst->Put(Arg1Name, 0, &var1, 0); if(FAILED(hr)){ Clean();MessageBox(NULL,L"Put", L"Error",MB_OK);return hr; } else hr = pInInst->Put(Arg2Name, 0, &var2, 0); if(FAILED(hr)){ Clean();return hr; } else{ VARIANT resultParameter; ULONG Status; hr = pNamespace->ExecMethod(InstancePath, MethodName, 0, NULL, pInInst, &pOutInst, NULL);. 2.3 设计技巧 使用 WMI 测试程序进行 WMI 测试,Windows Management Instrumentation(WMI)测试程序,也叫做 WBEMTest,是一个在 Windows Management Instrumentation (WMI)服务程序和 WMI 应用程序开发期间,用于查 看和更改公共信息模型(Common Information Model, CIM)类、实例和方法的常规工具。 在编写本软件程序的过程中,往往需要首先测试获 得获取当前系统的某些参数,如果直接在程序中编码调 试将增加设计难度,因此可以首先在 WMI 测试程序中 进行。例如获取当前网络适配器信息就可以通过以下步 骤获得:从“开始”→“运行”,或者是命令行提示符 下输入 wbemtest。 单击“连接”按钮,在名称空间后输入\root\cimv2, 并单击“连接”按钮,如图 3 所示。.
(5) 第四篇 网络与通信. 201. IP 地址分配设置工具, 经过编译后运行界面如图 5 所示。. 图3. 连接名称空间. 单击“查询”按钮,并输入需要测试的查询语句, 例 如 “ SELECT * FROM Win32_NetworkAdapter Configuration”,单击查询后即可获得查询结果,如图 4 所示,单击每个查询结果可以查看每个对象的详细属性等 信息。. 图4. 查询结果. 使用 WBEMTest 主要来解决 WMI 和依赖于 WMI 的程序中的问题,可以执行以下任务: * * * *. 创建、列举及删除 CIM 类和实例。 执行方法。 运行查询。 显示关于类和实例的受管理对象格式(Managed. Object Format,MOF)代码。. 3. 应用 按照以上的思路和方法可以编写出一个自动静态. 图5. 静态 IP 自动设置程序. 启动程序后依次选择网卡和主机所在位置后单击 “自动设置”即可将相应的网络参数配置到指定的网络 适配器中。其中不同位置的网络信息参数预先已经存放 在数据文件 config.ini 文件中,每一小节配置对应图 5 中主机所在位置下拉选框中数据,配置格式如下: [我的办公室配置] IP_Address=192.168.1.0 MASK=255.255.255.0 GW_Address=192.168.1.1 DNS1=192.168.1.1 DNS2=192.168.1.2 [教学楼] IP_Address=192.168.2.0 MASK=255.255.255.0 GW_Address=192.168.2.1 DNS1=192.168.1.1 DNS2=192.168.1.2 ……. 经过实际应用和测试本程序获得了用户的一致好 评,特别是在禁止了 UAC(User Account Control)的 Vista 环境中也能正常工作,大大简化了 IP 地址的配置 过程。本方案虽然从本质上不能解决静态 IP 网络中 IP 地址的分配问题,但是通过适当的管理措施加上本程序 的应用,也最大限度的降低了网管员在相关工作的劳动 强度,并且通过客户端的编写进一步深刻理解了 WMI 等网管技术。. 4.2 IE 快捷菜单扩展编程实现 陈建丽 宋克强 现在工作中大家经常到互联网上去查询需要的各 种资料。为了方便以后的使用,在找到需要的资料后一 般都要将相应的网页保存在自己的计算机里面。但是在. 使用 IE 本身保存网页的过程中也觉得有一个小小的不 便:IE 只能将整个网页完全保存,而不能只保存网页中 的部分内容。而自己需要的往往只是网页中的部分内容.
(6) 《电脑编程技巧与维护》2009 年合订本(精华版). 202. (特别是文字信息),如果每次都保存整个网页的话, 不仅浪费磁盘空间也浪费了自己的时间。因此自然而然 地就想,要是能够只保存选中的网页内容就好了。经过 一段时间的摸索,终于用扩展 IE 快捷菜单的方法实现 了预期的部分功能。. 1. 此处将其默认值建立为 C:\SaveSelectedHTML.htm 则表示当用户选定 IE 快捷菜单中的命令“保存选 定 的 网页 内容 ” 时系 统将 自动 执 行文 件 C:\SaveSelectedHTML.htm。. 1.3 指定扩展菜单. 扩展 IE 的功能. 要能够保存网页中的选定部分内容,必须对 IE 的 现有功能进行扩展。常见的扩展 IE 现有功能的方法主 要有:扩展 IE 的工具菜单、扩展 IE 的工具栏,以及扩 展 IE 的快捷菜单等。在此选择使用扩展 IE 快捷菜单的 方法。. 如果愿意,还可以在第一步建立的注册表项中建立 一个名为“Contexts”、类型为“DWORD”的值,用于 指定扩展的菜单命令在何种情况下才会出现在 IE 的快 捷菜单中。该值可以是如表 1 所示几个值的逻辑“或” (OR)运算的组合。 表1. 1.1 修改注册表. 值. 在注册表的分支 HKEY_CURRENT_USER\Software\ Microsoft\Internet Explorer\MenuExt 中建立一个项,用于 在 IE 的快捷菜单中显示可选择的命令。 例如,此处建立的项为: HKEY_CURRENT_USER\Software\Microsoft\Intern et Explorer\MenuExt\保存选定的网页内容 表示在 IE 的快捷菜单中会增加一个命令“保存选. 快捷菜单的类型. 0x1. 缺省快捷菜单. 0x2. 图像的快捷菜单. 0x4. 控件的快捷菜单. 0x8. 表单域的快捷菜单. 0x10. 选中文字的快捷菜单. 0x20. 锚点的快捷菜单. 定的网页内容” 。. 1.2 设置默认值 用于指定当用户选择 IE 快捷菜单中相应命令时要执 行的脚本文件的 URL。该脚本文件可以通过操作代表快 捷菜单所在窗口的对象 window.external.menuArguments, 进而处理 IE 窗口的各种对象(如 document、location、 history 等)。. 图1. 2. 例如,如果想在图像和选定文本的快捷菜单中显示 扩展的命令,则可以将 Contexts 的值设置为 0x12。由 于此处希望可以保存 IE 中选中的任何内容,因此不设 置 Contexts,这样扩展的命令随时都会出现在 IE 的快 捷菜单中。 现在,注册表中对应位置如图 1 所示。. 添加注册表项. 设计. 认为病毒程序而被删除;即使不被杀毒软件删除,也有 可能因为 IE 的安全设置的原因而被禁止运行。另外, 也不能自由地设置文件的名字和保存位置等信息。. 通过上面的步骤,在 IE 的快捷菜单中就会出现命 令“保存选定的网页内容”,当用户选择该命令的时 候 就 可 以 执 行 包 含 可 执 行 脚 本 的 文 件 (C:\SaveSelectedHTML.htm)。下面就进行该脚本程序. 为解决这些问题,可以使用 VB 等程序先建立并注 册一个 COM 服务器,该服务器用于实现系统需要的接 口,本例主要是实现文件的读写等操作;IE 在运行时通 过在脚本文件中调用相应的 COM 对象的方法从而实现. 的设计了虽然需要的功能实际上都可以在该文件中用 脚本语言(如 JavaScript、VBScript)直接实现,但是这 样会有一些限制。因为程序会涉及到读写本地文件,如 果直接用脚本语言读写本地文件,有可能被杀毒软件误. 需要的功能。 下面以 Visual Basic 和 JavaScript 为例说明程序的具 体实现过程。 (1)启动 VB 6.0,选择“File-New Project-ActiveX.
(7) 第四篇 网络与通信 DLL”,创建一个 ActiveX DLL 文件,设置工程名为 “SaveHTML”。. 203. MainForm.Show vbModal End Sub. (3)选择“Project-Add Module”,添加一个模块 Module1,在其中加入以下公共变量的声明语句:. (2)将默认的类 class1 的 Name 设置为 Saver,然 后为该类加入如下代码,实现接口 SaveIt。. Public SelectedHTML As String 定的网页内容的 HTML 源代码. Public Sub SaveIt(Recieved As String) 'Recieved 用于接收 传递过来的参数,即选定的网页内容的 HTML 代码 SelectedHTML = Recieved '将传递过来的参数赋值给公共 变量. '公共变量,用于保存选. (4)选择“Project-Add Form” ,添加一个窗体和需 要的控件,设置其属性如表 2 所示。 表2. 对象. 属性. 设置值. 作用 用户操作界面,用于设置文件的保 存位置和文件名. Name. MainForm. Caption. 设置文件保存位置和文件名. Border Style. 3-Fixed Dialog. Label. Caption. 保存位置. Label. Caption. 文件名. Name. TextLocation. Locked. True. TextBox. Name. TextName. 用于输入文件名. CommandButton. Name. CommandBrowse. 单击该按钮可选择文件保存位置. Caption. 选择文件夹…. Name. CommandStart. Caption. 开始保存. Form. TextBox. CommandButton. 设置好后该窗体的界面如图 2 所示。. 图2. 程序运行界面. 下面为窗体加入如下一些声明和代码: ‘用于显示选择文件夹浏览窗口的常数、类型和 API Private Const BIF_RETURNONLYFSDIRS = 1 Private Const BIF_DONTGOBELOWDOMAIN = 2 Private Const MAX_PATH = 260 Private Declare Function SHBrowseForFolder Lib "shell32" (lpbi As BrowseInfo) As Long Private Declare Function SHGetPathFromIDList Lib "shell32" (ByVal pidList As Long, ByVal lpBuffer As String) As Long Private Declare Function lstrcat Lib "kernel32" Alias "lstrcatA" (ByVal lpString1 As String, ByVal lpString2 As String) As Long Private Type BrowseInfo hWndOwner As Long pIDLRoot As Long pszDisplayName As Long lpszTitle As Long. 起提示作用,使用默认的 Name 显示用户选择的文件保存位置. 单击该按钮则保存选定内容. ulFlags As Long lpfnCallback As Long lParam As Long iImage As Long End Type Private LastFileName As String ‘以下为具体的实现代码 Private Sub CommandBrowse_Click() '选择保存文件的路径 TS= SelectedDir() If TS<>”” then TextLocation.Text =TS endif End Sub Private Function SelectedDir() As String '自定义函数,显示 文件夹选择对话框并返回用户的选择 Dim lpIDList As Long Dim sBuffer As String Dim szTitle As String Dim tBrowseInfo As BrowseInfo szTitle = "选择文件的保存位置" With tBrowseInfo .hWndOwner = Me.hWnd .lpszTitle = lstrcat(szTitle, "") .ulFlags = BIF_RETURNONLYFSDIRS + BIF_DONTGOBELOWDOMAIN End With.
(8) 《电脑编程技巧与维护》2009 年合订本(精华版). 204. lpIDList = SHBrowseForFolder(tBrowseInfo) If (lpIDList) Then sBuffer = Space(MAX_PATH) SHGetPathFromIDList lpIDList, sBuffer sBuffer = Left(sBuffer, InStr(sBuffer, vbNullChar) - 1) SelectedDir = sBuffer End If End Function Private Sub CommandStart_Click() '开始保存选定内容 If TextName.Text = "" Then TI = MsgBox(" 错 误 ! 必 须 指 定 保 存 文 件 的 名 字 。 ", vbOKOnly, "文件名为空") Else TStart = "<HTML>" + vbCrLf + "<head>" + vbCrLf + "<title></title>" + vbCrLf + "</head>" + vbCrLf + "<body>" 'HTML 网页文件的前半部分 TSEnd = "</body>" + vbCrLf + "</HTML>" 'HTML 网页文 件的后半部分 TSResult = TStart + SelectedHTML + TSEnd '将选定内容 的 HTML 代码加入中间,构成最终的网页文件的 HTML 代码 '下面将 HTML 代码写入最终的 HTML 文件中 Open TextLocation.Text + "\" + TextName.Text + ".htm" For Output As #1 Print #1, TSResult Close #1 TI = MsgBox("选定网页内容保存成功。", vbOKOnly, "提示") Unload Me End If End Sub Private Sub Form_Load() TextLocation.Text = App.Path '启动时设置默认的保存位 置为 DLL 所在文件夹 End Sub. (5)选择“File-Save Project” ,以系统默认的名字 保 存 整 个 工程 ( 包括 窗 体 、模 块 、类 ); 然后 选 择 “File-Make SaveHTML.DLL”,生成最终的 ActiveX DLL 文件。 (6)注册刚刚生成的 ActiveX DLL。在系统文件 夹 Windows\System32 中找到文件 regsvr32.exe,将. SaveHTML.DLL 拖到其上方,即可出现注册成功的提示。 (7)用记事本等编辑软件建立内容如下的 HTML 文件 SaveSelectedHTML.HTM,并将其保存到 C:\。 <SCRIPT LANGUAGE="JavaScript"> var HTMLObj; HTMLObj =new ActiveXObject("SaveHTML.Saver");// 建 立 COM 对象 HTMLObj.SaveIt(window.external.menuArguments.docume nt.selection.createRange().htmlText);//调用对象的接口,保存选 定内容到本地文件 </SCRIPT>. 现在打开一个网页,选定其中的一部分内容,然 后右击,就会出现如图 2 所示的对话框;选择好文件 的保存位置,设定好文件的名字,然后单击“开始保 存”,选定部分的内容就会保存在你的计算机里了。 以上程序用 VB 6.0 和 JavaScript 配合实现,在 Windows 2000/XP 环境下均验证通过。. 3. 结语. 由于程序只是保存了选定部分的 HTML 代码,因此 网页中的图像、声音等对象的 URL 都是 Internet 上的地 址。这样在 IE 脱机的情况下虽然文字可以正常显示, 但是图像等对象却只能显示为占位符;只有在 IE 连接 互联网的情况下才能正常显示图像等对象。为解决此问 题,可以在脚本中通过 window.external.menuArguments. document 对象的 images 数组元素的 src 属性来获得图像 的 URL,通过 window.external.menuArguments.document 对象的 embeds 数组元素的 src 属性来获得其他多媒体 对象的 URL,然后将这些 URL 作为参数传递给 COM 对象,由 COM 对象完成这些文件的下载,并修改 HTML 代码中这些文件的 Internet 地址为本地地址。限 于篇幅,在此只是提出实现思路,有兴趣的读者可以 自己做一下。. 4.3 网页摘文快车程序设计 国 林. 1. 概述. 浏览网页时,当看到一篇有用或有趣的文字,想把 它“当”下来时,有的朋友选择将网页直接“另存为”保 存,而有些朋友则选择:选中文本→复制→新建记事本 →粘贴→保存→重命名,殊不知这样做无形中浪费了上. 网时间,久而久之,浪费的就不只是一点点琐碎的时间了。 设计本程序的目的就是为了方便用户,提高用户上 网摘文得效率,节约宝贵的时间。VC 是 Microsoft 的一 个非常好用的 C++编程工具,现在已经出到 Microsoft Visual Studio 2008,大多数的 C++程序员都喜欢用 VC, 不但开发环境友好,而且有功能强大的 MFC(微软基 础类库,Microsoft Foundation Class)支持。然而,MFC.
(9) 第四篇 网络与通信 在.NET 平台下没有太多的改进。因此,大部分的 VC 程序员都喜欢用 VC++ 6.0 开发 MFC 应用程序。. 2. 程序设计 首先,创建一个基于 MFC 的对话框界面的应用程. 序,命名为 SuperGet。. 2.1 皮肤设计 俗话说:“人靠衣装,马靠鞍” 。软件同样应该具备. 205. //对话框的代码 } else if (nResponse == IDCANCEL) { // TODO: 在此放置处理何时用“取消”来关闭 //对话框的代码 } USkinExit(); //USkin 退出. 由此,编译→构建→生成,一个漂亮的对话框界面 就生成了。 绘制界面如图 1 所示。. 一个友好、美观的用户界面。然而,VC 的界面设计和 时间处理方法非常复杂,无法在有限的时间内设计出美 观、用户熟悉的操作界面。 于是在这里使用 USkin 来设计皮肤。 USkin 的特性: 1)支持 20 多种 Windows 标准控件。 2)支持文件、颜色、打印、字体等标准对话框。 3)支持第三方/自定义控件。 4)支持所见即所得的皮肤文件编辑。 5)支持 MDI/SDI/Dialog 风格的应用程序。 6)支持 WindowsBlind 皮肤文件导入,多达万个现 成皮肤供您使用。 7)支持颜色主题,一套皮肤可以演变成多种皮肤。 8)支持多种编程语言。 9)支持多线程。 10)支持动态换肤。 11)支持所有弹出菜单,包括 Edit 控件右键弹出菜单。 12)只需三行代码即可实现换肤。 13)支持 ListView/TreeView 等控件滚动条换肤。 14)皮肤资源文件所占空间小。 (1)包含 USkin.lib 和 USkin.h 头文件。首先,将 USkin.lib 和 USkin.h 文件拷贝到工程目录下,然后工程 →设置→Link→L 对象/库模块中,添加 USkin.lib,接着 在 SuperGetDlg.h 文件中#include "USkin.h"。 (2)加载皮肤文件。首先,将皮肤文件(这里以 ToMorning.u3 为例)拷贝 到工程目录下 (编译后 将 ToMorning.u3 和 USkin.dll 放到 Debug 文件夹中),然后 在 SuperGet.cpp 添加如下代码: BOOL CSuperGetApp::InitInstance() { AfxEnableControlContainer(); SetRegistryKey(_T("应用程序向导生成的本地应用程序")); USkinInit(NULL,NULL,_T("ToMorning.u3")); //加载 u3 皮肤文件 CSuperGetDlg dlg; m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: 在此放置处理何时用“确定”来关闭. 图1. 绘制界面. 2.3 程序代码 2.3.1 主要的函数 void PerFormCtrlC(); 模拟 Ctrl+c 按键 BOOL GetCopy(); 获得复制到剪贴板中的文本内容 void File_Save(); 将得到的文本内容保存到指定位置 void CutBlank(); 消除文本中的空格 LRESULT OnHotKey(WPARAM wp,LPARAM lp); 注册热键 void Release Focus(); 释放本程序的焦点. 2.3.2 函数说明 1)模拟 Ctrl+c 按键 void CSuperGetDlg::PerFormCtrlC() { EmptyClipboard(); //清空剪贴板 Sleep(1000); //延时 1s //模仿键盘击键 Ctrl+C keybd_event(VK_CONTROL,MapVirtualKey(VK_CONTR OL,0),0,0); //按住 Ctrl,不放开 keybd_event(0x43,MapVirtualKey(0x43,0),0,0); //按住 C 键,不放开 keybd_event(0x43,MapVirtualKey(0x43,0), KEYEVENTF_KEYUP,0); //放开 C 键 keybd_event(VK_CONTROL,MapVirtualKey (VK_CONTROL,0), KEYEVENTF_ KEYUP,0); //放开 Ctrl }. 2)从剪贴板中获得复制文本 BOOL CSuperGetDlg::GetCopy() { BOOL m_bcopy=TRUE; //设置 copy 为成功.
(10) 《电脑编程技巧与维护》2009 年合订本(精华版). 206. //打开系统剪贴版 if(!OpenClipboard()) { AfxMessageBox("无法打开剪贴版"); m_bcopy=FALSE; //copy 失败 } //判断剪贴版上的数据是否是制定的数据格式 if(IsClipboardFormatAvailable(CF_TEXT)||IsClipboardFor matAvailable(CF_OEMTEXT)) { //从剪贴版上获取数据 HANDLE hClipboardData=GetClipboardData(CF_TEXT); //通过给内存句柄加锁,获得指向指定格式数据的指针 char * pchData=(char *)GlobalLock(hClipboardData); //本地变量获得数据 strClipBoard=pchData; //给内存句柄解锁 GlobalUnlock(hClipboardData); if(!m_Blank) strData=LPCTSTR(strClipBoard); //关闭剪贴版 CloseClipboard(); } else { AfxMessageBox("剪贴版中无文本数据"); m_bcopy=FALSE; //copy 失败 } return m_bcopy; }. 3)添加消除空行的函数 void CSuperGetDlg::CutBlank() { //处理文本中的空行、空格 CStringArray arr; //定义 CStringArray 数组 CString strtemp; TCHAR * pszBuf=NULL; //Tchar 类型指针 pszBuf=(TCHAR *)LPCTSTR(strClipBoard); //pszBuf 指向文本 char * p; for (p=strtok(pszBuf,"\r\n");p!=NULL; p=strtok(NULL,"\r\n")) /*分解 pszBuf 字符串为一组标记 串。pszBuf 为要分解的字符串,\r\n 为分隔符字符串。返回指 向下一个标记串,当没有标记串时则返回空字符 NULL。*/ { arr.Add(p); //将得到的字符串添加到 arr 数组中 } //删除空行 for (int i=0;i<arr.GetSize();i++) { strtemp=arr[i]; //将每一个字符串赋给 strtemp if(strtemp.IsEmpty()) //如果 strtemp 为空 { arr.RemoveAt(i); //移除此项 i--; //i 自减 continue; } //删除空格. int j=1; while(j>0) { strtemp.TrimLeft(); //没有参数,从左删除字符空格 strtemp.TrimRight(); //没有参数,从右删除字符空格 j = strtemp.Replace(" ",""); //用无替换字符串中间的空格 } strData+=strtemp+"\r\n"; //将无空行、空格的文本传给 strData } }. 4)将文本保存在指定位置 void CSuperGetDlg::File_Save() { CStdioFile File; //CStdioFile 类型变量 File NameFile(m_Namenumber); //给文件命名 CString FileName=m_SavePlace+"//"+strName+".txt"; //FileName 得到文件全路径 if (!File.Open(FileName,CFile::modeWrite| CFile::typeText)) //创建文本文件 { if (!SetCurrentDirectory(m_SavePlace)) //检测是否有此目录 { CreateDirectory(m_SavePlace, NULL); //如果没有则创建 } if(!File.Open(FileName,CFile::modeCreate| CFile::modeWrite|CFile::typeText)) //如果不能打开打开 { MessageBox(m_SavePlace+strName+".txt"+"不能被 创建","信息提示",MB_OK); //显示错误提示 } else { File.SeekToEnd(); //先定位到文件尾部 File.Write(strData,strData.GetLength()+1); //将内容写入文件中 File.Close(); //关闭文件 } } }. 5)注册快捷键 LRESULT CSuperGetDlg::OnHotKey (WPARAM wp,LPARAM lp) { if(HIWORD(lp)==90&&LOWORD(lp)== MOD_ALT|MOD_CONTROL) //响应 Ctrl+Alt+Z { ReleaseFocus(); //释放本程序焦点 PerFormCtrlC(); //模拟 Ctrl+c 按键 UpdateData(TRUE); //更新数据 strData.Empty(); //清空 strData BOOL bCopy=GetCopy(); //拷贝剪贴板中的文本内容.
(11) 第四篇 网络与通信 if(m_Blank) CutBlank(); //清除空行 if(bCopy) { if(!m_SavePlace.IsEmpty()) File_Save(); else AfxMessageBox("请选择保存路径"); }. 207. gFocus = wnd; //使本进程和激活窗口的进程联系起来,接收本进 //程的按键消息 AttachThreadInput( GetWindowThreadProcessId(m_hWnd,NULL), GetWindowThreadProcessId(gFocus,NULL), TRUE); }. } else if(HIWORD(lp)==88&&LOWORD(lp)== MOD_ALT) //响应 Alt+X { ReNameFile(); //重命名文件名字 }. } } return CDialog::PreTranslateMessage(pMsg); } //释放本程序的窗口激活状态 void CSuperGetDlg::ReleaseFocus() { if(IsWindow(gFocus)) { HWND wnd = ::GetForegroundWindow(); if(IsWindow(wnd)) { if(wnd == gFocus) { return; } } //设置保存的焦点窗口处于激活状态 ::SetForegroundWindow(gFocus); ::SetFocus(gFocus);. return 0; }. 6)激活当前程序 BOOL CSuperGetDlg::PreTranslateMessage(MSG* pMsg) { HWND wnd = ::GetForegroundWindow(); if(IsWindow(wnd)) { //如果当前激活窗口不是本程序的窗口 if(wnd != this->m_hWnd) { //激活窗口发生了改变 if(gFocus != wnd) { if(IsWindow(gFocus)) { //释放本进程和 gFocus 线程的联系 AttachThreadInput( GetWindowThreadProcessId (m_hWnd,NULL), GetWindowThreadProcessId(gFocus,NULL), FALSE); }. 图2. } }. 由于篇幅所限,本程序的具体功能就不一一介绍 了,有兴趣的朋友可以阅览本程序的源代码。本摘文快 车(SuperGet)在 VC++ 6.0,Windows XP 环境下调试 通过,编译并运行本程序,摘文快车的界面效果如图 2 所示。. 程序界面效果 复制→粘贴→保存→重命名过程。读者在本程序的基. 3. 结语 本文详细的介绍了在 VC++环境下,网页摘文中. 础上可添加更多的功能,实现功能更加完善的摘文 快车。.
(12) 《电脑编程技巧与维护》2009 年合订本(精华版). 208. 4.4 用 Java 实现 Yahoo 天气预报客户端 吴亚峰 刘 佳 李志昕 <!-- 此处省略了一些不重要代码 --> <item> <!-- 此处省略了一些不重要代码 --> <pubDate>Sun, 06 Jul 2008 3:00 pm CST</pubDate> <yweather:condition text="Fair" code="34" temp ="32" date="Sun, 06 Jul 2008 3:00 pm CST" /> <!-- 此处省略了一些不重要代码 --> <yweather:forecast day="Sun" date="6 Jul 2008" low="22" high="31" text="Sunny" code="32" /> <yweather:forecast day="Mon" date="7 Jul 2008" low="22" high="31" text="Partly Cloudy" code = "30" /> <!-- 此处省略了一些不重要代码 --> </item> </channel> </rss>. 1 Yahoo 天气预报 Yahoo 作为大型的中文门户网站之一,提供了种类 繁多的各种信息服务,其中也包括了非常实用的天气预 报信息服务。非常值得注意的是,Yahoo 提供的天气预 报信息不但可以通过登录 Yahoo 的网站浏览,也可以获 取特定格式的 XML 文档自行解析。有了第二种天气预 报服务,就可以自己开发天气预报的客户端软件,或把 天气预报功能嵌入到自己的桌面软件或 Web 应用中。 获取 Yahoo 天气预报的 XML 文档非常简单,只要 使用如下格式的 URL 即可: http://xml.weather.yahoo.com/forecastrss?u=c&p=CH XX0008 其中查询参数 u 表示温度单位,若摄氏度则为“c”, 华氏度则为“f”。查询参数 p 表示地点,后跟城市代码。 城市代码是一个 8 位长度的字符串,前四位固定为 “CHXX”,后四位为数字,表示不同的城市。例如, “0008”表示北京,常见的城市代码如表 1 所列。 表 1 城市代码 代码. 城市. 代码. 城市. CHXX0008. 北京. CHXX0044. 杭州. CHXX0116. 上海. CHXX0502. 海口. CHXX0037. 广州. CHXX0131. 唐山. CHXX0138. 武汉. CHXX0321. 扬州. 输入了上述的 URL 后,就可以获得 Yahoo 提供的 当天北京地区天气预报信息的 XML 文档,其基本内容 如下: <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <rss version="2.0" xmlns:yweather ="http://xml.weather.yahoo.com/ns/rss/1.0" xmlns:geo ="http://www.w3.org/2003/01/geo/wgs84_pos#"> <channel> <!-- 此处省略了一些不重要代码--> <yweather:wind chill="32" direction="130" speed="11.27" /> <yweather:atmosphere humidity="49" visibility="999.00" pressure="999" rising="0" /> <yweather:astronomy sunrise="4:53 am" sunset="7:46 pm"/>. 上述文档中包含了当时的天气情况信息、当天以及 明天的天气预报信息,详细说明如下所列: (1)yweather:wind 标记中的 chill 属性表示当前的 风冷热系数,direction 属性表示当前的风向,speed 表示 当前的风速。 (2)yweather:atmosphere 标记中的 humidity 属性 表示当前的湿度,visibility 属性表示当前的能见度, pressure 属性表示当前的气压。 (3)yweather:astronomy 标记中的 sunrise 属性表示 当天日出时间,sunset 属性表示当天日落时间。 (4)pubDate 标记中的内容是天气预报的发布时间。 (5)yweather:condition 标记中的 code 属性表示当 前的天气情况代码,temp 属性表示当前温度。 (6)两个 yweather:forecast 标记中包含的分别是今 天与明天的天气预报信息,其中 date 属性表示日期,low 属性表示最低温度,high 属性表示最高温度,code 属性 表示天气情况代码。. 2. 案例功能 将结合 Yahoo 天气预报客户端的开发来介绍 JAXP. (Java API for XML Processing)的简单使用,下面首先 对本软件的功能、界面进行简单的介绍。. 2.1 程序界面 程序中主要包含两个窗体,第一个用于选择天气预 报的城市(如图 1 所示),第二个用来显示获取的天气 预报信息(如图 2 所示) 。.
(13) 第四篇 网络与通信. 图1. 城市选择窗口. 209. <cityItem> <code>CHXX0502</code><name>海口</name> </cityItem> <cityItem> <code>CHXX0131</code><name>唐山</name> </cityItem> <cityItem> <code>CHXX0321</code><name>扬州</name> </cityItem> </CityList>. 使用 XML 文档的好处是,未来需要添加新的城市 时不需要修改源代码,只需要在 XML 中添加新的 cityItem 元素即可。 有了记录城市信息的 XML 文档后就可以对城市 选择窗体类 YahooWeatherFramePre 进行开发了,其代 码框架如下:. 图2. 天气预报信息显示窗口. 2.2 软件实现的功能 (1)程序启动后首先显示的是如图 1 所示的城市 选择窗口,用户可以在其中选择需要的城市,并单击“确 定”按钮。 (2)按下确定按钮后,程序通过网络连接 Yahoo 的服务器,获取所需的天气预报 XML 文档。 (3)获取 XML 文档后,软件进行解析,并将当前 天气信息,今明两天的天气预报信息显示在界面上。. 3. 城市选择窗体的开发. 城市选择窗体的主要功能就是让用户选择需要天 气预报的城市,其核心就是供城市选择的下拉列表框。 为了方便维护以及程序的可扩展性考虑,下拉列表中的 城市信息将从一个自定义的 XML 文档 CityList.xml 中加 载,其基本内容如下: <?xml version="1.0" encoding="GBK" standalone="yes" ?> <CityList> <cityItem> <code>CHXX0008</code><name>北京</name> </cityItem> <cityItem> <code>CHXX0116</code><name>上海</name> </cityItem> <cityItem> <code>CHXX0037</code><name>广州</name> </cityItem> <cityItem> <code>CHXX0138</code><name>武汉</name> </cityItem> <cityItem> <code>CHXX0044</code><name>杭州</name> </cityItem>. package wyf; import java.util.*; import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.xml.parsers.*; import org.w3c.dom.*; import java.io.*; import java.net.*; public class YahooWeatherFramePre extends JFrame{ Image image;//窗体图标 JLabel jl=new JLabel("请选择城市"); //城市选择下拉列表 JComboBox jcb=new JComboBox(); JButton jb=new JButton("确定"); //用来封装每个城市名称及代码的内部类 public static class CityItem{ String cname;//城市名称 String ccode;//城市代码 // CityItem 内部类构造器 public CityItem(String cname,String ccode) {this.cname=cname; this.ccode=ccode;} //重写 toString 方法 @Override public String toString(){return cname;} } // YahooWeatherFramePre 类构造器 public YahooWeatherFramePre() { //对标题和 logo 图片进行初始化 this.setTitle("Yahoo 天气预报客户端"); image=new ImageIcon("img/ico.png").getImage(); this.setIconImage(image); //对界面中的控件进行摆放 this.setLayout(new FlowLayout(FlowLayout.LEFT,10,6)); jl.setPreferredSize(new Dimension(200,20)); this.add(jl); jcb.setPreferredSize(new Dimension(150,20)); this.add(jcb); jb.setPreferredSize(new Dimension(60,20)); this.add(jb); //对城市列表初始化 this.initCityList(); //为“确定”按钮添加监听器 jb.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e).
(14) 《电脑编程技巧与维护》2009 年合订本(精华版). 210 {. //获取当前选中的城市 CityItem currCI = (CityItem)jcb.getSelectedItem(); String selectedCityCode = currCI.ccode; //未来在此处添加创建天气预报信息显示 //窗口的代码…… YahooWeatherFramePre.this.dispose(); } } ); //设置窗体首次出现的大小和位置 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int centerX=screenSize.width/2;//屏幕中央 x 坐标 int centerY=screenSize.height/2; //屏幕中央 y 坐标 int w=250;//本窗体宽度 int h=100;//本窗体高度 //设置窗体出现在屏幕中央 this.setBounds(centerX-w/2,centerY-h/2-100,w,h); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setResizable(false);//设置窗体不可修改大小 } //从 CityList.xml 文件中加载城市列表 public void initCityList(){} //主方法 public static void main(String args[]) {new YahooWeatherFramePre();} }. 上述代码中“ImageIcon("img/ico.png")”加载了窗 体的 logo 图片,因此要将 ico.png 图片文件存放到 img 文件夹下,img 文件夹放置在 class 包所在目录下,否则 程序不能正确执行。 在完成了代码框架的开发后就可以开发加载城市 列表 XML 文档 CityList.xml 的 initCityList 方法了,其 代码如下: public void initCityList() { try { // 为解析 XML 文件创建 DOM 对象 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); //解析 XML 文件 Document doc = builder.parse(new File("CityList.xml")); // 规格化 doc.normalize(); //解析城市列表 NodeList cityItems = doc.getElementsByTagName("cityItem"); int cityCount=cityItems.getLength(); CityItem[] cia=new CityItem[cityCount]; for(int i=0;i<cityCount;i++){ Element cityElement = (Element)cityItems.item(i);. String ccode= cityElement.getElementsByTagName("code") .item(0).getFirstChild().getNodeValue(); String cname= cityElement.getElementsByTagName("name") .item(0).getFirstChild().getNodeValue(); cia[i]=new CityItem(cname,ccode);} jcb.setModel( new DefaultComboBoxModel(cia)); }catch(Exception e){e.printStackTrace();} }. 上述 initCityList 方法将 CityList.xml 文件中的每个 cityItem 加载为一个 CityItem 类对象, 并添加到 CityItem 数组中,最终将数组添加到 DefaultComboBoxModel 对 象以显示到下拉列表中。完成 YahooWeatherFramePre 类的开发后,将代码编译运行一下,可以见到如图 1 所 示的城市列表选择窗体。 要注意的是,由于上述代码访问了 CityList.xml 文 件,因此要将此文件放到 class 包所在目录下,否则程 序不能正确执行。. 4. 显示窗体 完成了城市列表窗体的开发后,就可以着手开发用. 于显示天气信息的窗体类 YahooWeatherFrame,其代码 框架如下: package wyf; import java.util.*; import javax.swing.*; import java.awt.*; public class YahooWeatherFrame extends JFrame{ Font font= new Font("楷体_GB2312",Font.PLAIN,18); //左侧显示详细天气情况的面板 JPanel jpz=new JPanel(); //右上侧显示今天天气预报的面板 JPanel jps=new JPanel(); //右下侧显示明天天气预报的面板 JPanel jpx=new JPanel(); JsplitPane jspy = new JSplitPane( JSplitPane.VERTICAL_SPLIT,jps,jpx); JSplitPane jspz = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT,jpz,jspy); //当前天气情况的各个显示标签 JLabel jlTodayImg=new JLabel();//天气情况图片 JLabel jlTodayTitle=new JLabel();//天气总情况描述 JLabel jlTodayDegree=new JLabel();//当前气温 JLabel jlTodayChill=new JLabel();//当前风冷热系数 JLabel jlTodaySpeed=new JLabel();//当前风速 JLabel jlTodayDirection=new JLabel();//当前风向 JLabel jlTodayHumidity=new JLabel();//当前湿度 JLabel jlTodayPressure=new JLabel();//当前气压 JLabel jlTodayVisibility=new JLabel();//当前能见度 JLabel jlTodaySunrise=new JLabel();//日出时间 JLabel jlTodaySunset=new JLabel();//日落时间.
(15) 第四篇 网络与通信 JLabel jlTodayPublishTime=new JLabel();//发布时间 //今天天气预报情况的各个显示标签 JLabel jlTomorrowTime=new JLabel();//今天时间 //今天情况图片 JLabel jlTomorrowImg=new JLabel(); //今天最高温度 JLabel jlTomorrowHigh=new JLabel(); //今天最低温度 JLabel jlTomorrowLow=new JLabel(); //明天天气预报情况的各个显示标签 JLabel jlDATTime=new JLabel();//明天时间 JLabel jlDATImg=new JLabel();//明天情况图片 JLabel jlDATHigh=new JLabel();//明天最高温度 JLabel jlDATLow=new JLabel();//明天最低温度 public YahooWeatherFrame(String cityCode, Image image){ //对界面进行初始化 this.initWeatherFrame(image); //未来添加解析天气并填充到界面代码…… //设置窗体首次出现的大小和位置 Dimension screenSize= Toolkit.getDefaultToolkit().getScreenSize(); int centerX=screenSize.width/2;//屏幕中央 x 坐标 int centerY=screenSize.height/2;//屏幕中央 y 坐标 int w=620;//本窗体宽度 int h=358;//本窗体高度 //设置窗体出现在屏幕中央 this.setBounds(centerX-w/2,centerY-h/2-100,w,h); this.setVisible(true); //设置窗体的默认关闭动作 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setResizable(false); } //对界面进行初始化的方法 public void initWeatherFrame(Image image){} }. 在完成了 YahooWeatherFrame 类框架的开发后,就 可以开发对界面控件进行初始化的 initWeatherFrame 方 法了,其代码如下: public void initWeatherFrame(Image image) { //对标题和 logo 图片进行初始化 this.setTitle("Yahoo 天气预报客户端"); this.setIconImage(image); //设置三个面板的背景色 jpz.setBackground(new Color(231,231,231)); jps.setBackground(new Color(252,237,180)); jpx.setBackground(new Color(176,237,255)); //对总界面进行初始化 this.add(jspz,BorderLayout.CENTER); jspz.setDividerLocation(300); jspy.setDividerLocation(165); jspz.setDividerSize(0); jspy.setDividerSize(0); //对本日天气界面进行初始化 jpz.setLayout(null); jlTodayImg.setBounds(50,5,175,120); jpz.add(jlTodayImg);jlTodayTitle.setFont(font);. 211. jlTodayTitle.setBounds(5,130,260,20); jpz.add(jlTodayTitle);jlTodayDegree.setFont(font); jlTodayDegree.setBounds(5,150,260,20); jpz.add(jlTodayDegree);jlTodayChill.setFont(font); jlTodayChill.setBounds(150,150,150,20); jpz.add(jlTodayChill);jlTodaySpeed.setFont(font); jlTodaySpeed.setBounds(5,170,180,20); jpz.add(jlTodaySpeed);jlTodayDirection.setFont(font); jlTodayDirection.setBounds(190,170,170,20); jpz.add(jlTodayDirection); jlTodayHumidity.setFont(font); jlTodayHumidity.setBounds(5,190,170,20); jpz.add(jlTodayHumidity); jlTodayPressure.setFont(font); jlTodayPressure.setBounds(100,190,170,20); jpz.add(jlTodayPressure); jlTodayVisibility.setFont(font); jlTodayVisibility.setBounds(5,210,170,20); jpz.add(jlTodayVisibility); jlTodaySunrise.setFont(font); jlTodaySunrise.setBounds(5,230,150,20); jpz.add(jlTodaySunrise); jlTodaySunset.setFont(font); jlTodaySunset.setBounds(5,250,150,20); jpz.add(jlTodaySunset); jlTodayPublishTime.setFont(font); jlTodayPublishTime.setBounds(5,270,290,20); jpz.add(jlTodayPublishTime); //对明日天气界面进行初始化 jps.setLayout(null); jlTomorrowTime.setFont(font); jlTomorrowTime.setBounds(5,5,300,20); jps.add(jlTomorrowTime); jlTomorrowImg.setBounds(55,20,175,120); jps.add(jlTomorrowImg); jlTomorrowHigh.setFont(font); jlTomorrowHigh.setBounds(5,140,175,20); jps.add(jlTomorrowHigh); jlTomorrowLow.setFont(font); jlTomorrowLow.setBounds(155,140,175,20); jps.add(jlTomorrowLow); //对后天天气界面进行初始化 jpx.setLayout(null); jlDATTime.setFont(font); jlDATTime.setBounds(5,5,300,20); jpx.add(jlDATTime); jlDATImg.setBounds(55,20,175,120); jpx.add(jlDATImg);jlDATHigh.setFont(font); jlDATHigh.setBounds(5,140,175,20); jpx.add(jlDATHigh);jlDATLow.setFont(font); jlDATLow.setBounds(155,140,175,20); jpx.add(jlDATLow); }. 完成了上述代码的开发后将 YahooWeatherFrame 类 进行编译,并在 YahooWeatherFramePre 类代码框架中 “未来在此处添加创建天气预报信息显示窗口的代 码……”处添加如下代码: new YahooWeatherFrame(selectedCityCode, image);.
(16) 《电脑编程技巧与维护》2009 年合订本(精华版). 212. 添加完上述代码后,再次编译 YahooWeatherFramePre 类并运行,此时再单击“确定”按钮就可以看到天气预 报窗体了,不过此时程序还不能从网络中获取天气预报 信息解析显示。. 5. 信息解析类. 完成了两个窗体类的开发后,就可以进行天气预报 信息解析类 YahooWeather 的开发了,其代码框架如下: package wyf; import javax.xml.parsers.*; import org.w3c.dom.*; import java.io.*;import java.net.*; import javax.swing.*;import java.text.*; import java.util.*; public class YahooWeather { //获取天气信息并解析填充的方法 public static void parseWeather (YahooWeatherFrame ywf, String cityCode) {} //将天气情况代码转换为文字信息的方法 public static String fromCodeToText(int code){} //将风向角度转化为文字信息的方法 public static String fromDegreeToDirectionStr(int degree){} }. 从上述代码中可以看出,YahooWeather 是一个工具 类,其中提供了用于获取解析天气的 3 个静态方法。首 先应该开发将风向角度转化为文字信息的 fromDegreeToDirectionStr 方法,其代码如下: public static String fromDegreeToDirectionStr(int degree) { if(degree>337 && degree<=360){return "北风";} else if(degree>=0 && degree<=22){return "北风";} else if(degree>22 && degree<=67){return "东北风";} else if(degree>67 && degree<=112){return "东风";} else if(degree>112 && degree<=157){return "东南风";} else if(degree>157 && degree<=202){return "南风";} else if(degree>202 && degree<=247){return "西南风";} else if(degree>247 && degree<=292){return "西风";} else if(degree>292 && degree<=337){return "西北风";} else {return "错误的方向值";} }. 开发完将风向角度转化为文字信息的 fromDegree ToDirectionStr 方法后,就可以开发将天气情况代码转换 为文字信息的 fromCodeToText 方法了,其代码如下: public static String fromCodeToText(int code){ switch(code){ case 0: return "龙卷风";case 1: return "热带风暴"; case 2: return "飓风";case 3: return "雷暴雨"; case 4: return "雷雨";case 5: return "雨夹雪"; case 6: return "雨夹冰雹";case 7: return "雪夹冰雹"; case 8: return "冻毛毛雨";case 9: return "毛毛雨"; case 10: return "冻雨";case 11: return "阵雨";. case 12: return "阵雪";case 13: return "雪小雪"; case 14: return "小雪骤雨";case 15: return "风雪"; case 16: return "雪";case 17: return "冰雹"; case 18: return "雨夹雪";case 19: return "尘"; case 20: return "雾";case 21: return "霾"; case 22: return "黑烟";case 23: return "狂风"; case 24: return "风";case 25: return "冷"; case 26: return "多云"; case 27: return "夜间大部多云"; case 28: return "日间大部多云"; case 29: return "夜间部分多云"; case 30: return "日间部分多云"; case 31: return "夜间晴朗";case 32: return "日间晴朗"; case 33: return "夜间清晰";case 34: return "日间清晰"; case 35: return "雨夹雹";case 36: return "热"; case 37: return "局部雷阵雨";case 38: return "零星雷阵雨"; case 39: return "零星雷阵雨";case 40: return "零星暴雨"; case 41: return "大雪";case 42: return "零星暴雪"; case 43: return "大雪";case 44: return "部分多云"; case 45: return "雷阵雨";case 46: return "阵雪"; case 47: return "局部地区雷阵雨"; case 3200: return "不可用"; default: return "没有此代码"; } }. 在两个用于信息转换的辅助方法都开发完成后,就 可 以 开 发 用 于 获 取 并 解 析 显 示 天 气 XML 文 档 的 parseWeather 方法了,其代码如下: public static void parseWeather (YahooWeatherFrame ywf,String cityCode){ try{ //为解析 XML 文件创建 DOM 对象 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder= factory.newDocumentBuilder(); //远程 URL 解析 URL url=new URL("http://xml.weather.yahoo."+ "com/forecastrss?u=c&p="+cityCode); Document doc=builder.parse(url.openStream()); doc.normalize(); //规格化 //解析天气预报发布时间 NodeList links = doc.getElementsByTagName("pubDate"); String dateStr = links.item(0).getFirstChild().getNodeValue(); SimpleDateFormat sdf=new SimpleDateFormat( "EEE, dd MMM yyyy K:mm aa zzz",Locale.US); Date date=sdf.parse(dateStr); Calendar cd=Calendar.getInstance(); cd.setTime(date); dateStr=(cd.get(Calendar.YEAR))+"年" +(cd.get(Calendar.MONTH)+1)+"月" +(cd.get(Calendar.DATE))+"日" +cd.get(Calendar.HOUR_OF_DAY)+"时" +((cd.get(Calendar.MINUTE)>9)?cd.get(Calendar.MINUTE )+"":"0"+cd.get(Calendar.MINUTE))+"分";.
(17) 第四篇 网络与通信 ywf.jlTodayPublishTime.setText( "发布时间:"+dateStr); //解析风相关信息 links =doc.getElementsByTagName("yweather:wind"); NamedNodeMap nnm=links.item(0).getAttributes(); ywf.jlTodayChill.setText("风冷热系数:" +nnm.getNamedItem("chill").getNodeValue()); ywf.jlTodaySpeed.setText("风速:" +nnm.getNamedItem("speed").getNodeValue() +"公里/小时"); String directionStr= nnm.getNamedItem("direction").getNodeValue(); int directionInt=Integer.parseInt(directionStr); ywf.jlTodayDirection.setText("风向:" +fromDegreeToDirectionStr(directionInt)); //解析大气相关信息 links =doc.getElementsByTagName( "yweather:atmosphere"); nnm=links.item(0).getAttributes(); ywf.jlTodayHumidity.setText("湿度:"+ nnm.getNamedItem("humidity").getNodeValue()+"%"); ywf.jlTodayPressure.setText("气压:"+ nnm.getNamedItem("pressure").getNodeValue()+"毫巴"); ywf.jlTodayVisibility.setText("能见度:"+ ((int)Double.parseDouble(nnm.getNamedItem("visibility").g etNodeValue())*100)/10000.0+"公里"); //解析天文学有关信息 links =doc.getElementsByTagName("yweather:astronomy"); nnm=links.item(0).getAttributes(); ywf.jlTodaySunrise.setText("日出时间:" +nnm.getNamedItem("sunrise").getNodeValue().replaceAll( "\\s","")); ywf.jlTodaySunset.setText("日落时间:+ nnm.getNamedItem("sunset").getNodeValue().replaceAll("\\ s","")); //解析当前天气相关信息 links =doc.getElementsByTagName("yweather:condition"); nnm=links.item(0).getAttributes(); int code= Integer.parseInt( nnm.getNamedItem("code").getNodeValue()); ywf.jlTodayTitle.setText("当前天气情况:". 213. nnm.getNamedItem("date").getNodeValue()); cd=Calendar.getInstance(); cd.setTime(date); dateStr=(cd.get(Calendar.YEAR))+"年" +(cd.get(Calendar.MONTH)+1)+"月" +(cd.get(Calendar.DATE))+"日"; ywf.jlTomorrowTime.setText("今天:"+dateStr+" " +fromCodeToText(code)); ywf.jlTomorrowHigh.setText("最高温度:"+ nnm.getNamedItem("high").getNodeValue()+"℃"); ywf.jlTomorrowLow.setText("最低温度:"+ nnm.getNamedItem("low").getNodeValue()+"℃"); //解析明天天气预报信息 nnm=links.item(1).getAttributes(); code=Integer.parseInt( nnm.getNamedItem("code").getNodeValue()); ii=new ImageIcon("img\\"+code+".png"); ywf.jlDATImg.setIcon(ii); sdf=new SimpleDateFormat("dd MMM yyyy",Locale.US); date=sdf.parse(nnm.getNamedItem("date").getNodeValue()); cd=Calendar.getInstance(); cd.setTime(date); dateStr=(cd.get(Calendar.YEAR))+"年" +(cd.get(Calendar.MONTH)+1)+"月" +(cd.get(Calendar.DATE))+"日"; ywf.jlDATTime.setText("明天:"+dateStr +" "+fromCodeToText(code)); ywf.jlDATHigh.setText("最高温度:"+ nnm.getNamedItem("high").getNodeValue()+"℃"); ywf.jlDATLow.setText("最低温度:"+ nnm.getNamedItem("low").getNodeValue()+"℃"); }catch(Exception e){e.printStackTrace();} }. 此方法中使用 JAXP 中的 DOM 方式对从网络上获 取的天气信息 XML 文档进行解析,并将解析的结果填 充到界面中的各个控件进行显示。 要特别注意的是,在显示天气情况时为了生动形 象,采用了图片。对每种不同的天气情况代码各提供一 幅图片,统一存放在 img 文件夹中,图片的名称即为情 况代码,如图 3 所示。. +fromCodeToText(code)); ImageIcon ii=new ImageIcon("img\\"+code+".png"); ywf.jlTodayImg.setIcon(ii); ywf.jlTodayDegree.setText("当前气温:"+ nnm.getNamedItem("temp").getNodeValue()+"℃") //解析天气预报信息 links =doc.getElementsByTagName("yweather:forecast"); //解析今天天气预报信息 nnm=links.item(0).getAttributes(); code=Integer.parseInt(nnm.getNamedItem("code").getNode Value()); ii=new ImageIcon("img\\"+code+".png"); ywf.jlTomorrowImg.setIcon(ii); sdf=new SimpleDateFormat("dd MMM yyyy",Locale.US); date=sdf.parse(. 图3. 天气情况图片.
(18) 《电脑编程技巧与维护》2009 年合订本(精华版). 214. 另外要注意将 img 文件夹与 class 文件包放在同一 个目录中,否则程序无法正确运行。 完成了 YahooWeather 类的开发后,将其进行编译, 并在 YahooWeatherFrame 类代码框架中“未来添加解析 天气并填充到界面代码……”处添加如下代码:. 图4. 制作可执行 jar 包的过程. YahooWeather.parseWeather(this,cityCode);. 添加完上述代码后,再次编译 YahooWeatherFrame 类,并运行 YahooWeatherFramePre 类。此时如图 1、图 2 所示,程序就能够从网络中获取对应城市的天气预报 信息并显示在界面上了。. 请读者注意,笔者机器上 JavaSE 6.0 的安装目录为 “C:\Java\jdk1.6.0” ,读者需要根据自己机器的情况对路 径进行相应修改。 第三,jar 包制作完毕后,可以通过运行如下命令启 Yahoo 天气预报客户端应用程序。. 6. 程序的打包与发布. path=C:\Program Files\Java\jdk1.6.0\bin java -jar YWC.jar. 完成了所有代码的编写后,就可以将程序打包发布 了,在本案例中使用 JavaSE 6.0 自带的 jar 工具将应用 程序打包成可执行 jar 包发布,按如下步骤操作即可。 首先 ,在进行打 包之前首先 要编写一个 名称为 MANIFEST.MF 的清单文件,用来对应用程序进行描述, 其内容如下: Mainfest-Version: 1.0 Main-Class: wyf.YahooWeatherFramePre Created-By: 1.6.0(Sun Microsystems Inc.). 请读者特别注意的是,这个文件的格式非常重要, 每一行要顶格写,前面不能留空格。同时,“:”前面不 能有空格,后面一定要留一个空格,大小写也不能出错。 其次,将 MANIFEST.MF 文件保存到编译后 class 文件包所在的目录,在命令行窗口执行如下命令, 执行 结果如图 4 所示。 path=C:\Program Files\Java\jdk1.6.0\bin jar cvfm YWC.jar mainfest.mf wyf/*. 由于本应用程序使用了资源图片,因此在运行可 执行 jar 包时需要将 jar 包与 img 文件夹放在同一个目 录下。另外,如果读者机器上的 JavaSE 安装完全正确 的话,也可以通过鼠标双击 YWC.jar 文件启动此应用 程序。. 7. 结语. 通过开发 Yahoo 天气预报客户端程序,读者应该对 JavaSE 中提供的 JAXP DOM 有了一定的了解。同时, 读者也应该了解到使用 Yahoo 提供的天气预报信息服务 来丰富自己软件的功能也是十分方便的。另外,本案例 虽然是桌面版的,但获取天气信息并解析的 YahooWeather 类是独立开发的。如果有需要,读者只要 稍加修改就可以将其与 Web 应用程序结合使用,让自己 的 Web 应用轻松拥有天气预报的功能。. 4.5 多媒体网络集中管理 王海峰 随着高校信息化建设的不断推进,多媒体网络教学 已经在全国各地的各类高校及单位得到广泛的应用,面 对着学校众多分布在不同校区和楼宇内的多媒体教室, 其管理与维护问题已经突显出来。. 算机进行网络远程控制。唤醒模块在服务器当中,其主 要功能就是要能够实现计算机远程启动,当需要通过网 络唤醒一台指定的远程计算机时,可以从本地计算机向 网络中发送一个基于 MAGIC PACKET 标准的唤醒数据. 本管理系统分服务器管理系统与客户端管理系统, 都是以 VB 6.0 编程实现,由于整个系统模块比较多, 不能全部叙述,现就系统中的关键技术:远程唤醒(即 远程启动计算机)、远程通信、远程关机、三个模块进. 包,该数据包中含有欲被唤醒计算机所带网卡的物理地 址,此时,欲被唤醒的计算机虽然处于关机状态,但其 网卡所带的控制芯片是由计算机电源的专用线路供电 的,因此仍然可以接受和处理网络上的数据包。当控制. 行详细阐述。. 芯片通过检查数据包内的 MAC 地址,发现并且确认数 据是发给自己的时候,就通过专用线路发出开启电源信 号,通知主板开机启动。 唤醒数据包的用户数据分为前后两部分,前面部分. 1. 远程唤醒模块的设计与实现 该模块主要是实现对远程计算机的集中唤醒,对计. 是 6 个 FF,用来表示这是一个特殊的唤醒数据包。后.
(19) 第四篇 网络与通信. 215. 面部分是被重复了 16 次的网卡的 MAC 地址,用于指定 欲唤醒的远程计算机唤醒数据包数据格式如表 1 所示,. B5688D750010B5688D750010B5688D750010B5688D75 0010B5688D750010B5688D750010B5688D750010B5688. 如假设要唤醒的远程主机所带网卡的 MAC 地址为 00-10-B5-68-8D-75,其对应的远程唤醒数据帧为:. D750010B5688D750010B5688D750010B5688D750010B 5688D750010B5688D750010B5688D75 远程唤醒部分用 VB.NET 编写。. FFFFFFFFFFFF0010B5688D750010B5688D750010 表1 目的地卡号. 来源地卡号. FFFFFFFFFF. 重复十六次的远程计算机 MAC. 控制台应用程序其实就是在 DOS 下运行的可执行文. Sub Main() data = Command(). 件,编写 wol.exe 唤醒程序以便在其他程序中调用。在 Visual Studio VB.NET 环境中使用命令行参数,Command() 函数读取要唤醒的计算机 MAC,Command()返回一个字 符串,其中包含在命令行上位于程序名称之后输入的所. intport = 3600 try. 其他数据. '接收 DOS 控制台输入的 MAC 地址. '唤醒数据端口为 3600. 'try…catch 错误处理机制. For i = 0 To 5 str(i) = Mid(data, 2*i + 1, 2) '取 MAC 地址中两个为一组. 有文本。为了添加参数,须按照下面几个步骤: 首先,在“项目”中选中 WOL 工程以打开工程的 属 性 页面 , 在属 性页 面 的左 边, 选择 Configuration Properties 下的 Debugging,如图 1 所示。. str(i) = "&H" + str(i). '在选取字符串前添加"&H". wol(i) = CByte(&HFF) Next For n = 1 To 16. '转换 6 个 FF 为字节型. '设置重复次数 n 为 16 次. i=n*6 wol(i) = CByte(str(0)) '转换 str 数组六个字符串为字节型 wol(i + 1) = CByte(str(1)) wol(i + 2) = CByte(str(2)) wol(i + 3) = CByte(str(3)) wol(i + 4) = CByte(str(4)) wol(i + 5) = CByte(str(5)) Next groupip = New IPEndPoint(IPAddress.Parse ("255.255.255.255"), intport) '设置 groupip 为网络广播地址 255.255.255.255 端口 3600 myudp = New UdpClient. 图1. WOL 工程的属性页面设置. myudp.Close(). 其次,在标题为命令行参数的文本框中输入(data) 一个或者使用空格分隔的多个参数,注意如果参数中包 含有空格的话则添加双引号。 最后,单击“确定”按钮,在运行该工程时,指定 的参数将被传送到程序中,就像在命令行提示符处输入 一样。 下面则是编好的 wol.exe 控制台可执行程序: Imports System.Net.Sockets Imports System.Net. '引入 Socket 类. '引入网络.NET 类. Module Module1 Dim n As Integer. '定义 n 为重复次数变量(整型). Dim i As Integer. '定义 i 为 MAC 个数变量(整型). Dim data As String. '定义 data 为字符串. Dim str(5) As String Dim myudp As UdpClient Dim intport As Integer. '定义 myudp 为 UdpClient 类. '重载 myudp. myudp.Send(wol, 102, groupip) '以 UDP 协议向网络中发送要唤醒的 MAC 物理地址 '发送完毕关闭 myudp. Catch ex As Exception. 'try…catch 错误处理机制. MsgBox("MAC 地址当中有错误") End Try End Sub End Module. 在工程中调用 wol.exe 的时候后面要空一格,譬如 在 VB 中调用这个控制台程序的时候,要远程启动的电 脑 MAC 地址为 00-10-B5-68-8D-75,那么在调用的时候 为这样 shell(c:\wol.exe 0010B5688D75)大小写都不要 紧。执行这个语句后就能把远程电脑给唤醒(要求计算 机的 CMOS 设置中的“Power Up On LAN”或者“Power Up On PCI Card”必须被设置“Enable”)。. 2. 客户端与服务器通信. '定义端口变量 intport 为整型. Dim wol(101) As Byte '定义 wol 为重复 16 次的字节型数组 Dim groupip As IPEndPoint '定义 groupip 为发送唤醒数据终端 IPEndPoint 型. 服务器要控制多个客户端,如实施远程关机、发送 命令等,必须通过网络通信。设计中用 VB 6.0 中的.
(20) 《电脑编程技巧与维护》2009 年合订本(精华版). 216. Winsock 控件来实现网络通信。服务器要可靠的与客户 端通信,同时要在服务器管理软件中实时地显示连接状. 1000 开始,服务器一个端口对一个远程计算机进行 TCP/IP 通信,例如计算机 1000 申请向服务器通信端口. 态,只有确保连接后才能够实现网络控制,所以采用 TCP/IP 协议建立网络连接。 计算机通信端口从 1~65535,设计中通信端口从. 1000 申请 TCP/IP 连接,服务器设计的每个通信端口都 处于侦听状态,只要有远程计算机申请就连接,其连接 示意图如图 2 所示。. 图2. 服务器与客户端 TCP/IP 连接示意图. 服务器端侦听代码: sckserver(0).LocalPort = 1000 sckserver(0).Listen 服务器端接收连接代码:. '设置服务器监听端口 '启动监听. Private Sub sckserver_ConnectionRequest(Index As Integer, ByVal requestID As Long) If sckserver(Index).state <> 0 Then sckserver(Index).Close '如申请连接的服务器端口没关,则先关闭此端口 End If sckserver(Index).Accept requested '对应服务器端口接收客户端申请连接 sckserver(Index).SendData "你已经与服务器建立连接!" '向客户端回发已连接成功的信号 End Sub 客户端申请连接代码: sckclient.RemoteHost = remoteIP '设置客户端的 IP 地址或计算机名 sckclient.RemotePort = 1000 '设置需要连接的远程服务器端口 sckclient.Connect '连接远程服务器. 发送数据采用 Winsock 的 SendData 方法,通过上 述代码可以进行网络通信。. 3. 远程关机. 机 操 作 。 假 设 需 要 控 制 的 计 算 机 的 IP 地 址 为 192.168.45.68,服务器端的主要程序代码如下: remoteIP = "192.168.45.68" '设置需要连接的 IP 地址 sckclient.RemoteHost = remoteIP sckclient.RemotePort = 1001 '设置需要连接的远程端口 sckclient.Connect '连接远程计算机. 连接上之后,如果要求关闭远程计算机,发送“关 机”字符串命令: Private Sub sckserver_Connect() sckserver.SendData "关机" End Sub. 客户端侦听服务器连接请求,只要连接上,客户端 根据服务器的指令来作出操作,其主要程序代码与步骤 如下: Private Sub sckserver_ ConnectionRequest (ByVal requestID As Long) sckserver.Accept requested '服务器首先接收对应客户端申请连接的请求 End Sub. 彼此建立 TCP/IP 连接成功后服务器发送“关机” 命令。 Private Sub sckserver_DataArrival(ByVal bytesTotal As Long) Dim remotedata As String sckserver.GetData remotedata. '接收关机命令. If Trim(remotedata) = "关机" Then Call closeclient(). 3.1 远程关机的设计思想 在 TCP/IP 网络协议的 C/S 结构中,在一个计算机 上装上服务器端的软件(控制方通过端口给受控方的端 口发送数据包),在受控的另外的计算机上装上客户端 的软件(用于侦听端口并接收数据包),通过 TCP/IP 网 络协议来进行网络通信。建立网络连接后,如果要关闭 客户端计算机,只要向客户端发送“关机”命令,当客 户端收到该命令后调用系统中的关机函数,就可完成关. '调用关机程序. End If End Sub. 接下来讲解客户端关机程序 closeclient()。. 3.2 客户端关闭操作系统 目前计算机系统多为 Windows 2000 和 Windows XP。Windows 98 系统下的关机比较容易,只需要直接 调用关闭计算机函数 ExitWindowEx 就可以了,而在 Windows 2000 系统下的调用这个函数只能“注销”而不.
(21) 第四篇 网络与通信 能实现系统关机。在 Windows 2000 系统实现关机操作 需得到 Shutdown 许可,得到 Shutdown 许可需要调用相. 217. Private Declare Function OpenProcessToken Lib "advapi32" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long. 应的 API 函数,具体过程如下: ①首先得到当前程序的进程句柄; ②使用这个进程句柄得到当前程序的访问标记; ③生成 TOKEN_PRIVILEGES 结构;. 3)查找进程权限函数 LookupPrivilegeValue,函数 声明如下: Private Declare Function LookupPrivilegeValue Lib "advapi32" Alias "LookupPrivilegeValueA" (ByVal lpSystemName As String, ByVal lpName As String, lpLuid As LUID) As Long. ④ 有 了 TOKEN_PRIVILEGES 结 构 后 再 获 得 Shutdown 权限; ⑤最后使用 ExitWindowEx 函数进行相关操作。. 4)获得关机权限函数 AdjustTokenPrivileges,函数 声明如下: Private Declare Function AdjustTokenPrivileges Lib "advapi32" (ByVal TokenHandle As Long, ByVal DisableAllPrivileges As Long, NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, PreviousState As TOKEN_PRIVILEGES, ReturnLength As Long) As Long. 3.2.1 相关的 API 函数 1)获得当前进程伪句柄函数 GetCurrentProcess,函 数声明如下: Private Declare Function GetCurrentProcess Lib "kernel32" () As Long. 5)关机函数 ExitWindowEx。用于关机操作的一些 常数如表 2 所示。. 2)取得程序访问标记函数 OpenProcessToken,函 数声明如下: 表2 常数值. 字符标识. 作用. &H20. TOKEN_ADJUST_PRIVILEGES. 关机权限标识. &H8. TOKEN_QUERY. 标识查询. &H2. SE_PRIVILEGE_ENABLED. 私有进程有效. 0. EWX_LOGOFF. 终止进程系统注销. 1. EWS_SHUTDOWN. 关闭系统电源. 2. EWS_REBOOT. 重新启动. 4. EWS_FORCE. 强行终止没有响应的进程. 3.2.2 关闭计算机的程序 代码如下: Private Sub closeclient() Dim hProcessHandle As Long Dim hTokenHandle As Long Dim tmpLuid As LUID Dim tkpNew As TOKEN_PRIVILEGES Dim tkpPrevious As TOKEN_PRIVILEGES Dim lBufferNeeded As Long '获取当前进程的一个伪句柄 hProcessHandle = GetCurrentProcess() OpenProcessToken hProcessHandle, TOKEN_ADJUST_ PRIVILEGES Or TOKEN_QUERY, hTokenHandle LookupPrivilegeValue "", "SeShutdownPrivilege", tmpLuid' 获取 LUID 关闭权限 tkpNew.PrivilegeCount = 1 '设置权限 tkpNew.TheLuid = tmpLuid tkpNew.Attributes = SE_PRIVILEGE_ENABLED lBufferNeeded = 0 '使关闭程序标识有效 '允许当前应用程序有关闭操作系统的权限 AdjustTokenPrivileges hTokenHandle, False, tkpNew,. Len(tkpPrevious), tkpPrevious, lBufferNeeded ExitWindowsEx EWX_FORCE Or EWX_POWEROFF, 0 End Sub. 将上述关机代码写入每个需要控制的客户端计算 机当中,就可以关闭计算机了。图 3、图 4 分别为多媒 体网络集中管理系统的服务器端与客户端主界面。. 图3. 服务器端控制软件.
(22) 《电脑编程技巧与维护》2009 年合订本(精华版). 218. 4. 结语. 本文所阐述的只是多媒体网络控制系统中的几个 关键技术,唤醒程序是在 VB.NET 2003 版中实现的控制 台应用程序;关机程序是在 VB 6.0 中实现的。整个多 媒体网络集中管理系统在实际运行中效果很好、各项功 能都能实现。. 图4. 客户端控制软件. 4.6 ASP 环境下网络硬盘的设计与实现 张 锋. 1. 在该文件夹下创建以“用户名+用户 ID”命名的文件夹, 作为网络硬盘用户的硬盘空间(一个为该用户使用的文 件夹) ,相应的目录为络硬盘用户的根目录。. 功能. 网络硬盘 NetDiskV1.0 是一款办公系统应用软件。 系统基于 B/S 架构,实现了多用户的并发访问。每个网 盘用户分配 1G 的空间,用户可在自己的硬盘空间内创 建 4 级文件夹,单个文件夹可再创建最多 10 个文件夹。 并主要实现了文件夹的切换、用户占用空间的显示、文 件夹内容的显示、文件夹的创建和删除、文件的上传、 下载和删除等功能。. 2. 设计原理. 2.3 文件夹切换 网络硬盘用户进入系统和进行文件夹切换的时,更 改当前文件夹路径变量的值,并存储到 session 变量中。 每次页面调用时,当前文件夹路径在该 session 变量中 取值。. 2.4 用户操作 利用自定义的 FSO 实现文件夹的创建、删除、使用 空间的计算等操作。. 2.1 用户登录. 2.5 文件上传. 网络硬盘用户登录系统时,从数据库中提取用户 名、用户 ID 号和是否为网络硬盘用户的信息,并存储 到相应的 session 变量中。. 2.2 用户文件映射 利用 server.MapPath()映射网络硬盘空间 userDisk 文 件夹在网络服务器上的位置,网络硬盘用户登录系统时. 利用化境无组件上传控件实现文件的上传。. 3. 界面设计. 界面设计力求简洁、直观和方便操作,界面元素和 设计效果分别如表 1 和图 1 所示。. 表 1 界面元素列表 名称. 类型. 取值. 说明. currentfcn. Select. 当前文件夹的路径. 显示当前文件夹的路径,进入下一级文件夹. bttnReturnUp. button. 返回上一级. 返回上一级文件夹. bttnUpload. button. 上传文件. 调用文件上传窗口,实现文件上传.
Outline
相關文件
why he/she is doing it before even starting work Unwittingly working on a previously.
• Students annotate a text using an annotation tool that identifies their authorship. • Advantage: student annotations may
How would this task help students see how to adjust their learning practices in order to improve?..
• A narrative poem is a poem that tells a story. Narrative poems can come in many forms and styles. They can be long or short, simple or complex, as long as they tell stories.
As soon as Bob finishes his meal, he will leave the restaurant.. Bob will leave the restaurant as soon as he finishes
Edge triggered device sample inputs on the event edge Transparent latches sample inputs as long as the clock is asserted.
[r]
èNÈIÈÅË6ÃIÈ^â ô?ÈÃ4Ì,˳Êýè)ÎêÒ,ËkÆNåòè&Ç ÆOÂ,ÃIÄsÆOÇ ÏÐË^ÂÐË^Ç,ÏÐÈ ÆOÇ ÃTÌ,Ë ÂÐÍ1Äsé6Ë