Posted: March 24, 2007 at 9:36 pm | Tags: class, debug, html, server, shell, web, windows, 开发, 类
关键字:Band,Desk Band,Explorer Band,Tool Band,浏览器栏,工具栏,桌面工具栏
一、引言
最近,由于工作的要求,我需要在 IE 上做一些开发工作。于是在 MSDN 上翻阅了一些资料,根据 MSDN 上的说明我用 ATL 胜利完成了“资本家老板”分配的任务。
(并且在白天睡觉的过程中梦到了老板给我加工资啦……)
现在,我把 MSDN 上的原文资料,经过翻译整理并把一个 ATL 的实现奉贤给 VCKBASE 上的朋友们。
二、概念
在翻译的过程中,有两个词汇非常不好理解。第一个词是 Band 对象,词典中翻译为“镶边、裙子边、带子、乐队……”我的英文水平有限,实在不知道应该翻译为什么词汇更合适。于是我毅然决然地决定:在如下的论述中,依然使用 band 这个词!(什么?没听明白?我的意思就是说,我不翻译这个词了)但到底 Band 对象应该如何理解那?请看图一:

图一
图一中画红圈的地方,分别称作“垂直的浏览器栏”、“水平的浏览器栏”、“工具栏”和“桌面工具栏”。这些“栏”,都可以在 IE 的“查看”菜单中或鼠标右键的上下文快捷方式菜单中显示或隐藏起来。这些界面窗口的实现,其实就是实现一种 COM 接口对象,而这个对象叫 band。这个概念实在是只能意会而无法言传的,我总不能在文章中把它翻译为“总是靠在 IE 主窗口边上的对象”吧?^_^
另外,还有一个词叫 site。这个很好翻译,叫“站点”!。呵呵,我敢打包票,如果你要能理解这个翻译在计算机类文章中的含义,那就只能恭喜你了,你的智慧太高了。(都是学计算机软件的人,做人的差距咋就这么大呢?)在本篇文章中,site 可以这样理解:IE 的主框架四周,就好比是“汽车站”,那些 band 对象,就好比是“汽车”。band 汽车总是可以停靠在“汽车站”上。所以,site 就是“站点”,它也是 COM 接口的对象(IObjectWithSite、IInputObjectSite)。
三、原理
3.1 基本 band 对象
Band 对象,从 Shell 4.71(IE 5.0) 开始提供支持。Band 是一个 COM 对象,必须放在一个容器中去使用,当然使用它们就好象使用普通窗口是一样的。IE 就是一个容器,桌面 Shell 也是一个容器,它们提供不同的函数功能,但基本的实现是相似的。
Band 对象分三种类型,浏览器栏 band(Explorer bands)、工具栏 band(Tool Bands)和桌面工具栏(Desk bands),而浏览器栏 band 又有两种表现形式:垂直和水平的。那么 IE 和 Shell 如何区分并加载这些 bands 对象呢?方法是:你要对不同的 band 对象,在注册表中注册不同的组件类型(CATID)。
|
Band 样式
|
组件类型
|
CATID
|
| 垂直的浏览器栏 |
CATID_InfoBand |
00021493-0000-0000-C000-000000000046 |
| 水平的浏览器栏 |
CATID_CommBand |
00021494-0000-0000-C000-000000000046 |
| 桌面的工具栏 |
CATID_DeskBand |
00021492-0000-0000-C000-000000000046 |
IE 工具栏不使用组件类型注册,而是使用在注册进行 CLSID 的登记方式。详细情况见 3.3。
在例子程序中,实现了全部四个类型的 band 对象,垂直浏览器栏(CVerticalBar)显示了一个 HTML 文件,并且实现了对 IE 主窗口浏览网页的导航等功能;水平的浏览器栏(CHorizontalBar)是一个编辑窗,它同步显示当前网页的 BODY 源文件内容;IE 工具栏(CToolBar)最简单,只是添加了一个空的工具栏;桌面工具栏(CDeskBar)实现了一个单行编辑窗口,你可以在上面输入命令行或文件名称,回车后它会执行 Shell 的打开动作。
3.2 必须实现的 COM 接口
Band 对象是 IE 或 Shell 的进程内服务器,所以它被包装在 DLL 中。而作为 COM 对象,它必须要实现 IUnknown 和 IClassFactory 接口。(大家可以不同操心,因为我们用 ATL 写程序,这两个接口是不用我们自己写代码的。)另外,Band 对象还必须实现 IDeskBand、IObjectWithSite 和 IPersistStream 三个接口:
IPersistStream 是持续性接口的一种。当 IE 加载 band 对象的时候,它通过这个接口的 Load 方法传递属性值给对象,让其进行初始化;而当卸载前,IE 则调用这个接口的 Save 方法保存对象的属性。用 ATL 实现这个接口很简单:
class ATL_NO_VTABLE Cxxx : ...... public IPersistStreamInitImpl, // 添加继承 ......{public: BOOL m_bRequiresSave; // IPersistStreamInitImpl 所必须的变量......BEGIN_COM_MAP(CVerticalBar) ...... COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit) COM_INTERFACE_ENTRY2(IPersistStream, IPersistStreamInit) COM_INTERFACE_ENTRY(IPersistStreamInit) ......END_COM_MAP()BEGIN_PROP_MAP(Cxxx)...... // 添加需要持续性的属性END_PROP_MAP()
上面的代码,其实实现的是 IPersistStreamInit 接口,不过没有关系,因为 IPersistStreamInit 派生自 IPersistStream,实例化了派生类,自然就实例化了基类。在例子程序中,我只在桌面工具栏对象中添加了持续性属性,用来保存和初始化“命令行”。另外 COM_INTERFACE_ENTRY2(A,B)表示的含义是:如果想查询A接口的指针,则提供B接口指针来代替。为什么可以这样那?因为B接口派生自A接口,那么B接口的前几个函数必然就是A接口的函数了,自然B接口的地址其实和A接口的地址是一样的了。
IObjectWithSite 是 IE 用来对插件进行管理和通讯用的一个接口。必须要实现这个接口的2个函数:SetSite() 和 GetSite()。当 IE 加载 band 对象和释放 band 对象的时候,都要调用 SetSite()函数,那么在这个函数里正好是写初始化和释放操作代码的地方:
STDMETHODIMP Cxxx::SetSite(IUnknown *pUnkSite){ if( NULL == pUnkSite ) // 释放 band 的时候 { // 如果加载的时候,保存了一些接口 // 那么现在:释放它 } else // 加载 band 的时候 { m_hwndParent = NULL; // 装载 band 的父窗口(就是带有标题的那个框架窗口) // 这个窗口的句柄,是调用 IUnknown::QueryInterface() 得到 IOleWindow // 然后调用 IOleWindow::GetWindow() 而获得的。 CComQIPtr< IOleWindow, &IID_IOleWindow > spOleWindow(pUnkSite); if( spOleWindow ) spOleWindow->GetWindow(&m_hwndParent); if( !m_hwndParent ) return E_FAIL; // 现在,正好是建立子窗口的时机。 // 注意,子窗口建立的时候,不要使用 WS_VISIBLE 属性 ... ... // 在例子程序中,用 CAxWindow 实现了一个能包容ActiveX的容器窗口(垂直浏览器栏) // 在例子程序中,用 WIN API 函数 CreateWindow 实现了标准窗口(水平浏览器栏、工具栏) // 在例子程序中,用 CWindowImpl 实现了一个包容窗口(桌面工具栏) /*********************************************************/ 以下部分,根据 band 对象特有的功能,是可以选择实现的 **********************************************************/ // 如果子窗口实现了用户输入,那么必须实现 IInputObject 接口, // 而该接口是被 IE 的 IInputObjectSite 调用的,因此在你的对象 // 中,应该保存 IInputObjectSite 的接口指针。 // 在类的头文件中,定义: // CComQIPtr< IInputObjectSite, &IID_IInputObjectSite > m_spSite; m_spSite = pUnkSite; // 保存 IInputObjectSite 指针 if( !m_spSite ) return E_FAIL; // 你需要控制 IE 的主框架吗? // 那么在类的头文件中,定义: // CComQIPtr< IWebBrowser2, &IID_IWebBrowser2 > m_spFrameWB; // 然后,先取得 IServiceProvider,再取得 IWebBrowser2 CComQIPtr < IServiceProvider, &IID_IServiceProvider> spSP(pUnkSite); if( !spSP ) return E_FAIL; spSP->QueryService( SID_SWebBrowserApp, &m_spFrameWB ); if( !m_spFrameWB) return E_FAIL; // 如果你取得了 IE 主框架的 IWebBrowser2 指针 // 那么,当它发生了什么事情,你难道不想知道吗? // 定义:CComPtr m_spCP; CComQIPtr< IConnectionPointContainer, &IID_IConnectionPointContainer> spCPC( m_spFrameWB ); if( spCPC ) { spCPC->FindConnectionPoint( DIID_DWebBrowserEvents2, &m_spCP ); if( m_spCP ) { m_spCP->Advise( reinterpret_cast< IDispatch * >( this ), &m_dwCookie ); } } // 咳~~~ 不说了,看源码去吧。这里能干的事情太多了... ... } return S_OK;}
IDeskBand 是一个特殊的 band 对象接口,有一个方法函数:GetBarInfo();
IDockingWindow 是 IDeskBank 的基类,有3个方法函数:ShowDW()、CloseDW()、ResizeBorderDW();
IOleWindow 又是 IDockingWindow 的基类,有2个方法函数:GetWindow()、ContextSensitiveHelp();
首先声明 IDeskBand ,然后要实现 IDeskBand 接口的共6个函数,这些函数比较简单,不同类型的 band 对象,其实现方法也都基本一致:
class ATL_NO_VTABLE Cxxx : ...... public IDeskBand, ......{......BEGIN_COM_MAP(Cxxx) ...... COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand) ......END_COM_MAP()// IOleWindowSTDMETHODIMP Cxxx::GetWindow(HWND * phwnd){ // 取得 band 对象的窗口句柄 // m_hWnd 是建立窗口时候保存的 *phwnd = m_hWnd; return S_OK;}STDMETHODIMP Cxxx::ContextSensitiveHelp(BOOL fEnterMode){ // 上下文帮助,参考 IContextMenu 接口 return E_NOTIMPL;}// IDockingWindowSTDMETHODIMP CVerticalBar::ShowDW(BOOL bShow){ // 显示或隐藏 band 窗口 if( m_hWnd ) ::ShowWindow( m_hWnd, bShow ? SW_SHOW : SW_HIDE); return S_OK;}STDMETHODIMP CVerticalBar::CloseDW(DWORD dwReserved){ // 销毁 band 窗口 if( ::IsWindow( m_hWnd ) ) ::DestroyWindow( m_hWnd ); m_hWnd = NULL; return S_OK;}STDMETHODIMP CVerticalBar::ResizeBorderDW(LPCRECT prcBorder, IUnknown* punkToolbarSite, BOOL fReserved){ // 当框架窗口的边框大小改变时 return E_NOTIMPL;}// IDeskBandSTDMETHODIMP CVerticalBar::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO* pdbi){ // 取得 band 的基本信息,你需要填写 pdbi 参数作为返回 if( NULL == pdbi ) return E_INVALIDARG; // 如果将来需要调用 IOleCommandTarget::Exec() 则需要保存这2个参数 m_dwBandID = dwBandID; m_dwViewMode = dwViewMode; if(pdbi->dwMask & DBIM_MINSIZE) { // 最小尺寸 pdbi->ptMinSize.x = 10; pdbi->ptMinSize.y = 10; } if(pdbi->dwMask & DBIM_MAXSIZE) { // 最大尺寸 (-1 表示 4G) pdbi->ptMaxSize.x = -1; pdbi->ptMaxSize.y = -1; } if(pdbi->dwMask & DBIM_INTEGRAL) { pdbi->ptIntegral.x = 1; pdbi->ptIntegral.y = 1; } if(pdbi->dwMask & DBIM_ACTUAL) { pdbi->ptActual.x = 0; pdbi->ptActual.y = 0; } if(pdbi->dwMask & DBIM_TITLE) { // 窗口标题 wcscpy(pdbi->wszTitle,L"窗口标题"); } if(pdbi->dwMask & DBIM_MODEFLAGS) { pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT; } if(pdbi->dwMask & DBIM_BKCOLOR) { // 如果使用默认的背景色,则移除该标志 pdbi->dwMask &= ~DBIM_BKCOLOR; } return S_OK;}
3.3 选择实现的 COM 接口
有两个接口不是必须实现的,但也许很有用:IInputObject 和 IContextMenu。如果 band 对象需要接收用户的输入,那么必须实现 IInputObject 接口。IE 实现了 IInputObjectSite 接口,当容器中有多个输入窗口时,它调用 IInputObject 接口方法去负责管理用户的输入焦点。
在浏览器栏中需要实现3个函数:UIActivateIO()、HasFocusIO()、TranslateAcceleratorIO()。
当浏览器栏激活或失去活性的时候,IE 调用 UIActivateIO 函数,当激活的时候,浏览器栏一般调用 SetFocus 去设置它自己窗口的焦点。当 IE 需要判断哪个窗口有焦点的时候,它调用 HasFocusIO 。当浏览器栏的窗口或其子窗口有输入焦点时,则应返回 S_OK,否则返回 S_FALSE。TranslateAcceleratorIO 允许对象处理加速键,例子程序中没有实现,所以直接返回 S_FALSE。
STDMETHODIMP CExplorerBar::UIActivateIO(BOOL fActivate, LPMSG pMsg){ if(fActivate) SetFocus(m_hWnd); return S_OK;}STDMETHODIMP CExplorerBar::HasFocusIO(void){ if(m_bFocus) return S_OK; return S_FALSE;}STDMETHODIMP CExplorerBar::TranslateAcceleratorIO(LPMSG pMsg){ return S_FALSE;}
Band 对象能够通过包容器的 IOleCommandTarget::Exec() 调用执行命令。而 IOleCommandTarget 接口指针,则可以通过调用包容器的 IInputOjbectSite::QueryInterface(IID_IOleCommandTarget,…) 函数得到。CGID_DeskBand 是命令组,当一个 band 对象的 GetBandInfo 被调用的时候,包容器通过 dwBandID 参数指定一个 ID 给 band 对象,对象要保存住这个ID,以便调用 IOleCommandTarget::Exec()的时候使用。ID 的命令有:
- DBID_BANDINFOCHANGED
Band 的信息变化。设置参数 pvaIn 为 band ID, 该 ID 就是最近一次调用 GetBandInfo 所得到的值,容器会调用 band 对象的 GetBandInfo 函数来更新请求信息。
- DBID_MAXIMIZEBAND
最大化 band。设置参数 pvaIn 为 band ID,该 ID 就是最近一次调用 ?GetBandInfo ?所得到的值。
- DBID_SHOWONLY
打开或关闭容器中其它的 bands。 设置参数 pvaIn 为VT_UNKNOWN 类型,它可以是如下的值:
| 值 |
描述 |
| pUnk |
band 对象的 IUnknown 指针,其它的桌面 bands 将被隐藏 |
| 0 |
隐藏所有的桌面 bands |
| 1 |
显示所有的桌面 bands |
- DBID_PUSHCHEVRON
在菜单项左边显示“v”的选择标志。容器发送一个 RB_PUSHCHEVRON 消息,当 band 对象接收到通知消息 RBN_CHEVRONPUSHED 提示它显示一个"v"的标志。设置 IOleCommandTarget::Exec 函数中 nCmdExecOpt 参数为 band ID,该 ID 是最近一次调用 GetBandInfo ?所得到的值,设置 IOleCommandTarget::Exec 函数中 pvaIn 参数为 VT_I4 类型,这是应用程序定义的一个值,它通过通知消息 RBN_CHEVRONPUSHED 中lAppValue 回传给 band 对象。
3.4 Band 对象注册
Band 对象必须注册为一个 OLE 进程内的服务器,并且支持 apartment 线程公寓。注册表中默认键的值是表示菜单的文字。对于浏览器栏,它加到 IE 菜单的“查看\浏览器栏”中;对于工具栏 band ,它加到 IE 菜单的“查看\工具栏”中;对于桌面 band, 它加到系统任务栏的快捷菜单中。在菜单资源中,可以使用“&”指明加速键。
通常,一个基本的 band 对象的注册表项目是:
HKEY_CLASSES_ROOT
CLSID
{你的 band 对象的 CLSID}
(Default) = 菜单的文字
InProcServer32
(Default) = DLL 的全路径文件名
ThreadingModel= Apartment
工具栏 bands 还必须把它们的 CLSID 注册到 IE 的注册表中。
在 HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Toolbar 下给出 CLSID 作为键名,而其键值是被忽略的。
HKEY_LOCAL_MACHINE
Software
Microsoft
Internet Explorer
Toolbar
{你的 band 对象的 CLSID}
还有几个可选的注册表项目(例子程序并不是这样实现的)。比如,你想让浏览器栏显示 HTML 的话,必须要如下设置注册表:
HKEY_CLASSES_ROOT
CLSID
{你的 Band 对象的 CLSID}
Instance
CLSID
(Default) = {4D5C8C2A-D075-11D0-B416-00C04FB90376}
同时,如果要指定一个本地的 HTML 文件,那么要如下设置:
HKEY_CLASSES_ROOT
CLSID
{你的 Band 对象的 CLSID}
Instance
InitPropertyBag
Url
另外,还可以指定浏览器栏的宽和高,当然,它是依赖于这个栏是纵向还是横向的。其实这个项目无所谓,因为当用户调整了浏览器栏的大小后,会自动保存在注册表中的。
HKEY_CURRENT_USER
Software
Microsoft
Internet Explorer
Explorer Bars
{你的 Band 对象的 CLSID}
BarSize
BarSize 键的类型必须是 REG_BINARY 类型,它有8个字节。左起前4个字节,是用16进制表示的像素宽度或高度,后4个字节保留,你应该设置为0。下面是一个可以在浏览器栏上显示 HTML 文件的全部注册表项目的例子,默认宽度为291(0×123)个像素点:
HKEY_CLASSES_ROOT
CLSID
{你的 Band 对象的 CLSID}
(Default) = 菜单文字
InProcServer32
(Default) = DLL 的全路径文件名
ThreadingModel= Apartment
Instance
CLSID
(Default) = {4D5C8C2A-D075-11D0-B416-00C04FB90376}
InitPropertyBag
Url= 你的 HTML 文件名
HKEY_CURRENT_USER
Software
Microsoft
Internet Explorer
Explorer Bars
{你的 Band 对象的 CLSID}
BarSize= 23 01 00 00 00 00 00 00
对于注册表的设置,用 ATL 实现其实是异常简单的。打开工程的 xxx.rgs 文件,并手工编辑一下就可以了。 下面这个文件源码,是例子程序中 IE 工具栏的注册表样式,HKLM 是需要手工添加的,因为它不使用组件类型方式注册。而对于其它类型的 band 对象只要在类声明中添加:
BEGIN_CATEGORY_MAP(Cxxx) // 向注册表中注册 COM 类型 IMPLEMENTED_CATEGORY(CATID_InfoBand) // 垂直样式的浏览器栏END_CATEGORY_MAP()
IE 工具栏类型 band 对象的“.rgs”文件
HKCR // 这个项目是 ATL 帮你生成的,你只要手工修改“菜单上的文字”就可以了{ Bands.ToolBar.1 = s ''ToolBar Class'' { CLSID = s ''{ 你的 CLSID }'' } Bands.ToolBar = s ''ToolBar Class'' { CLSID = s ''{ 你的 CLSID }'' CurVer = s ''Bands.ToolBar.1'' } NoRemove CLSID { ForceRemove { 你的 CLSID } = s ''用在菜单上的文字(&T)'' { ProgID = s ''Bands.ToolBar.1'' VersionIndependentProgID = s ''Bands.ToolBar'' ForceRemove ''Programmable'' InprocServer32 = s ''%MODULE%'' { val ThreadingModel = s ''Apartment'' } ''TypeLib'' = s ''{xxxx-xxxx-xxxxxxxxxxxxxxx}'' } }}HKLM // 这个项目是手工添加的IE工具栏所特有的{ Software { Microsoft { ''Internet Explorer'' { NoRemove Toolbar { ForceRemove val { 你的 CLSID } = s ''随便给个说明性文字串'' } } } }}
四、 ATL 实现
下载代码后(VC 6.0 工程),请参照前面的说明仔细阅读,代码中也有一些关键点的注释。如果想运行,则可以用 regsvr32.exe 进行注册,然后打开 IE 浏览器或资源浏览器就可以看到效果了。如果想自己实践一下,可以按照如下的步骤构造工程:
4.1 建立一个 ATL DLL 工程
4.2 添加 New ATL Object…,选择 Internet Explorer Object,选这个类型的目的是让向导给我们添加 IObjectWithSite 的支持。如果你使用的是 .net 环境,则不要忘记选择支持这个接口。

4.3 输入对象名称,比如我想建立一个垂直的浏览器栏,不妨叫它 VerBar

4.4 线程模型必须选择 Apartment,接口类型的选择无所谓,看你想不想支持 IDispatch 接口功能了。在例子程序中的垂直浏览器栏中,由于想更简单的操纵 IE 和从 IE 中接受事件(连接点),选择 Dual 是必要的。聚合选项,你只要别选择 Only 就可以了。

4.5 展现你无穷的智慧,开始输入程序吧。如果是 Debug 方式编译,可能会出现一个连接错误,报告找不到_AtlAxCreateControl,那么你要在菜单 Project\Settings…\Link 中增加对 Atl.lib 的连接。或者使用 #pragma comment ( lib, "atl" )加入连接库。
4.6 如果想调试代码,在菜单 Project\Settings…\Debug 中输入 IE 的路径名称,比如:“C:\Program Files\Internet Explorer\IEXPLORE.EXE”,然后就可以跟踪断点调试了。 编译和调试桌面工具栏的 band 对象,是非常麻烦的,因为计算机启动时自动运行 Shell,而 Shell 就会加载活动的桌面对象。
五、结束语
好了,到这里,就到这里了。祝大家学习快乐^_^
Posted: January 8, 2007 at 8:41 pm | Tags: blog, class, debug, flash, html, java, php, ror, server, shell, web, windows, 开发, 类
在 CB 上看到的……
办公
OpenOffice - office suite
PC Suite 602 - office suite
AbiWord – text editor
Atlantis Nova – text editor
Microsoft PowerPoint Viewer - power point files viewer
Adobe Reader – pdf reader
Foxit PDF Reader – pdf reader
PDFCreator – create pdf documents
Doc Convertor - document convertor
Convert – unit convertor
Converber – unit convertor
Sunbird – calendar/organizer
EssentialPIM Free – calendar/organizer
PhraseExpress – speed up your writing
ATnotes – create notes on the desktop
解压缩
7-Zip - compression program
IZArc - compression program
TugZIP - compression program
CabPack – compression program
Universal Extractor – extract files from any type of archive
互联网
Firefox – web browser
Internet Explorer- web browser
Maxthon – web browser
Opera – web browser
Avant Browser – web browser
Thunderbird – email client
PopTray – check for emails
Free Download Manager – download manager
FlashGet - download manager
WellGet – download manager
Download Master – download manager
WGET – commandline download manager
HTTrack – offline browser
WebReaper – offline browser
Yeah Reader - RSS reader
GreatNews - RSS reader
RSSOwl – RSS reader
P2P
µTorrent – torrent client
Azureus – torrent client
BitComet – torrent client
ABC – torrent client
BitTornado – torrent client
eMule – p2p client
SoulSeek – p2p client
Shareaza – p2p client
DC++ – Direct Connect network client
PeerGuardian – IP blocker
聊天
Miranda – chat client
MSN Messenger – chat client
Yahoo Messenger – chat client
QIP – chat client
Gaim – chat client
JAJC – chat client
HydraIRC – IRC client
Talkative IRC – IRC client
IceChat – IRC client
Skype – VOIP client
Google Talk - VOIP client
VoipStunt – VOIP client
Gizmo – VOIP client
Wengo – VOIP client
安全
AVG Free – antivirus
Avast Home Free – antivirus
AntiVir PersonalEdition – antivirus
BitDefender Free – antivirus
ClamWin – antivirus
CyberDifender - Internet Security Suite
Ad-aware – anti-spyware
Spybot: Search & Destroy – anti-spyware
Windows Defender – anti-spyware
SpywareBlaster - anti-spyware
Spyware Terminator – anti-spyware
Tootkit Reveaker - rootkit detection utility
Winpooch - system protection
HiJack Free – system protection
HighJackThis – hijackers detector and remover
Kerio Personal Firewall – firewall
Sygate Personal Firewall - firewall
ZoneAlarm - firewall
AxCrypt – file encryption
Simple File Shredder – securely delete files
PuTTy - SSH client
KeePass – password manager
LockNote – password manager
nPassword – password manager
Microsoft Baseline Security Analyzer – identify security misconfigurations
网络
Hamachi – VPN client
RealVNC – remote control
UltraVNC – remote control
Ethereal – local area network administration
The Dude – network administration
Wireshark – network administration
Angry IP Scanner – IP scanner
IP-Tools - IP scanner
Free Port Scanner – IP scanner
NetMeter – network bandwidth monitoring
服务器
FileZilla – FTP client
FileZilla Server – FTP server
EFTP – FTP client/server
XAMPP – integrated server package of Apache, mySQL, PHP and Perl
WAMP – Apache, PHP5 and MySQL server
音频
Foobar2000 – audio player
WinAmp – audio player
1by1 – audio player
JetAudio – audio player
XMPlay – audio player
Xion – audio player
Apollo – audio player
MediaMonkey – music organizer
The GodFather – music organizer
dBpowerAMP – audio converter
Audacity – audio converter
WavePad – audio converter
Kristal Audio Engine – audio editor
Exact Audio Copy – CD ripper
Audiograbber – CD ripper
CDex – CD ripper
Mp3 Tag Tools – tag editor
Mp3tag – tag editor
Taggin’ MP3 – tag editor
Monkey’s Audio – APE compressor/decompressor
mpTrim - mp3 editor
WavTrim - wave editor
EncSpot Basic – analyse mp3 files
视频
Windows Media Player – audio/video player
VLC – video player
Media Player Classic – video player
MV2Player – video player
CrystalPlayer 1.95 – video player
Zoom Player – video player
GOM Player – video player
viPlay – video player
DSPlayer – video player
VirtualDub – video editor
CamStudio – video screen recording
AviSplit – Avi splitter
Video mp3 Extractor – rip audio from video files
Free iPod Converter – convert all popular video formats to iPod video
MediaPortal – turning your PCinto a Media Center
The FilmMachine
图像
Gimp – image editor
PhotoFiltre – image editor
Paint.net – image editor
ArtRage - image editor
Artweaver – image editor
IrfanView - image viewer
Picasa - image viewer
XnView – image viewer
FastStone Image Viewer - image viewer
FuturixImager - image viewer
Easy Thumbnails – create thumbnails from images
JoJoThumb – create thumbnails from images
iWebAlbum - create web photo albums
JAlbum – create web photo albums
3D Box Shot Maker - design quality box shot
FastStone Capture - screen capture
WinSnap - screen capture
3D
Blender3D – 3D renderer
3Delight Free – 3D renderer
SketchUp – 3D modeling
Maya Learning Edition – 3D modeling
AutoIt – task automation
SciTE4AutoIt3 - text editor for AutoIt
AutoHotkey - task automation
PHP Designer – PHP editor
Notepad++ – text editor
ConTEXT Editor – text editor
PSPad – text editor
FoxEditor - text editor
Crimson Editor - source code editor
Elfima Notepad - text editor
Notepad2 - text editor
Nvu – HTML editor
Alleycode - HTML editor
BlockNote - web page editor
Weaverslave – web page editor
CD/DVD
DeepBurner – CD/DVD burner
CDBurner XP Pro – CD/DVD burner
BurnAtOnce – CD/DVD burner
Express Burn – CD/DVD burner
Zilla CD-DVD Rip’n’Burn – CD/DVD
刻录
ImgBurn – ISO, BIN burner
Daemon tools – virtual CD/DVD
DVD Decrypter – DVD ripper
DVD Shrink – DVD ripper
Nero CD-DVD Speed - CD/DVD info and quality test
解码
GSpot - codec information
AC3Filter – audio codec
Xvid – video codec
QuickTime Alternative – video codec
Real Alternative – video codec
K-Lite Codec Pack – all codecs
系统工具
CCleaner – system cleaner
xp-AntiSpy – OS setup
jv16 Powertools – system utilities
XP SysPad – system monitoring utility
What’s Running – process guard
Registrar Lite – registry editor
WinIPConfig – replacement for “ipconfig.exe” and “route.exe”
Unlocker – file eraser
Eraser – secure file eraser
Undelete Plus – file recovery
freeCommander – file manager
ExplorerXP - file manager
Duplicate File Finder – find all duplicate files
Ant Renamer – file renaming
ReNamer – file renaming
Icons From File – icos extractor
Chaos MD5 – MD5 generator
HashTab - MD5, SHA1 and CRC-32 file hashes
Rainlendar Lite – desktop calendar
Weather Watcher – weather firecast
Subtitle Workshop – subtitles editor
Ant Movie Catalog – movie organizer
Disclib – CD organizer
Dexpot – virtual desktops
DriveImage XML – create partition images
MozBackup – backup and restore bookmarks, etc.
SyncBack – system backup
Atomic Cock Sync – syncronize your clock
Citrus Alarm Clock – alarm clock
TaskSwitchXP – Alt-Tab replacement
Launchy - application launcher
allSnap – make all windows snap
Sysinternals Tools – various system tools
StrokeIt - mouse gestures
Net Profiles – create profiles of your network settings
ResourceHacker – view, modify, rename, add, delete
Java Runtime Environment – java for Windows
UI设计
RocketDock - application launcher
AveDesk – desktop enhancer
IconPhile - customize windows’s system icons
CursorXP Free – change mouse cursors
MacSound – volume control
LClock - Windows Longhorn clock
Y’z Dock – application launcher
Y’z Shadow – shadow effect to the windows
Y’z Toolbar – change the toolbar icons in Explorer and Internet Explorer
Taskbar Shuffle – rearrange the programs on the taskbar by dragging
Visual Task Tips – thumbnail preview image for each task in the taskbar
Badges - put badges on any folder or file
Folderico - change icons of the folders
Folder Marker – mark your folders
Folder2MyPC – add favourite locations to My Computer
Microsoft TweakUI – system settings
BricoPacks – shell packs
ShellPacks – shell packs
Tango Shell Patcher – shell patcher
XPize – GUI enhancer
Vista Transformation Pack - complete visual style
Vista Sound Scheme – Windows Vista sound scheme
Royale Theme - visual style
硬件检测
CPU-Z - cpu information
CrystalCPUID – cpu information
Central Brain Identifier – cpu information
Everest – system information
SiSoft Sandra - system information
SpeedFan - hardware monitor
Memtest86 – memory test
PowerMax – HDD test
3Dmark 06 - 3D game performance benchmark
Aquamark - performance benchmark
rthdribl – 3D benchmark
Fraps - 3D benchmark, fps viewer and screen recorder
Prime 95 - cpu benchmarking
SuperPI - cpu benchmarking
CPU Rightmark - cpu overclock
Core Temp - cpu temperature
ATiTool - video overclock
ATI Tray Tools – Radeon tweaker
aTuner - GeForce and Radeontweaker
RivaTuner – video overclock
Nokia Monitor Test - monitor adjustmets
UDPixel – fix dead pixels
游戏
123 Free Solitaire - solitaire games collection
Arcade Pack - classic arcade games
Live For Speed – online racing simulator
Enigma – puzzle game
Freeciv – multiplayer strategy game
Tux Racer – race down steep, snow-covered mountains
教育
SpeQ Mathematics - mathematics program
Dia – diagram creation program
Google Earth – explore the world
NASA World Wind – 3D virtual globe
Celestia – explore the space
Stellarium – planetarium
杂类
nLite – Build your own custom Windows disk.
VirtualPC – create virtual machines
grabMotion - webcam capture
iDailyDiary – simple page-for-a-day diary
Pivot Stickfigure Animator – create stick-figure animations
Wink – create presentations
Scribus – professional page layout
FreeMind – midn mapping software
Windows Live Writer – WYSIWYG blog authoring
墙纸
Michael Swanson - 1920 x 1200; 1600 x 1200; amazing wallpapers
Mikhail Arkhipov - 1920 x 1200; 1600 x 1200; amazing wallpapers
Posted: December 13, 2006 at 11:00 pm | Tags: debug, windows, 开发, 技术, 类
虽然在.NET时代这种命名法不再适用, 但作为C/C++开发人员来说, 还是非常有用的.
就MFC应用开发中, 这种命名法足够了. 除非你的风格另类.
转至http://www.kaoiki.com
匈牙利命名法是一种编程时的命名规范。基本原则是:变量名=属性+类型+对象描述,其中每一对象的名称都要求有明确含义,可以取对象名字全称或名字的一部分。命名要基于容易记忆容易理解的原则。保证名字的连贯性是非常重要的。
举例来说,表单的名称为form,那么在匈牙利命名法中可以简写为frm,则当表单变量名称为Switchboard时,变量全称应该为 frmSwitchboard。这样可以很容易从变量名看出Switchboard是一个表单,同样,如果此变量类型为标签,那么就应命名成 lblSwitchboard。可以看出,匈牙利命名法非常便于记忆,而且使变量名非常清晰易懂,这样,增强了代码的可读性,方便各程序员之间相互交流代码。
这种命名技术是由一位能干的Microsoft程序员查尔斯·西蒙尼(Charles Simonyi) 提出的,他出生在匈牙利。在 Microsoft 公司中和他一起工作的人被教会使用这种约定。这对他们来说一切都很正常。但对那些 Simonyi 领导的项目组之外的人来说却感到很奇特,他们认为这是死板的表达方式,甚至说带有这样奇怪的外观是因为它是用匈牙利文写的。从此这种命名方式就被叫做匈牙利命名法。
据说这种命名法是一位叫 Charles Simonyi 的匈牙利程序员发明的,后来他在微软呆了几年,于是
这种命名法就通过微软的各种产品和文档资料向世界传播开了。现在,大部分程序员不管自己使用
什么软件进行开发,或多或少都使用了这种命名法。这种命名法的出发点是把量名变按:属性+类型
+对象 描述的顺序组合起来,以使程序员作变量时对变量的类型和其它属性有直观的了解,下面
是HN变量命名规范,其中也有一些是我个人的偏向:
属性部分
全局变量
g_
常量
c_
c++类成员变量
m_
静态变量
s_
类型部分
指针
p
函数
fn
无效
v
句柄
h
长整型
l
布尔
b
浮点型(有时也指文件)
f
双字
dw
字符串
sz
短整型
n
双精度浮点
d
计数
c(通常用cnt)
字符
ch(通常用c)
整型
i(通常用n)
字节
by
字
w
实型
r
无符号
u
描述部分
最大
Max
最小
Min
初始化
Init
临时变量
T(或Temp)
源对象
Src
目的对象
Dest
这里顺便写几个例子:
hwnd : h 是类型描述,表示句柄, wnd 是变量对象描述,表示窗口,所以 hwnd 表示窗口句柄;
pfnEatApple : pfn 是类型描述,表示指向函数的指针, EatApple 是变量对象描述,所以它表示
指向 EatApple 函数的函数指针变量。
g_cch : g_ 是属性描述,表示全局变量,c 和 ch 分别是计数类型和字符类型,一起表示变量类
型,这里忽略了对象描述,所以它表示一个对字符进行计数的全局变量。
上面就是HN命名法的一般规则。
小结:匈牙利命名法
匈牙利命名法
MFC、句柄、控件及结构的命名规范 Windows类型 样本变量 MFC类 样本变量
HWND hWnd; CWnd* pWnd;
HDLG hDlg; CDialog* pDlg;
HDC hDC; CDC* pDC;
HGDIOBJ hGdiObj; CGdiObject* pGdiObj;
HPEN hPen; CPen* pPen;
HBRUSH hBrush; CBrush* pBrush;
HFONT hFont; CFont* pFont;
HBITMAP hBitmap; CBitmap* pBitmap;
HPALETTE hPaltte; CPalette* pPalette;
HRGN hRgn; CRgn* pRgn;
HMENU hMenu; CMenu* pMenu;
HWND hCtl; CState* pState;
HWND hCtl; CButton* pButton;
HWND hCtl; CEdit* pEdit;
HWND hCtl; CListBox* pListBox;
HWND hCtl; CComboBox* pComboBox;
HWND hCtl; CScrollBar* pScrollBar;
HSZ hszStr; CString pStr;
POINT pt; CPoint pt;
SIZE size; CSize size;
RECT rect; CRect rect;
一般前缀命名规范 前缀 类型 实例
C 类或结构 CDocument,CPrintInfo
m_ 成员变量 m_pDoc,m_nCustomers
变量命名规范 前缀 类型 描述 实例
ch char 8位字符 chGrade
ch TCHAR 如果_UNICODE定义,则为16位字符 chName
b BOOL 布尔值 bEnable
n int 整型(其大小依赖于操作系统) nLength
n UINT 无符号值(其大小依赖于操作系统) nHeight
w WORD 16位无符号值 wPos
l LONG 32位有符号整型 lOffset
dw DWORD 32位无符号整型 dwRange
p * 指针 pDoc
lp FAR* 远指针 lpszName
lpsz LPSTR 32位字符串指针 lpszName
lpsz LPCSTR 32位常量字符串指针 lpszName
lpsz LPCTSTR 如果_UNICODE定义,则为32位常量字符串指针 lpszName
h handle Windows对象句柄 hWnd
lpfn callback 指向CALLBACK函数的远指针
前缀 符号类型 实例 范围
IDR_ 不同类型的多个资源共享标识 IDR_MAIINFRAME 1~0x6FFF
IDD_ 对话框资源 IDD_SPELL_CHECK 1~0x6FFF
HIDD_ 对话框资源的Help上下文 HIDD_SPELL_CHECK 0×20001~0x26FF
IDB_ 位图资源 IDB_COMPANY_LOGO 1~0x6FFF
IDC_ 光标资源 IDC_PENCIL 1~0x6FFF
IDI_ 图标资源 IDI_NOTEPAD 1~0x6FFF
ID_ 来自菜单项或工具栏的命令 ID_TOOLS_SPELLING 0×8000~0xDFFF
HID_ 命令Help上下文 HID_TOOLS_SPELLING 0×18000~0x1DFFF
IDP_ 消息框提示 IDP_INVALID_PARTNO 8~0xDEEF
HIDP_ 消息框Help上下文 HIDP_INVALID_PARTNO 0×30008~0x3DEFF
IDS_ 串资源 IDS_COPYRIGHT 1~0x7EEF
IDC_ 对话框内的控件 IDC_RECALC 8~0xDEEF
Microsoft MFC宏命名规范 名称 类型
_AFXDLL 唯一的动态连接库(Dynamic Link Library,DLL)版本
_ALPHA 仅编译DEC Alpha处理器
_DEBUG 包括诊断的调试版本
_MBCS 编译多字节字符集
_UNICODE 在一个应用程序中打开Unicode
AFXAPI MFC提供的函数
CALLBACK 通过指针回调的函数
库标识符命名法 标识符 值和含义
u ANSI(N)或Unicode(U)
d 调试或发行:D = 调试;忽略标识符为发行。
静态库版本命名规范 库 描述
NAFXCWD.LIB 调试版本:MFC静态连接库
NAFXCW.LIB 发行版本:MFC静态连接库
UAFXCWD.LIB 调试版本:具有Unicode支持的MFC静态连接库
UAFXCW.LIB 发行版本:具有Unicode支持的MFC静态连接库
动态连接库命名规范 名称 类型
_AFXDLL 唯一的动态连接库(DLL)版本
WINAPI Windows所提供的函数
Windows.h中新的命名规范 类型 定义描述
WINAPI 使用在API声明中的FAR PASCAL位置,如果正在编写一个具有导出API人口点的DLL,则可以在自己的API中使用该类型
CALLBACK 使用在应用程序回叫例程,如窗口和对话框过程中的FAR PASCAL的位置
LPCSTR 与LPSTR相同,只是LPCSTR用于只读串指针,其定义类似(const char FAR*)
UINT 可移植的无符号整型类型,其大小由主机环境决定(对于Windows NT和Windows 9x为32位);它是unsigned int的同义词
LRESULT 窗口程序返回值的类型
LPARAM 声明lParam所使用的类型,lParam是窗口程序的第四个参数
WPARAM 声明wParam所使用的类型,wParam是窗口程序的第三个参数
LPVOID 一般指针类型,与(void *)相同,可以用来代替LPSTR
Posted: November 27, 2006 at 4:51 pm | Tags: class, debug, java, ror, server, web, 类
转至 www.jdon.com
注: 理解ACE中的Reactor模式, 高效的响应IO等事件.
当前分布式计算 Web Services盛行天下,这些网络服务的底层都离不开对socket的操作。他们都有一个共同的结构:
1. Read request
2. Decode request
3. Process service
4. Encode reply
5. Send reply
经典的网络服务的设计如下图,在每个线程中完成对数据的处理:
但这种模式在用户负载增加时,性能将下降非常的快。我们需要重新寻找一个新的方案,保持数据处理的流畅,很显然,事件触发机制是最好的解决办法,当有事件发生时,会触动handler,然后开始数据的处理。
Reactor模式类似于AWT中的Event处理:
Reactor模式参与者
1.Reactor 负责响应IO事件,一旦发生,广播发送给相应的Handler去处理,这类似于AWT的thread
2.Handler 是负责非堵塞行为,类似于AWT ActionListeners;同时负责将handlers与event事件绑定,类似于AWT addActionListener
如图:
Java的NIO为reactor模式提供了实现的基础机制,它的Selector当发现某个channel有数据时,会通过SlectorKey来告知我们,在此我们实现事件和handler的绑定。
我们来看看Reactor模式代码:
| public class Reactor implements Runnable{
final Selector selector; final ServerSocketChannel serverSocket;
Reactor(int port) throws IOException { selector = Selector.open(); serverSocket = ServerSocketChannel.open(); InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(),port); serverSocket.socket().bind(address);
serverSocket.configureBlocking(false); //向selector注册该channel SelectionKey sk =serverSocket.register(selector,SelectionKey.OP_ACCEPT);
logger.debug("–>Start serverSocket.register!");
//利用sk的attache功能绑定Acceptor 如果有事情,触发Acceptor sk.attach(new Acceptor()); logger.debug("–>attach(new Acceptor()!"); }
public void run() { // normally in a new Thread try { while (!Thread.interrupted()) { selector.select(); Set selected = selector.selectedKeys(); Iterator it = selected.iterator(); //Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。 while (it.hasNext()) //来一个事件 第一次触发一个accepter线程 //以后触发SocketReadHandler dispatch((SelectionKey)(it.next())); selected.clear(); } }catch (IOException ex) { logger.debug("reactor stop!"+ex); } }
//运行Acceptor或SocketReadHandler void dispatch(SelectionKey k) { Runnable r = (Runnable)(k.attachment()); if (r != null){ // r.run();
} }
class Acceptor implements Runnable { // inner public void run() { try { logger.debug("–>ready for accept!"); SocketChannel c = serverSocket.accept(); if (c != null) //调用Handler来处理channel new SocketReadHandler(selector, c); } catch(IOException ex) { logger.debug("accept stop!"+ex); } } } }
|
以上代码中巧妙使用了SocketChannel的attach功能,将Hanlder和可能会发生事件的channel链接在一起,当发生事件时,可以立即触发相应链接的Handler。
再看看Handler代码:
| public class SocketReadHandler implements Runnable {
public static Logger logger = Logger.getLogger(SocketReadHandler.class);
private Test test=new Test();
final SocketChannel socket; final SelectionKey sk;
static final int READING = 0, SENDING = 1; int state = READING;
public SocketReadHandler(Selector sel, SocketChannel c) throws IOException {
socket = c;
socket.configureBlocking(false); sk = socket.register(sel, 0);
//将SelectionKey绑定为本Handler 下一步有事件触发时,将调用本类的run方法。 //参看dispatch(SelectionKey k) sk.attach(this);
//同时将SelectionKey标记为可读,以便读取。 sk.interestOps(SelectionKey.OP_READ); sel.wakeup(); }
public void run() { try{ // test.read(socket,input); readRequest() ; }catch(Exception ex){ logger.debug("readRequest error"+ex); } }
/** * 处理读取data * @param key * @throws Exception */ private void readRequest() throws Exception {
ByteBuffer input = ByteBuffer.allocate(1024); input.clear(); try{
int bytesRead = socket.read(input);
……
//激活线程池 处理这些request requestHandle(new Request(socket,btt));
…..
}catch(Exception e) { }
}
|
注意在Handler里面又执行了一次attach,这样,覆盖前面的Acceptor,下次该Handler又有READ事件发生时,将直接触发Handler.从而开始了数据的读 处理 写 发出等流程处理。
将数据读出后,可以将这些数据处理线程做成一个线程池,这样,数据读出后,立即扔到线程池中,这样加速处理速度:

更进一步,我们可以使用多个Selector分别处理连接和读事件。
一个高性能的Java网络服务机制就要形成,激动人心的集群并行计算即将实现。
Posted: November 15, 2006 at 3:54 pm | Tags: cache, class, debug, html, java, linux, php, python, ruby, server, web, 优化, 测试, 类, 缓存
一、memcached 简介
在很多场合,我们都会听到 memcached 这个名字,但很多同学只是听过,并没有用过或实际了解过,只知道它是一个很不错的东东。这里简单介绍一下,memcached 是高效、快速的分布式内存对象缓存系统,主要用于加速 WEB 动态应用程序。
二、memcached 安装
首先是下载 memcached 了,目前最新版本是 1.1.12,直接从官方网站即可下载到 memcached-1.1.12.tar.gz。除此之外,memcached 用到了 libevent,我下载的是 libevent-1.1a.tar.gz。
接下来是分别将 libevent-1.1a.tar.gz 和 memcached-1.1.12.tar.gz 解开包、编译、安装:
# tar -xzf libevent-1.1a.tar.gz# cd libevent-1.1a# ./configure --prefix=/usr# make# make install# cd ..# tar -xzf memcached-1.1.12.tar.gz# cd memcached-1.1.12# ./configure --prefix=/usr# make# make install
安装完成之后,memcached 应该在 /usr/bin/memcached。
三、运行 memcached 守护程序
运行 memcached 守护程序很简单,只需一个命令行即可,不需要修改任何配置文件(也没有配置文件给你修改
):
/usr/bin/memcached -d -m 128 -l 192.168.1.1 -p 11211 -u httpd
参数解释:
-d 以守护程序(daemon)方式运行 memcached;-m 设置 memcached 可以使用的内存大小,单位为 M;-l 设置监听的 IP 地址,如果是本机的话,通常可以不设置此参数;-p 设置监听的端口,默认为 11211,所以也可以不设置此参数;-u 指定用户,如果当前为 root 的话,需要使用此参数指定用户。
当然,还有其它参数可以用,man memcached 一下就可以看到了。
四、memcached 的工作原理
首先 memcached 是以守护程序方式运行于一个或多个服务器中,随时接受客户端的连接操作,客户端可以由各种语言编写,目前已知的客户端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。PHP 等客户端在与 memcached 服务建立连接之后,接下来的事情就是存取对象了,每个被存取的对象都有一个唯一的标识符 key,存取操作均通过这个 key 进行,保存到 memcached 中的对象实际上是放置内存中的,并不是保存在 cache 文件中的,这也是为什么 memcached 能够如此高效快速的原因。注意,这些对象并不是持久的,服务停止之后,里边的数据就会丢失。
三、PHP 如何作为 memcached 客户端
有两种方法可以使 PHP 作为 memcached 客户端,调用 memcached 的服务进行对象存取操作。
第一种,PHP 有一个叫做 memcache 的扩展,Linux 下编译时需要带上 –enable-memcache[=DIR] 选项,Window 下则在 php.ini 中去掉 php_memcache.dll 前边的注释符,使其可用。
除此之外,还有一种方法,可以避开扩展、重新编译所带来的麻烦,那就是直接使用 php-memcached-client。
本文选用第二种方式,虽然效率会比扩展库稍差一些,但问题不大。
四、PHP memcached 应用示例
首先 下载 memcached-client.php,在下载了 memcached-client.php 之后,就可以通过这个文件中的类“memcached”对 memcached 服务进行操作了。其实代码调用非常简单,主要会用到的方法有 add()、get()、replace() 和 delete(),方法说明如下:
add ($key, $val, $exp = 0)
往 memcached 中写入对象,$key 是对象的唯一标识符,$val 是写入的对象数据,$exp 为过期时间,单位为秒,默认为不限时间;
get ($key)
从 memcached 中获取对象数据,通过对象的唯一标识符 $key 获取;
replace ($key, $value, $exp=0)
使用 $value 替换 memcached 中标识符为 $key 的对象内容,参数与 add() 方法一样,只有 $key 对象存在的情况下才会起作用;
delete ($key, $time = 0)
删除 memcached 中标识符为 $key 的对象,$time 为可选参数,表示删除之前需要等待多长时间。
下面是一段简单的测试代码,代码中对标识符为 ‘mykey’ 的对象数据进行存取操作:
<pre><?php// 包含 memcached 类文件require_once(‘memcached-client.php’);// 选项设置$options = array( ’servers’ => array(‘192.168.1.1:11211′), //memcached 服务的地址、端口,可用多个数组元素表示多个 memcached 服务 ‘debug’ => true, //是否打开 debug ‘compress_threshold’ => 10240, //超过多少字节的数据时进行压缩 ‘persistant’ => false //是否使用持久连接 );// 创建 memcached 对象实例$mc = new memcached($options);// 设置此脚本使用的唯一标识符$key = ‘mykey’;// 往 memcached 中写入对象$mc->add($key, ’some random strings’);$val = $mc->get($key);echo “n”.str_pad(‘$mc->add() ’, 60, ‘_’).“n”;var_dump($val);// 替换已写入的对象数据值$mc->replace($key, array(’some’=>‘haha’, ‘array’=>‘xxx’));$val = $mc->get($key);echo “n”.str_pad(‘$mc->replace() ’, 60, ‘_’).“n”;var_dump($val);// 删除 memcached 中的对象$mc->delete($key);$val = $mc->get($key);echo “n”.str_pad(‘$mc->delete() ’, 60, ‘_’).“n”;var_dump($val);?></pre>
是不是很简单,在实际应用中,通常会把数据库查询的结果集保存到 memcached 中,下次访问时直接从 memcached 中获取,而不再做数据库查询操作,这样可以在很大程度上减轻数据库的负担。通常会将 SQL 语句 md5() 之后的值作为唯一标识符 key。下边是一个利用 memcached 来缓存数据库查询结果集的示例(此代码片段紧接上边的示例代码):
<?php$sql = ‘SELECT * FROM users’;$key = md5($sql); //memcached 对象标识符if ( !($datas = $mc->get($key)) ) { // 在 memcached 中未获取到缓存数据,则使用数据库查询获取记录集。 echo “n”.str_pad(‘Read datas from MySQL.’, 60, ‘_’).“n”; $conn = mysql_connect(‘localhost’, ‘test’, ‘test’); mysql_select_db(‘test’); $result = mysql_query($sql); while ($row = mysql_fetch_object($result)) $datas[] = $row; // 将数据库中获取到的结果集数据保存到 memcached 中,以供下次访问时使用。 $mc->add($key, $datas);} else { echo “n”.str_pad(‘Read datas from memcached.’, 60, ‘_’).“n”;}var_dump($datas);?>
可以看出,使用 memcached 之后,可以减少数据库连接、查询操作,数据库负载下来了,脚本的运行速度也提高了。
之前我曾经写过一篇名为《PHP 实现多服务器共享 SESSION 数据》文章,文中的 SESSION 是使用数据库保存的,在并发访问量大的时候,服务器的负载会很大,经常会超出 MySQL 最大连接数,利用 memcached,我们可以很好地解决这个问题,工作原理如下:
- 用户访问网页时,查看 memcached 中是否有当前用户的 SESSION 数据,使用 session_id() 作为唯一标识符;如果数据存在,则直接返回,如果不存在,再进行数据库连接,获取 SESSION 数据,并将此数据保存到 memcached 中,供下次使用;
- 当前的 PHP 运行结束(或使用了 session_write_close())时,会调用 My_Sess::write() 方法,将数据写入数据库,这样的话,每次仍然会有数据库操作,对于这个方法,也需要进行优化。使用一个全局变量,记录用户进入页面时的 SESSION 数据,然后在 write() 方法内比较此数据与想要写入的 SESSION 数据是否相同,不同才进行数据库连接、写入数据库,同时将 memcached 中对应的对象删除,如果相同的话,则表示 SESSION 数据未改变,那么就可以不做任何操作,直接返回了;
- 那么用户 SESSION 过期时间怎么解决呢?记得 memcached 的 add() 方法有个过期时间参数 $exp 吗?把这个参数值设置成小于 SESSION 最大存活时间即可。另外别忘了给那些一直在线的用户延续 SESSION 时长,这个可以在 write() 方法中解决,通过判断时间,符合条件则更新数据库数据。
五、相关资源
肖理达 (KrazyNio AT hotmail.com), 2006.04. 06, 转载请注明出处
转载自:http://nio.infor96.com/php-memcached/
Posted: November 6, 2006 at 8:10 pm | Tags: class, debug, html, java, javascript, 类
scriptaculous学习笔记(三)
Slider滑动杆
滑动杆是通过两个Div嵌套而成的。一个是滑动槽,一个是滑动杆。将这两个div注册为滑动杆就可以了。
<div ID="track1" STYLE="width:200px;background-color:#aaa;height:5px;">
<div ID="handle1" STYLE="width:5px;height:10px;background-color:#f00;"> </div>
</div>
<script>
new Control.Slider(‘handle1′,’track1′,{
sliderValue:0.5,
onSlide:function(v){$(‘debug1′).innerHTML=’slide: ‘+v},
onChange:function(v){$(‘debug1′).innerHTML=’changed! ‘+v}});
</script>
程序通过new Control.Slider( )来注册滑动杆。第一个id是滑动杆,可以以[‘id1’,’id2’,…]的方式来注册多个滑动杆
第二个id是滑动槽。
后面花括号{}中的参数:
sliderValue:滑动杆初始值,当有多个滑动杆的时候,用 [v1,v2,…]的方式指定多个缺省值
range: $R(2,15) 滑动槽的值的上下限范围。默认是0~1
axis: ‘vertical’, 可以获得一个上下拖动的滑动杆.缺省为水平.
restricted:true, 多个滑杆时,初始值大的滑杆与初始值小的滑杆不能互相倒置大小.
values: [1,2,3…] 滑动槽的多个预设值。滑杆只能滑动到其中的某个值。
onSlide:function(v) 事件:滑动时触发。V是滑杆当前值。
onChange:function(v) 事件:值改变时触发。V是滑杆当前值。
滑杆区域:(多个滑杆之间围成的上下界区域)
spans:['span7-1','span7-2'],
startSpan:’span7-start’,
endSpan:’span7-end’,
这个地方还没有仔细看,不是非常明白。
注意:当存在多个滑杆时,滑动槽设为relative,滑动杆应设为display:absolute;left:0 ;top:0;
scriptaculous学习笔记(二)
Effect效果对象
下拉效果&上拉效果
<div id="d1">
aaaaaaa<p>bbbbbbbbbbbbbbbbb<p>ccccccccccccc<p>
</div>
<a href="#" onclick="Effect.BlindDown(‘d1′,{});; return false;">BlindDown()</a>
<p>
<a href="#" onclick="Effect.BlindUp(‘d1′,{});; return false;">BlindUp()</a>
Effect.BlindDown(‘d1′,{})函数的花括号里面{}可以跟参数:
duration:1.0; 这个数字表示动作持续时间。
delay: 0.5 延迟0.5秒再启动效果
如果想让一个Div开始的时候隐藏,点击下拉的时候才拉下,那么只需要将此Div的属性设为:display: none
上滚&下滚效果
这一组函数:
Effect.SlideUp(‘d1′,{});
Effect.SlideDown(‘d1′,{});
这组函数效果与Blind那一组基本一样,效果粗看起来差不多……我也是细心比较才发现的。原来Blind这一对内容是不会随着上拉或下拉而动的。而Slide中的内容会被拉上或拉下。
变色闪动效果
Effect.Highlight(‘d1′,{duration:1.5})
此元素将会改变几次颜色并最终返回原来的颜色。
渐变显示效果
Effect.Appear(‘d1’,{})
原来的元素初始CSS为display:none,用此效果后渐渐显示,渐变的alpha滤镜效果。
膨胀消失效果
Effect.Puff(‘d1’,{})
消失后可以使用Element.show(‘d1′) 再次将元素显示出来。
渐渐消失效果
Effect.Fade(‘d1′)
渐渐显示效果
Effect.Appear(‘test_img’)
震动效果
Effect.Shake(‘d1’,{})
此元素将会左右震动
闪烁效果
Effect.Pulsate(‘d1′,{})
此函数通过alpha滤镜来进行闪烁。
长大效果
Effect.Grow("d1",
{duration:5.0, direction: ‘bottom-right’, opacityTransition: Effect.Transitions.linear});
其中:direction 是指的元素从什么方向进入。
如果不指定后面的参数,元素缺省是从下面的中间开始变大。没有alpha效果。
萎缩效果
Effect.Shrink(“d1”,{})
长大效果Grow()的相反效果。
Toggle各种效果
汉语里面不知道怎么翻译Toggle,大体意思是:当某物打开的时候触发就关闭,而关闭的时候触发就打开 的一种像”乒乓开关”的行为。这种行为在做页面时特别有用。
Effect.toggle(‘d2′,’BLIND’)
Effect.toggle(‘d2′,’appear’)
Effect.toggle(‘d2′,’slide’)
…
似乎所有这种有着相反效果的函数都可以在这里设置Toggle, ’BLIND’中的效果名大小写不敏感。
取消效果函数
这几个函数真是乏善可陈……唯一要提的就是关于中止这几个动画过程的函数:cancel()
例如:
effect1=new Effect.SlideUp(‘d1’,{duration:10.0});
想要在这10秒钟中止动画过程: effect1.cancel()
效果队列
这个神秘的queue属性,还有待进一步学习……
function startTimeline() {
// 3x highlight in front
for(var i=0; i<3; i++)
new Effect.Highlight(‘d3′, { duration: 1.0, queue: ‘front’ });
// insert scale at very beginning
new Effect.Scale(‘d1′, 75, { scaleContent: true, duration: 1.0, queue: ‘front’ });
// parallel implied, delay 0.5 sec
new Effect.Highlight(‘d1′, { delay: 0.5 });
// puff at end
new Effect.Puff(‘d2′, { duration: 4.0, queue: ‘end’ });
}
scriptaculous学习笔记(一)
这两篇文章是我昨天一天的成果。scriptaculous真的是一个很好的类库,不过国内的资料似乎很少(起码我没有搜索到),正好是在学习这个咚咚,写个笔记来记录一下吧。
准备
包含库文件:
<script src="../prototype.js" type="text/javascript"></script>
<script src="../scriptaculous.js" type="text/javascript"></script>
可排序对象
例子:
以下代码将创建一个列表,并且可以拖动排序,每次移动户都将触发一个可以返回列表顺序的函数,并且已经序列化,可以通过Ajax传给服务器端。
//建立列表:
<ul id="x">
<li id="item_1">1</li>
<li id="items_2">2</li>
<li d="items_3">3</li>
<li d="items_4">4</li>
</ul>
//开始建立可排序组件
<script type="text/javascript" language="javascript" charset="utf-8">
// <![CDATA[
Sortable.create('x',
{overlap:'horizontal',
ghosting:true,
constraint:false,
onUpdate:function(sortable){alert(Sortable.serialize(sortable))},
onChange:function(element){$('state').innerHTML = Sortable.serialize(element.parentNode)}
});
这样一个可以排序的列表就作好啦~~恭喜~!
讲解:
其中,Sortable.create()的作用是将这个id=”x”的<UL>转化为可排序控件。第一个参数’x’便是此控件的ID。 花括号{ }内的属性列表是一些预置属性和各种动作的触发函数:
各个属性的意义:
l overlap : horizontal | vertical指明了列表是水平方向还是垂直方向排列。(在constraint属性中会和此属性有关)
l ghosting: true | false这个属性指明了拖动行时是否会在原来位置显示虚影占位。
l constraint: 'vertical' | 'horizontal' | false 这个属性指明了是否会被约束拖动方向。
l onUpdate:function(sortable){} :update事件将会在完成一次排序行为时(拖动后鼠标松开时)被触发。”sortable”参数中将会传入被绑定的<UL>对象。
l onChange:function(element){} :此事件将会在鼠标拖动时被触发,每移动一下都将触发此事件。注意:此事件传入的element参数是<UL>下被拖动的<LI>而非整个<UL>
构造函数中的参数列表:
参数名 初始值 说明
element: element
tag: 'li', // assumes li children,标签内可被拖动的子标签名
dropOnEmpty: false, ??
tree: false, // fixme: unimplemented ??
overlap: 'vertical', // one of 'vertical', 'horizontal'
constraint: 'vertical', // one of 'vertical', 'horizontal', false
handle: false, // or a CSS class ,CSS样式是此handle指定样式的标签部分可拖动如为false则整体可拖.
only: false, ???
hoverclass: null, //被拖入位置的CSS
ghosting: false, //显示残影占位
format: null, //???
onChange: Prototype.emptyFunction,
onUpdate: Prototype.emptyFunction
dropOnEmpty: true //or false 指定此<UL>等可排序区域可否接受其他<UL>中的元素
containment: ["list1","list2"] 当dropOnEmpty设为true,在此参数中设置可接受的列表id
除了构造函数,其余的常用方法:
l Sortable.serialize(sortable) 静态方法。返回一个当前sortable对象的按照排序顺序先后排列序号的字符串:如x[]=1& x[]=2& x[]=3,每一个<Li>的序号通过<li id="item_1">1</li>的下滑线后面的数字指定。下滑线前面的单词在一组排序中应使用一个相同的前缀。不同的组,前缀应该不同。
l Sortable .destroy(sortable) 静态方法。撤销此对象的排序属性。
常见问题:
当我们给<UL>外面加上DIV,比如<div style=”overflow-y:scroll;height:100px;”>
我们会发现页面一团糟了,UL溢出了DIV, 页面乱七八糟。
不用急,在Div的Style中加入 “position:relative;”就解决了<UL>不听指挥的问题。
现在再用一下,拖动有点问题……我们会发现定位不准确了,这是因为没有考虑到滚动条的偏移量。
我们在Sortable的构造函数前加上一句:
Position.includeScrollOffsets = true;
此问题便会迎刃而解~~!哈。
Posted: October 31, 2006 at 3:48 pm | Tags: debug, shell, unix, 类
FTP命令非常使用,尤其是在UNIX系统下FTP命令是Internet用户使用最频繁的命令之一,不论是在DOS还是UNIX操作系统下使用
FTP,都会遇到大量的FTP内部命令。熟悉并灵活应用FTP的内部命令,可以大大方便使用者,
并收到事半功倍之效。
FTP的命令行格式为: ftp -v -d -i -n -g [主机名] ,其中
-v 显示远程服务器的所有响应信息;
-d 使用调试方式;
-i 限制ftp的自动登录,即不使用;
-n etrc文件;
-g 取消全局文件名。
ftp使用的内部命令如下(中括号表示可选项):
1. ![cmd[args]]:在本地机中执行交互shell,exit回到ftp环境,如:!ls*.zip。
2. $ macro-ame[args]:执行宏定义macro-name。
3. account[password]:提供登录远程系统成功后访问系统资源所需的补充口令。
4. append local-file[remote-file]:将本地文件追加到远程系统主机,若未指定远程系统文件名,则使用本地文件名。
5. ascii:使用ascii类型传输方式。
6. bell:每个命令执行完毕后计算机响铃一次。
7. bin:使用二进制文件传输方式。
8. bye:退出ftp会话过程。
9. case:在使用mget时,将远程主机文件名中的大写转为小写字母。
10. cd remote-dir:进入远程主机目录。
11. cdup:进入远程主机目录的父目录。
12. chmod mode file-name:将远程主机文件file-name的存取方式设置为mode,如: chmod 777 a.out 。
13. close:中断与远程服务器的ftp会话(与open对应)。
14. cr:使用asscii方式传输文件时,将回车换行转换为回行。
15. delete remote-file:删除远程主机文件。
16. debug[debug-value]:设置调试方式, 显示发送至远程主机的每条命令,如: deb up 3,若设为0,表示取消debug。
17. dir[remote-dir][local-file]:显示远程主机目录,并将结果存入本地文件local-file。
18. disconnection:同close。
19. form format:将文件传输方式设置为format,缺省为file方式。
20. get remote-file[local-file]: 将远程主机的文件remote-file传至本地硬盘的local-file。
21. glob:设置mdelete,mget,mput的文件名扩展,缺省时不扩展文件名,同命令行的-g参数。
22. hash:每传输1024字节,显示一个hash符号(#)。
23. help[cmd]:显示ftp内部命令cmd的帮助信息,如:help get。
24. idle[seconds]:将远程服务器的休眠计时器设为[seconds]秒。
25. image:设置二进制传输方式(同binary)。
26. lcd[dir]:将本地工作目录切换至dir。
27. ls[remote-dir][local-file]:显示远程目录remote-dir, 并存入本地文件local-file。
28. macdef macro-name:定义一个宏,遇到macdef下的空行时,宏定义结束。
29. mdelete[remote-file]:删除远程主机文件。
30. mdir remote-files local-file:与dir类似,但可指定多个远程文件,如: mdir *.o.*.zipoutfile 。
31. mget remote-files:传输多个远程文件。
32. mkdir dir-name:在远程主机中建一目录。
33. mls remote-file local-file:同nlist,但可指定多个文件名。
34. mode[modename]:将文件传输方式设置为modename, 缺省为stream方式。
35. modtime file-name:显示远程主机文件的最后修改时间。
36. mput local-file:将多个文件传输至远程主机。
37. newer file-name: 如果远程机中file-name的修改时间比本地硬盘同名文件的时间更近,则重传该文件。
38. nlist[remote-dir][local-file]:显示远程主机目录的文件清单,并存入本地硬盘的local-file。
39. nmap[inpattern outpattern]:设置文件名映射机制, 使得文件传输时,文件中的某些字符相互转换,如:nmap $1.$2.$3[$1,$2].[$2,$3],则传输文件a1.a2.a3时,文件名变为a1,a2。该命令特别适用于远程主机为非UNIX机的情况。
40. ntrans[inchars[outchars]]:设置文件名字符的翻译机制,如ntrans1R,则文件名LLL将变为RRR。
41. open host[port]:建立指定ftp服务器连接,可指定连接端口。
42. passive:进入被动传输方式。
43. prompt:设置多个文件传输时的交互提示。
44. proxy ftp-cmd:在次要控制连接中,执行一条ftp命令,该命令允许连接两个ftp服务器,以在两个服务器间传输文件。第一条ftp命令必须为open,以首先建立两个服务器间的连接。
45. put local-file[remote-file]:将本地文件local-file传送至远程主机。
46. pwd:显示远程主机的当前工作目录。
47. quit:同bye,退出ftp会话。
48. quote arg1,arg2…:将参数逐字发至远程ftp服务器,如:quote syst。
49. recv remote-file[local-file]:同get。
50. reget remote-file[local-file]:类似于get,但若local-file存在,则从上次传输中断处续传。
51. rhelp[cmd-name]:请求获得远程主机的帮助。
52. rstatus[file-name]:若未指定文件名,则显示远程主机的状态,否则显示文件状态。
53. rename[from][to]:更改远程主机文件名。
54. reset:清除回答队列。
55. restart marker:从指定的标志marker处,重新开始get或put,如:restart 130。
56. rmdir dir-name:删除远程主机目录。
57. runique:设置文件名唯一性存储。
58. send local-file[remote-file]:同put。
59. sendport:设置PORT命令的使用。
60. site arg1,arg2…:将参数作为SITE命令逐字发送至远程ftp主机。
61. size file-name:显示远程主机文件大小,如:site idle 7200。
62. status:显示当前ftp状态。
63. struct[struct-name]:将文件传输结构设置为struct-name,缺省时使用stream结构。
64. sunique:将远程主机文件名存储设置为唯一(与runique对应)。
65. system:显示远程主机的操作系统类型。
66. tenex:将文件传输类型设置为TENEX机的所需的类型。
67. tick:设置传输时的字节计数器。
68. trace:设置包跟踪。
69. type[type-name]:设置文件传输类型为type-name,缺省为ascii,如:type binary,设置二进制传输方式。
70. umask[newmask]:将远程服务器的缺省umask设置为newmask,如:umask 3。
71. user user-name[password][account]:向远程主机表明自己的身份,需要口令时,必须输入口令,如:user anonymous my@email。
72. verbose:同命令行的-v参数,即设置详尽报告方式,ftp服务器的所有响应都将显示给用户,缺省为on。
73. ?[cmd]:同help。
Posted: October 10, 2006 at 11:28 am | Tags: blog, class, debug, html, linux, php, shell, windows
各位这阵子是不是看了不少的XGL/AIGLX的演示视频呢,他们都是用屏幕录像软件给录制下来的,今天我们就来介绍几个Linux下的屏幕录像工具。
首先要给大家介绍的这个1M多小巧而免费的xvidcap,当前最高版本为1.14rc1,它可以将屏幕操作录制为:avi、mpeg、asf、flv、dv、m1v、m2v和mov视频文件格式,安装方法如下:
wget http://switch.dl.sourceforge.net/sourceforge/xvidcap/xvidcap_1.1.4rc1_i386.debsudo dpkg -i xvidcap_1.1.4rc1_i386.debgedit ~/.local/share/applications/xvidcap.desktop
添加如下内容:
[Desktop Entry]Encoding=UTF-8Type=ApplicationComment=xvidcap screencastComment[zh_CN]=xvidcap screencastExec=xvidcapIcon=/usr/share/xvidcap/glade/xvidcap_logo.pngIcon[zh_CN]=/usr/share/xvidcap/glade/xvidcap_logo.pngName=xvidcapName[zh_CN]=xvidcapTerminal=false
安装完成后,在菜单的附件中点击xvidcap或者直接在终端中输入xvidcap直接执行xvidcap:

点吸管图标可以选择抓取范围,点桌面就是抓取全屏,点红点按钮开始录制,方块按钮停止,右键点击可以设定选项,比如生成的文件的名字,格式等。
第二个要介绍的是 wink,wink不只是一个屏幕录像软件,它还支持录制后的后期制作,添加/删除帧等,关于wink的这里有比较详细的介绍,当前Linux版本的wink为1.5,安装方法如下:
wget http://yet.another.linux-nerd.com/wink/download/wink15.tar.gztar xvzf wink15.tar.gz./installer.sh
以上缺省会将wink安装在~/wink目录里。现在先不急着运行,wink与scim有冲突,另外还与Ubuntu缺省的LANG不兼容,需要强制wink使用XIM语言使用en_GB.UTF-8,所以我们需要自己写过wink执行shell:
sudo gedit /usr/local/bin/wink
添加如下内容:
export GTK_IM_MODULE=XIMexport LANG=en_GB.UTF-8~/wink/wink
然后添加菜单:
gedit ~/.local/share/applications/wink.desktop
添加如下内容:
[Desktop Entry]Encoding=UTF-8Type=ApplicationComment=wink screencastComment[zh_CN]=wink screencastExec=winkIcon=Icon[zh_CN]=Name=winkName[zh_CN]=winkTerminal=false

除了以上提到的两款免费的录像工具,这里还有一个剑走偏锋的VNC2SWF,vnc2swf是将vnc的屏幕录制为swf的工具,所以如果您要使用这个的话,还得安装几个vnc服务器才行,这里有详细的安装步骤。
最后附上我用xvidcap录制的一段Aiglx+Beryl的视频:AIGLX_Beryl.swf
原文地址:http://blog.eshangrao.com/index.php/2006/10/09/288-windowslinux