Windows Live Writer+SyntaxHighter实现WordPress博客离线撰写时代码高亮

由于WordPress在线编写代码的不便,尤其是插入代码后对齐和缩进格式方面,一直都没有找到一个好的解决方案。索性就尝试使用Windows Live Writer离线撰写文章,不过对我这样一个整体和代码打交道的人来说,仍然绕不开代码的语法高亮和对齐。话说Windows Live Writer可以插入代码高亮插件,而且还是SyntaxHighter这款我很喜欢的风格,叫做“Windows Live Writer Source Code plugin for SyntaxHighlighter”,所以就急忙安装软件进行了尝试,结果却给热情的我足足的浇了一盆冰水,因为发布后的文章打开,浏览器会弹出“SyntaxHighter 无法找打brush:csharp”的提示(csharp为发布的代码语言),关闭通知后,文章中的代码也没有语法高亮,让人很失望。

经过网上一番资料的查找,发现可能的原因是插件只支持1.5.1版本的SyntaxHighlighter,而我的网站上安装的是最新的3.x版本(也可以切换到2.x风格)[参考资料],这可如何是好,我去哪里找1.5版本的安装,况且那个版本的风格还未知。

如何才能使用WordPress的SyntaxHighlighter3.0 插件和Windows Live Writer的该款插件,实现发布文章中的代码语法高亮并保持对齐缩进格式?

下面是我目前发现的一种方法。在此我将完整的过程记录如下:

1. WordPress 安装SyntaxHighlighter Evolved插件

在WordPress中搜索安装这款插件,然后启用该插件。

2. 安装Windows Live Writer并设置博客账号

网上相关教程很多,这里不再多述[参考教程]。

3. 安装插件

下载Windows Live Writer Source Code plugin for SyntaxHighlighter 插件,解压文件,并将WindowsLiveWriter.SourceCode.dll文件拷贝到Windows Live Writer 的plugin文件夹。具体为:

  • 32-bit 系统: C:\Program Files\Windows Live\Writer\Plugins
  • 64-bit 系统: C:\Program Files (x86)\Windows Live\Writer\Plugins

【注:解压得到的BlogEngine.net文件夹,直接无视就好】

下面就是重点内容了。

4. 撰写、发布含代码的文章

打开Windows Live Writer,新建日志,选择“插入—>Source Code Plugin…”

789c9e03a9ef.png

 

在弹出的对话框中粘贴代码,【对话框底端的语言和高亮设置可无视,因为后续还会修改】

0b2325d4a1dc.png

插入代码完成后,由“编辑”模式切换到“源代码”模式。可以看到粘贴的代码格式如下

pre.png

也许这个就是SyntaxHighlighter1.5.1版本支持的语法吧,但是现在用的已经是3.x版本了。所以接下来直接修改源代码,删除pre标签内的各种属性,增加3.x版本支持的中括号形式。修改如下:

cpp.png

修改完成后,切换会“编辑”状态,继续写文章。写好即可发布。

cpp.png

发布成功的效果如下:

ok.png

至此大功告成

—————————————-

更新:发现还是有问题,特殊符号显示不出来。于是又琢磨了另一套方法。大致如下:Windows Live Writer (简称WLW)中利用插件插入代码后,不用对代码做别的修改,发布完成后在WordPress中找到重新编辑这段代码,删除,并把WLW中的相应的代码复制下来粘贴上去,粘贴完成后在代码的首尾处分别加上[@cpp]、 [@/cpp](去掉@)。再次发布即可。

启示:善于用于源代码模式,直接通过修改文章的网页源代码来控制格式,确实能解决不少问题。

eVC开发WinSock程序时connect函数总是立即返回0的问题

Wince下eVC开发WinSock程序,connect函数总是返回0的问题。

前提:

一台Wince设备,一个串口线,一台PC。

Wince设备通过串口线连接到PC,使用ActiveSync工具同步,动态分配IP(DHCP)。

现象(问题):

在Wince下运行socket程序(系统底层利用ActiveSync通过PC连接网络),但connect函数立即返回,并且返回值始终为0(表示成功),

即便将PC的网络断开,即便连接的是一个任意的IP和端口,依旧立即返回一个0。

设计测试方案和分析:

方案一:将socket部分的程序移植到PC机上

  • 结果:connect函数返回值正确,运行正常。
  • 分析:所以问题应该出现在Wince设备本身或Wince设备与PC的连接上。

方案二:断开Wince设备与PC之间连接的串口线

  • 结果: connect函数返回SOCK_ERROR,运行正常。
  • 分析:所以问题出在了ActiveSync上。

方案三:不通过PC(即不使用串口线和ActiveSync工具),直接将Wince设备与服务器连接

  • 结果:connect函数返回这正确,运行正常

方案四:Wince设备和PC通过串口线相连接,但是不启动ActiveSync或者断开ActiveSync连接。

  • 结果:connect函数返回值正确,运行正常
  • 分析:通过以上几种方案,可以进一步确定是ActiveSync引起的问题。

结论:

由于使用了ActiveSync工具和DHCP,使得Wince设备在网络连接上出现了错误。

可能的原因是:

当Wince设备与PC通过ActiveSync连接,Wince设备连接网络时,只要连接请求能通过ActiveSync传送到PC,就默认为发送连接成功了,PC负责接下来的发送数据。Wince设备只有当接收不到响应数据时,才会判断出连接已经断开,所以连接上一段时间后,才会发现网络连接错误。

——————————————————————

该文2011-07-04 15:58首发于我的CSDN专栏。

发布一个ASP.NET网站的过程

本次实践基于Windows7,IIS7,Visual Studio 2008/2010

1. 新建ASP.NET WEB 项目

打开VS2008,新建一个ASP.NET Web项目


2. 编写网站代码

 根据自己的需要,编写自己的网站代码。

3. 发布网站

 菜单选择”Publish Web“,配置网站发布的目录,如F:/Web

 

4. IIS7 新建网站

 打开IIS7,右击
“网站”
,选择”添加网站”,打开添加网站对话框,对网站进行配置。

  • 网站名称:根据个人喜好自由设定
  • 物理路径:就是网站发布的路径,即上一步中的F:/Web

 单击
“确定”完成网站添加。
 


 5. IIS7中设置默认文档

 

  打开“默认文档”, 添加默认文档 Default.aspx,同时将其上移到顶部。

 

 6. IIS7中设置身份验证

 设置身份验证,允许匿名访问,这样别人的电脑就可以直接输入你的IP 登陆你的网站了


 7. 关闭防火墙

 如果按照以上步骤完成了,别人还是不能访问你的网站,那可能就是防火墙在作怪了。

 关闭防火墙,应该就没有问题了。

——————————————————————

该文2011-01-03 16:19首发于我的CSDN专栏。有改动。

(转载)XMLHTTPRequest对象原理介绍与应用

声明:转载自“让学习成为一种习惯”的百度空间。

作为wordpress的预热工作,我前阵子学了点PHP,其中接触到Ajax,并实际上手练习了一把,愈发觉得Ajax世界的奇妙。原文作者这篇文章写得很生动形象,忍不住转来珍藏。

XMLHTTPRequest对象原理介绍与应用

前一阵支援EKP,发现小蒋的代码中已经用JQuery做前端的开发了,于是就想到MAP3.0的时候希望每个开发人员都能掌握JQuery,这将会提高开发效率和质量。为什么我一直没用,说到这因为面临一个问题,原来prototype很流行,比较早的js开发库,而且不是每个开发人员都掌握的,那么就会带来一些问题,你写的代码别人看不懂,何谈修改,会给其它同事和项目开发人员带来一些痛苦和困惑,而且在长期的环境下,大多数开发人员已经习惯了“复制-粘贴-修改”的工作习惯,就像我一样,我现在都习惯这种开发方式了,而且好像也没带来什么问题,这种意识在长期的积累中会不断的加深,再加上平常进度的压力,已经不太主动去接受新事物了,所以希望公司这轮质量和性能的改革春风也能把我们这些开发人员吹一吹,也包括我,所以我今年的学习计划就是尽力的把以前学的给捡回来,也希望在捡的过程中,把一些分享给大家。这次分享本来想给大家分享jQuery的强大和开发的高效,但jquery这几天正在捡,过段时间再想想怎么介绍给大家比较合适,如果只是把常用方法,属性列出来可能有些乏味,所以要换种浅显易懂的方式。既然不介绍jquery那你还写这个干嘛??因为我想起jquery就想起了Ajax,想起ajax就想起了郭昊,然后再回过头想到了我们代码中的openXMLHTTP方法,最后想起了开头的一段:由于我们习惯copy的模式,可能有些原理就没有去学习和理解,所以想想就先介绍一下XMLHTTPRequest这个对象给大家,因为它是Ajax应用的基础,在jquery中有个好听的名字:ajax引擎!

XMLHTTPRequest最早是由微软IE5作为ActiveXObecjt对象引入的,引入这个东西的目的就是能向服务器发送异步请求,但这一对象直到Ajax技术的出现才真正有了用武之地,而其它浏览器厂商也认识到这一对象的重要性,纷纷引入但不是作为ActiveXObject对象引入,而是作为一个标准的浏览器对象引入的,现在IE7,IE8微软已经修正作为一个标准的浏览器对象引入,而且W3C组织也可能要把它标准化。所以以后我们的代码可能不会写成

Var xmlhttp = new ActiveXObject(“Miscrosoft.XMLHTTP”);

而直接写成

var xmlhttp=new XMLHTTPRequest();

那么说到这XMLHTTPRequest到底是什么,可以怎么用?如果你了解http协议这个问题就很好理解,就目前来讲所有的web的应用都是基于http协议的,这个协议规定了请求与响应一方应遵守的标准,只要满足这个标准就可以通信,例如我们建一个form然后填写信息提交到服务器,等待服务器处理,这个过程的实质其实就是浏览器把我们的请求包括form中的信息格式化成一个标准http协议的请求报头和请求正文,然后传送给服务器,我们一般都是这么干的,实质上XMLHTTPRequest也能这么干,也能格式化请求并发送请求而且还能返回服务器响应的内容。这也正是ajax应用的本质所在:

只取客户端关心的数据,而不必回送整个页面,实现了无刷新的效果!

那么XMLHTTPRequest是怎么干的呢?下面就介绍一下XMLHTTPRequest这个对象的方法和属性,并告诉你它是怎么干的。

场景:我想找个人帮我问李四:王五回家没有?

步骤1:var xmlhttp = new XMLHTTPRequest(); //实例化一个XMLHTTPRequest对象

比喻:找“张三”帮我做这个事,但现在张三只知道要帮我问话。

步骤2:xmlhttp.onreadystatechane=callback;//注册回调函数

比喻:张三带个手机,好告诉进展。

步骤3:xmlhttp.open(“get/post”,URL,isAsyn,username,password) //初始化http请求,并准备发送请求

5个参数:get/post采用哪种方法 ;URL请求的URL,同步或異步(true异步,默认值);username验证的用户名;password对应的密码。后两个参数可选,第三个参数省略用默认值

比喻:我现在告诉张三(xmlhttp)去问李四(URL).

采用get方向则直接是url?问话=王五回家没有,采用post则我把“问话=王五回家没有”写到纸条上并告诉李四你要问的就是纸上的问题。

如何选择同步意味着我必须等到张三回来我才能走开干其它的事,如果选择异常我吩咐完就干我自己的事了,等张三回来告诉我结果就行了。后面两个参数,如果李四不信任张三是我派去的,就会要求张三提供“暗号”,不然拒绝回答!

张三已经准备好,准备出发了!

步骤4:xmlhttp.send(null);若采用post方式写成xmlhttp.send(data)

场景:张三快去吧!张三已经出发了。

场景5:

function callback()
{
   If(xmlhttp.state==4&&xmlhttp.status==200)
   Alert(xmlhttp.responseText);//问的结果
}

场景:收到李四的回答!

但在场景5中为什么有判断,4代码什么,200又代码什么,因为张三去做这件事的时候还有其它状态,张三去问了在回来的路上和张三回来了。张三回来了就是4代码数据接收完成。200又代码什么呢,因为还有其它情况,例如张三没找到李四:404错误。

张三找到李四,李四说不清楚(没法处理),李四病了虽然知道说不了话(服务端不能正确响应请求),所以200代码李四没出现其它情况,是OK的。所以要加个判断!

【JarvisChu:总结起来,就是找张三(xmlhttp)帮忙去李四(URL)那里问“王五回家了没”(request参数),张三带个手机(异步),问完就打电话给我(调用callback函数)】

说到这应该差不多明白了吧.下面就简单列举一下方法和属性及事件!

方法:

  • abort方法,忽略xmlhttp对象,重新回到未初始化状态,也意味着终止请求。
  • open方法,初始化请求。
  • send发送请求。
  • setRequestHead设置请求的报头。例如请求的编码格式,就像告诉李四张三说的是英语你不能按照中文理解。
  • getResponseHead获取响应的指定报头。
  • getAllResponseHead获取响应的全部报头。

属性:

  • readystate状态就是描述张三是什么状态了,5个值,从0开始。0张三还不知道干啥事,1知道干啥事了,还没去。2已经去了 3,回来了还没到。4回来了并且已经到了。
  • status存放响应的状态码。
  • statusText存放响应状态码的简短描述。
  • responseText存放响应的文本,以文本方式存放。
  • responseXML存放响应的XML文档模式对象,如果返回的是文本些值为null.
  • onreadystatechange注册回调处理函数。

事件:

  • onreadystatechange事件当state状态发生改变时触发,即调用注册的回调函数处理!

WordPress中代码高亮和对齐

在博客中插入代码是一个码工最常做的事,但是向wordpress中粘贴代码时会默认去除了代码中的空格、Tab,使得代码失去了对齐和缩进,试想,一大块代码通通左对齐,这简直是一场噩梦。当然默认插入的代码页是没有语法高亮的。对我而言,没有对齐缩进和语法高亮的代码是不足以付之一撇的。

以前一直用CSDN的写博客,其插入代码功能还是不得不赞的,深得我心(虽然其它方面有各种限制和不合意)。于是动手改造我的wordpress编辑器,企图向CSDN的靠拢。虽然在尝试了各种方法后,没有能够实现与其相似的功能,但也算找到了一种方法迂回的实现了代码的高亮和对齐。

代码高亮

各种代码高亮插件供君选择,我偏好“SyntaxHighlighter Evolved”插件,其显示风格样式很合我意,使用简单。

代码对齐

由于不想放弃“SyntaxHighighter Evolved”,我拒绝了一些其他的代码对齐方法,而采用了下述方法

(1) 下载WordPress 代码粘贴助手(地址1地址2

(2) 将对齐后的代码(可以使用其他编辑器对齐代码)粘贴到WordPress代码粘贴助手中,点击“转换”,复制转换得到的代码。

助手1

(3) 在WordPress的文章编辑器中,切换到“文本”模式,粘贴转换得到的代码。

文本模式

(4) 再切换回“可视化”模式,在代码之前加上[@cpp],在代码之后加上[/cpp] (为了使用sytaxhighlighter的语法高亮)。

cpp

(1)-(3) 步可参考教程。感谢哈哈大侠的软件,对我很实用。

——————————–

2013-12-24更新

发现上述使用“WordPress 代码粘贴助手”来保持大块粘贴代码的对齐和缩进格式的方法,也常失效。至少今天我就自己就没有成功。WordPress在线撰写编写文章存在着诸多不便,于是我最终选择了安装Windows Live Writer离线写博客。

C++数制转换

十进制转换成n进制

这里n的范围是(1,9],将十进制转化成n进制的思路就是

循环求模、相除

实现代码如下

//将十进制 dec 转换成 n 进制,结果存在 other中,other在外部分配内存
void dec2other(int dec, char *other, int n)
{
    assert(n>1 && n<= 9);
    int i=0;
    char* tmpArray = new char[64];
    while(dec != 0){
        tmpArray[i] = dec%n+'0';//int转char
        dec /= n;
        i++;
    }
    //n进制的串的高位 保存在 tmpArray的高位,
    //如 dec=6,二进制为110,此时保存的tmpArray[0~2] = {0,1,1},逆序
    int len = i; //n进制串长
    for(i=0;i<len;i++){ //下面将tmpArray颠倒,存在other中
        other[i] = tmpArray[len-i-1];
    } //other[0~2]= {1,1,0} 这就是结果
    other[len] = '/0';
    delete[] tmpArray;
}

输入十进制数dec,要求转化成n进制的数并存放在other字符数组中。首先判断使用assert宏,判断n的合法性。然后new一个临时char数组,用于保存转换过程中的值。执行while循环,只要dec不为0,则将dec对n求模,并将结果转换为char型保存在tmpArray中。循环结束,tmpArray中保存了转换后的结果,但为逆序。最后将tmpArray逆序赋值给other,得到结果。调用示例如下

int dec = 128;
char* bin = new char[64];
dec2other(dec,bin,2);//转化成二进制
CString szNumber;
szNumber.Format("%s",bin);
AfxMessageBox(szNumber);//输出:10000000

char* octal = new char[64];
dec2other(dec,octal,8);//转化成八进制
szNumber.Format("%s",octal);
AfxMessageBox(szNumber);//输出:200

十进制转换成十六进制

基本思路和上面的一样,区别在于十六进制多出了’A’、’B’、’C’、’D’、’E’、’F’ 六个字符。当循环求模时,得到的结果大于9时,就要转换成相应的字母表示。代码如下

//hex 在外部分配空间
void dec2hex(int dec, char *hex)
{
    int i=0,flag;
    char* tmpArray = new char[64];
    while(dec != 0){
        flag = dec%16;
        //此次也可不使用switch-case,直接把字符保存在数组中,通过数组赋值实现
        switch(flag){
        case 10:
            tmpArray[i] = 'A';
            break;
        case 11:
            tmpArray[i] = 'B';
            break;
        case 12:
            tmpArray[i] = 'C';
            break;
        case 13:
            tmpArray[i] = 'D';
            break;
        case 14:
            tmpArray[i] = 'E';
            break;
        case 15:
            tmpArray[i] = 'F';
            break;
        default:
            tmpArray[i] = flag+'0';
            break;
        }
        dec /= 16;
        i++;
    }
    int len = i; //n进制串长
    for(i=0;i<len;i++){
        hex[i] = tmpArray[len-i-1];
    }
    hex[len] = '/0';
    delete[] tmpArray;
}

二进制转换成十进制

思路很简单,就是把二进制串的每一位上的数,乘上对应位上的权值,累加起来。

比如,二进制”110″,对应的十进制为1*2^2 + 1*2^1+0*2^0 = 1*4+1*2+0*1 = 6。(^表示幂)

实现代码如下

//二进制串保存在bin[]中,串长为n,函数返回对应的十进制数
int bin2dec(char bin[],int len){
    int dec = 0;//保存十进制结果
    for(int i=0;i<len;i++){
        if(bin[i] == '1'){
            dec += (int)pow(2,len-i-1); //计算 2 的 len-i 次方,并累加到最终结果
        }
        else if(bin[i] == '0'){
        }
        else{
            //输入二进制串有误!
            return 0;
        }
    }
    return dec;
}

八进制转十进制

思路与二进制转十进制相同。代码如下

//八进制串保存在oct[]中,串长为len,函数返回对应的十进制数
int oct2dec(char oct[],int len){
    int dec = 0;//保存十进制结果

    int nOct;
    for(int i=0;i<len;i++){
        if(oct[i] == '0'){ nOct = 0;}
        else if(oct[i] == '1'){ nOct = 1;}
        else if(oct[i] == '2'){ nOct = 2;}
        else if(oct[i] == '3'){ nOct = 3;}
        else if(oct[i] == '4'){ nOct = 4;}
        else if(oct[i] == '5'){ nOct = 5;}
        else if(oct[i] == '6'){ nOct = 6;}
        else if(oct[i] == '7'){ nOct = 7;}
        else{
            //输入八进制串有误!
            return 0;
        }
        dec += (int)(nOct*pow(8,len-i-1));
    }
    return dec;
}

十六进制转十进制

思路与二进制、八进制转十进制相同。代码如下

//十六进制串保存在hex[]中,串长为len,函数返回对应的十进制数
    int hex2dec(char hex[],int len){
    int result = 0;//保存转换的十进制数结果

    int nHex;
    for(int i=0;i<len;i++){
        if(hex[i] == '0'){ nHex = 0;}
        else if(hex[i] == '1'){ nHex = 1;}
        else if(hex[i] == '2'){ nHex = 2;}
        else if(hex[i] == '3'){ nHex = 3;}
        else if(hex[i] == '4'){ nHex = 4;}
        else if(hex[i] == '5'){ nHex = 5;}
        else if(hex[i] == '6'){ nHex = 6;}
        else if(hex[i] == '7'){ nHex = 7;}
        else if(hex[i] == '8'){ nHex = 8;}
        else if(hex[i] == '9'){ nHex = 9;}
        else if(hex[i] == 'A'){ nHex = 10;}
        else if(hex[i] == 'B'){ nHex = 11;}
        else if(hex[i] == 'C'){ nHex = 12;}
        else if(hex[i] == 'D'){ nHex = 13;}
        else if(hex[i] == 'E'){ nHex = 14;}
        else if(hex[i] == 'F'){ nHex = 15;}
        else{
          //输入十六进制串有误!
          return 0;
        }
    dec += (int)(nHex*pow(16,len-i-1));
    }
    return dec;
}

利用栈实现十进制转换为n进制

//《数据结构 c语言版》(严蔚敏) P48
void conversion(int N){
    InistStack(S);
    scanf("%d",dec); //从屏幕读取一个十进制
    while(dec != 0){ //转换
        Push(S,dec%N);
        dec /= N;
    }
    while(!StackEmpty(S)){ //显示结果
        Pop(S,e);
        printf("%d",e);
    }
}

PS:上述代码严格的说存在许多问题,比如没有考虑负数,代码不够简洁。后续有机会再改。另外,基于上述代码,我用MFC实现了一个MFC进制转换小工具,可是实现上述各种数制实时转换。软件可点此下载(貌似需要1积分,我没找到怎么修改,算了,如果需要,请留邮箱吧)。如需要源码,也请留邮箱。

数制转换软件

——————————————————————

该文2010-11-28 19:32首发于我的CSDN专栏。有改动。

最小化程序到托盘区

Windows系统右下角显示时间、音量的那块区域叫做系统托盘区(即任务栏的最右侧)。

通常的程序窗口,点击最小化按钮之后,会最小化到任务栏。如果一个程序不需要经常打开界面操作,以后台为主时,可以将它最小化到托盘区,这样就不会占用任务栏的一格,需要时点击托盘区图标打开即可。

最小化到托盘区

任意位置执行下面的代码可以将程序最小化到托盘

void CMyDlg::OnBtnToTray()
{
    NOTIFYICONDATA nid;
    nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);
    nid.hWnd=this-&gt;m_hWnd;
    nid.uID=IDR_MAINFRAME;
    nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP ;
    nid.uCallbackMessage=WM_SHOWTASK;//自定义的消息名称
    nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
    strcpy(nid.szTip,&quot;MySoftWare V1.0&quot;); //信息提示条
    Shell_NotifyIcon(NIM_ADD,&amp;nid); //在托盘区添加图标
    ShowWindow(SW_HIDE); //隐藏主窗口
}

下面解释这段代码

NOTIFYICONDATA 结构体

NOTIFYICONDATA: Contains information that the system needs to display notifications in the notification area. Used by Shell_NotifyIcon.

NOTIFYICONDATA 结构体包含了系统在托盘区(通知区)显示通知所需要的信息。它是函数Shell_NotifyIcon的参数。结构体包含的信息和使用方法如代码1所示。

代码1第8行设定一个回调消息WM_SHOWTASK(这是我们自己定义的消息,具体实现方法下面会讲述),当我们点击(左击、右击、双击等等)托盘区时,系统就会发送出WM_SHOWTASK消息。

Shell_NotifyIcon函数

BOOL Shell_NotifyIcon(
  _In_  DWORD dwMessage,//指示函数要执行的动作
  _In_  PNOTIFYICONDATA lpdata//指向NOTIFYICONDATA的指针
);

Shell_NotifyIcon: Sends a message to the taskbar’s status area.

向任务栏的状态区域(托盘区)发送一条消息。

dwMessage可取下面值中的一个:

  • NIM_ADD  添加一个图标(ICON)到托盘区
  • NIM_MODIFY 修改托盘区的一个图标
  • NIM_DELETE  删除托盘区的一个图标
  • NIM_SETFOCUM  将焦点返还到托盘区
  • NIM_SETVERSION  命令托盘区按照lpdata中指定的Shell版本运行

自定义Windows 消息

自定义一个Windows消息需要如下四个步骤

声明消息,声明消息处理函数,关联消息和消息处理函数,实现消息处理函数

windows_message

声明消息

在.cpp中 添加 #define WM_SHOWTASK (WM_USER + 1)

声明消息处理函数

在.h中添加 afx_msg LRESULT OnShowTask(WPARAM wParam,LPARAM lParam);

关联消息和处理函数

在.cpp的 BEGIN_MESSAGE_MAP 中 添加 ON_MESSAGE(WM_SHOWTASK,OnShowTask)

实现消息处理函数

在 .cpp中 实现函数 LRESULT CMyDlg::OnShowTask(WPARAM wParam,LPARAM lParam)

LRESULT CMyDlg::onShowTask(WPARAM wParam,LPARAM lParam)
//wParam接收的是图标的ID,而lParam接收的是鼠标的行为
{
    if(wParam!=IDR_MAINFRAME)
        return 1;
    switch(lParam)
    {
    case WM_RBUTTONUP://右键起来时弹出快捷菜单
    {
        LPPOINT lpoint=new tagPOINT;
        ::GetCursorPos(lpoint);//得到鼠标位置
        CMenu menu;
        menu.CreatePopupMenu();//声明一个弹出式菜单
        //增加菜单项“关闭”,点击则发送消息WM_DESTROY给主窗口(已隐藏),将程序结束。
        menu.AppendMenu(MF_STRING,WM_DESTROY,&quot;关闭&quot;);
        menu.AppendMenu(MF_STRING,WM_SHOWWINDOW,&quot;打开&quot;);
        //确定弹出式菜单的位置
        menu.TrackPopupMenu(TPM_LEFTALIGN,lpoint-&gt;x,lpoint-&gt;y,this);
        //资源回收
        HMENU hmenu=menu.Detach();
        menu.DestroyMenu();
        delete lpoint;
    }
    break;
    case WM_LBUTTONDBLCLK://双击左键的处理
    {
        this-&gt;ShowWindow(SW_SHOW);//简单的显示主窗口完事儿
    }
    break;
    }
    return 0;
}

拦截窗口的最小化消息,实现最小化到托盘区

以MFC对话框程序为例,当用户点击窗口右上角的最小化消息时,我们希望拦截此消息,实现程序的最小化到托盘,而不是默认的最小化到任务栏。

方法如下

(1)为窗口添加最小化按钮

MFC的对话框程序默认只有一个关闭按钮,所以首先要为窗口添加最小化(最大化)按钮。

右击窗口,选择“属性”,再切换到“样式”标签页,勾选“最小化框”“(最大化框”)

minimise

(2)添加窗口的OnSize消息响应

右击对话框类名,选择“Add Windows Message Handle…”,在打开的对话左侧选择“WM_SIZE”消息,单击右侧“Add and Edit”进入代码编辑。代码如下

void CMyDlg::OnSize(UINT nType, int cx, int cy)
{
    //最小化消息
    if(nType == SIZE_MINIMIZED)
    {
        //最小到托盘区
        NOTIFYICONDATA nid;
        nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);
        nid.hWnd=this->m_hWnd;
        nid.uID=IDR_MAINFRAME;
        nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP ;
        nid.uCallbackMessage=WM_HIDE_TO_TASK; //自定义的消息名称
        nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
        wcscpy(nid.szTip,L"ScreenCap 1.0"); //信息提示条
        Shell_NotifyIcon(NIM_ADD,&nid); //在托盘区添加图标

        ShowWindow(SW_HIDE); //隐藏主窗口
    }
    CDialogEx::OnSize(nType, cx, cy);
}

总结

至此,我们实现了程序的最小化,并给出了两种实行方案:一种是直接调用运行代码1,比如这可以是在菜单的消息响应函数中,也可以是在Button的消息响应函数中;一种是拦截窗口的最小化消息,调用代码1,实现窗口最小化到托盘。另外,还穿插讲到了NOTIFYICONDATA 结构体和Shell_NotifyIcon函数。

——————————————————————–

该文2010-08-01 19:19首发于我的CSDN专栏。有较大改动。

C++播放声音总结

程序中经常要用到声音,无论是简单的“滴答”,还是一小段乐谱,或者是一首CD。下面就总结一下目前我所知道的C++播放声音的方法。

1.播放系统消息声音

在平时使用Windows系统的时候,会经常遇到系统的提醒、警告、错误声音。这种使用MessageBeep实现。函数原型如下

BOOL WINAPI MessageBeep(
  _In_  UINT uType
);

MessageBeep: Plays a waveform sound. The waveform sound for each sound type is identified by an entry in the registry.

播放一个波形声音文件。这个波形声音对应的类型都是注册表中的一项。

使用方法如下

MessageBeep(MB_OK);
Sleep(3000);
MessageBeep(MB_ICONWARNING);
Sleep(3000);
MessageBeep(MB_ICONSTOP);
Sleep(3000);
MessageBeep(MB_ICONERROR);
Sleep(3000);
MessageBeep(MB_ICONEXCLAMATION);

2.播放wav格式声音

播放wav格式声音可以使用PlaySound函数,

BOOL PlaySound(
  LPCTSTR pszSound,
  HMODULE hmod,
  DWORD fdwSound
);

PlaySound: The PlaySound function plays a sound specified by the given file name, resource, or system event. 播放一个wav声音,或者是指定路径的wav文件,或者是一个资源,或者是一个系统事件对应的声音。

pszSound指定要播放的声音;fdwSound指定播放声音的类型和播放方式;hmod通常设为NULL,如果声音是资源文件,则设为包含资源文件的模块。

比如

#include <Mmsystem.h>
 #pragma comment(lib,"Winmm.lib")

//播放指定路径wav文件
 PlaySound(TEXT("recycle.wav"), NULL, SND_FILENAME);//系统声音,清空回收站的声音
 PlaySound(TEXT("c:\\love.wav"), NULL, SND_FILENAME);//用户指定声音文件

//播放资源文件中的声音
 PlaySound(MAKEINTRESOURCE(IDR_WAVE1), GetModuleHandle(NULL),SND_RESOURCE);//资源中声音

//播放系统事件声音
 PlaySound(TEXT("SystemStart"), NULL, SND_ALIAS);//开机声音

Windows的声音有许多,像recycle.wav就这C:\Windows\Media目录下(XP),系统事件如例程中的SystemStart也在该目录下(Windows XP 启动.wav)。这个目录下面还有其他的声音。

系统声音

3.利用MCI接口播放任意格式声音

MCI,Media Control Interface,媒体控制接口,是Windows系统提供给应用程序的媒体控制接口,很好很强大。关于MCI的更多使用,我将在以后专门讲解。这里指提供一个简单的例子。

#include <mmsystem.h> //导入声音头文件库
#pragma comment(lib,"winmm.lib")//导入声音的链接库

mciSendString("open C:/123.mp3" , NULL, 0, 0);
mciSendString("play C:/123.mp3 ", NULL, 0, 0);

4.强悍的MCIWndCreate()函数

MCIWndCreate()函数向系统注册一个MCIWnd 窗口类,并创建一个MCIWnd窗口,控制使用MCI设备。它不仅可以播放各种声音,还可以播放AVI文件。

//#include <Vfw.h>
 //#pragma comment(lib,"Vfw32.lib")

int type=MCIWNDF_SHOWALL|MCIWNDF_SHOWNAME; //播放控制条显示方式
 CString filename="C:/123.mp3"; //要播放的文件

//创建一个播放窗口
 HWND m_hwndMCI=MCIWndCreate(m_hWnd,AfxGetInstanceHandle(),type,filename);

//开始播放
 MCIWndPlay(m_hwndMCI);

/*if(m_hwndMCI!=NULL) {MCIWndDestroy(m_hwndMCI);}*///销毁MCIWND 窗口
MCIWnd播放工具条

MCIWnd播放工具条

5. Windows Media Player 控件

VC++6.0中,打开“project–>add to project–>Components and Controls –>Registered ActiveX Controls”,找到Windows Media Player控件。

Insert这个控件后,我们project中会自动添加17个类,这些都是Windows Media Player 控制相关,同时我们UI设计时的tools bar 中会多出一个控件,那就 Windows Media Player ,拖到窗口上就能使用。

将Windows Media Player控件拖动到自己的对话框窗口,并把该控件关联成Control 类型的变量,如m_ctlWMPlayer,在需要播放音乐的地方,调用其成员函数SetUrl即可播放该文件,如

m_ctrWMPlayer.SetUrl("C:/123.mp3")

———————-

2013-5-25 22:11::00 更新

6. 播放蜂鸣

使用Beep函数播放不同频率的蜂鸣

BOOL WINAPI Beep(
 __in DWORD dwFreq, //频率
 __in DWORD dwDuration //持续时间
);

while(1)    Beep(5000,500);

——————————————————————–

该文2010-08-03 19:46首发于我的CSDN专栏。有改动。

MFC递归复制文件夹

上一篇中使用CFileFind实现了递归删除文件夹。这一篇继续使用CFileFind类实现文件夹的复制。

文件title\name\path区分

开始之前,先讲一下文件最常用的三个属性title、name、path的区分。比如如下代码

CFile file("C:/note/file.txt",CFile::modeRead);

CString szPath = file.GetFilePath();
CString szName = file.GetFileName();
CString szTitle = file.GetFileTitle();

AfxMessageBox("Path : "+szPath);
AfxMessageBox("Name: "+szName);
AfxMessageBox("Title: "+szTitle);

请问输出的结果是什么

name和path很好理解,前者是文件名,后者是文件路径。那么name和title有何区别?

如果你文件夹选项中,设置的是显示文件后缀名,程序结果是

Path: C:/note/file.txtAfxMessageBox(“Path : “+szPath);
Name: file.txt
Title: file.txt

如果你文件夹选项中,设置的是隐藏文件后缀名,程序结果是

Path: C:/note/file.txtAfxMessageBox(“Path : “+szPath);
Name: file.txt
Title: file

可以看出区别了。Path是全路径+文件名,包括后缀名;name是文件名,包括后缀名;title是文件显示的名字,如果系统显示了后缀名,则其包括后缀名,否则不包括。

递归复制文件夹

MFC 中提供了一系列文件夹管理函数,却没有复制、移动文件夹这种基本操作函数

directory_manager

不过,按照上篇中递归的思想,仍旧可以实现复制文件夹,无论其非空与否。

实现代码

void myCopyDirectory(CString source, CString target)
{
    CreateDirectory(target,NULL); //创建目标文件夹
    //AfxMessageBox("创建文件夹"+target);
    CFileFind finder;
    CString path;
    path.Format("%s/*.*",source);
    AfxMessageBox(path);
    bool bWorking = finder.FindFile(path);
    while(bWorking){
        bWorking = finder.FindNextFile();
        AfxMessageBox(finder.GetFileName());
        if(finder.IsDirectory() && !finder.IsDots()){ //是文件夹 而且 名称不含 . 或 ..
            //递归创建文件夹+"/"+finder.GetFileName()
            myCopyDirectory(finder.GetFilePath(),target+"/"+finder.GetFileName());
        }
        else{ //是文件 则直接复制
            //AfxMessageBox("复制文件"+finder.GetFilePath());//+finder.GetFileName()
            CopyFile(finder.GetFilePath(),target+"/"+finder.GetFileName(),FALSE);
        }
    }
}

使用CFindFile对象,判断源文件夹的子项是文件还是文件夹,如果是文件,则直接copy过去,如果是文件夹则递归复制该子文件夹。

如果要实现递归移动,思路相同,区别在于复制过程中复制完一项就要删除源文件夹中相应的项。或者更简单

递归移动=递归复制+递归删除

——————————————————————–

该文2010-08-03 13:00首发于我的CSDN专栏。有改动。

MFC递归删除文件夹

最近在看MFC 的文件操作,从网上淘了一本比较讲MFC文件操作比较全的电子书,然后开始试手。在删除文件夹时,遇到了问题,通过查看MSDN和网友的论坛留言,自己总算是解决了这个问题,现在与大家共享。

MFC中提供了删除文件夹的一个封装函数 RemoveDirectory()

BOOL WINAPI RemoveDirectory(
  _In_  LPCTSTR lpPathName
);

只要把要删除的文件夹的路径传进去就可以删除了,貌似一切如此简单。我象征性的建立一个文件夹,然后在程序中删除了它,okay,一下就成功了。正当我要转手去做另外的操作时,喜欢乱尝试的毛病就鬼使神差的让我做了这么一件事,在这个文件夹下我添加了几个新的子文件夹以及一些文件,再试我的程序,出问题了,删不掉了!

原来RemoveDirectory()欺骗了我,它只能删除空的文件夹,这下就有问题了,如何才能删除一个文件夹,即便其中含有无数的子文件和子文件夹?

递归删除

RemoveDirectory() 的这种行为其实是情有可原的,它为我们的操作提供了一种安全级别的控制。 但如果要删除非空文件夹 , 如何操作?答案是

递归删除

递归,现将其所有子文件和子文件夹删除,在将其删除,问题解决。

实现代码

void myCleanDirectory(CString directory_path) //删除一个文件夹下的所有内容(清空文件夹)
{
   CFileFind finder;
   CString path;
   path.Format("%s/*.*",directory_path);
   BOOL bWorking = finder.FindFile(path);
   while(bWorking){
     bWorking = finder.FindNextFile();
     if(finder.IsDirectory() && !finder.IsDots()){//处理文件夹
       myCleanDirectory(finder.GetFilePath()); //递归清空该文件夹
       RemoveDirectory(finder.GetFilePath());
     }
     else{//处理文件
       DeleteFile(finder.GetFilePath());
     }
   }
}

首先定义一个CFileFind对象finder

CFileFind: Performs local file searches and is the base class for CGopherFileFind and CFtpFileFind, which perform Internet file searches.

执行本地文件查找,也是CGopherFileFind 和 CFtpFile(实现网络文件查找的对象)的基类。

设置要查找的文件名path为当前文件夹directory_path下的所有文件,包括文件夹(*.*)。执行FindFile()搜索,

FindFile(): Call this member function to open a search

调用该函数,打开一个搜索。查找成功返回非0值,查找失败返回0。FindFile()调用后,在调用其他文件属性函数前,必须至少调用一次FindNextFile函数。

bWorking非0时,表示查找成功,调用FindNextFile来获得查找结果序列中的下一个(第一次调用时返回序列的第一个)。然后,判断查找到的是文件还是文件夹,如果是文件,则直接删除;如果是文件夹,则递归调用myCleanDirectory()删除其子文件和子文件夹,再将其删除。

测试

为了测试myCleanDirectory函数,可以新建一个MFC工程,再新建一个测试文件夹ForVcTest,在文件夹中添加各种子文件和子文件夹,在工程中加入下面的代码

void DeleteAllDirectory() //删除文件夹 包括非空的文件夹
{
   //第一步 清空文件夹,删除该文件夹下所有文件
   myCleanDirectory("C:/ForVcTest");

   //第二步 删除该空文件夹
   RemoveDirectory("C:/ForVcTest");
}

执行代码,一个内容丰富的文件夹就消失了。成功。

——————————————————————–

该文2010-08-01 16:50首发于我的CSDN专栏。有改动。

密码保护:测试离线博客

这是一篇受密码保护的文章,您需要提供访问密码:

我与我的网站不得不说的事-建站历程

经过一番折腾,总算把自己的网站建立起来了。

为了纪念一下,也为了不让网站的第一天空空如也,记录一下我整个建站的心路历程,成此一篇,权当“镇站”吧。

憧憬阶段

网站是个很神奇的东西!

我一直这么想,特别是见识到了各色各类网站之后。

朦胧中记得是高中时微机课上,第一次接触到frontpage,按着教材摆弄出一个名为“我的主页”的简单静态html后,大喜,想来网页的东东不过如此。别人的网站都能动,我的文字和图片就不动,激起了我的好奇,当然这只是我好奇事物的冰山一角。

frontpage2000软件

frontpage2000软件

frontpage2000编辑界面

frontpage2000编辑界面

后来接触了html语言,用个专业的工具(表示用过Dw),敲几行标签,浏览器一打开,页面出来了。还是那个疑问,别人的能动我的怎么做到动呢?这个时候我掌握的知识已经不少了,我一度想,那是别人直接用的动画(gif,flash)。但还有一个问题,网页时给别人用的,当别人打开我的网站时,我怎么根据他的需要把东西显示给他呢?能提出这个问题,一下子把我境界提高了,因为让我接触到了另一个全新的东西–动态网页。

升级阶段

网页原来是分静态网页和动态网页之分的,从此我又陷进了这一个新概念。通过不懈的搜索查找和阅读,我搞清楚了这个概念,仅仅是概念,因为要自己做一个出来的话,由要涉及更多新的技术了,什么ASP,JSP,JS一堆,什么Web服务器,数据库服务一堆,这是一个坑接一坑啊。好歹我还是有兴趣的,开始学ASP.NET,听说这个东西好,比ASP新,那个时候对微软的产品还是抱有很大期待的,加上开发工具好,入门比较快。反正是学了一段时间,没有具体的项目,也没有觉悟搞自己的网站(主要是没资金和对技术的一点畏惧)。一段时间后,成果就是“我曾经用过ASP.net”,还是很熟悉的嘛,开发过程很友好嘛。

据说闭源收费的东西是没有前途的,ASP.net就可怜的被我冷落了。

那什么东西好?!JSP!跟着java潮流,前途一片光明,刚好那时学校也开了这么课。于是我又入了个门。还曾幻想着弄一个人人之类的社交网站,再不济弄一个自己的个人主页。

难度还是在哪里。不了了之的搁浅了。

单机阶段

有那么一个时刻,突然想到,建自己网站不一定就要自己写代码啊。是啊,于是又有了一种新的尝试。去网上找找源码运行学习一下也不错。

有那么一天,突然接触到了一个新东西,wordpress,什么,搞个博客网站这么简单?难以置信,于是去网上找资料看教程,折腾一番之后恍悟,原来就是这么简单!搭个apache,装个mysql,在下载一个wordpress,修修改改几行代码配置,浏览器“localhost/wordpress”那么一输入,网站建起来了。这还不够简单?apache、mysql配置太难。没事,我们有apache的好朋友-XAMPP。有了它,你什么都不用配置了。

apache

apache

xmapp

xmapp

有了这个利器之后,我开始摆脱种种建站的烦闷,开始一心一意的学习wordpress的使用,为了更好的使用wordpress,我又不得不接触PHP。

终于让我学成了!

我开始不安分了,当初那个想建一个自己博客的念头又出来了,尤其是当我发现之前用的博客网站限制越来越多,越来越不顺手的时候,我决定做一个决定:建自己的网站,让自己做主,这个决定迎合了我的喜好–爱折腾新玩意。

试水阶段

还是由于成本和观念的考虑,我开始尝试这种免费的东西,当我听说app engine这个概念的时候,不由身躯一震,总算让我找到了。首选自然是gae,大品牌值得信赖,我要弄的就是一个wordpress博客网站,但是,为什么你支持那么多技术,为什么就偏偏不支持php呢?

长叹息以掩涕息,哀吾生之多艰。

伤心之情无法言表。于是转战国内替代品,发现sina出了一个同样的产品sae(当然baidu,tencent据说也出了),好歹是国内大品牌,就你了。于是这个决定就诞生了一个zhujiangtao.sinaapp.com。很好用嘛,还免费的。好梦没多久,发现好不好用且不说,哪里是免费啊,谁能告诉我,云豆到底是什么东东!慌忙应付,先是实名认证,好歹保住了能用半年,但我的目标岂能是半年这么狭隘,我又着手申请开发者认证,可惜,无论我怎么尝试,还是失败了。

没什么,年轻人,经验最重要嘛,哎…

最后的战役

有三个原因促使我最终选择了建立这样一个网站

  • sae 不支持离线写博客,开发者身份一时申请不下来
  • 我惊奇的发现zhujiangtao.com竟然没有被注册,竟然只要49元,49元买到就是抢到啊。多一刻犹豫,就多一分被别人抢注的危险,我这么能容忍冠了我的大名网站被别人抢去,况且曾经有那么一刻,它以49元的价钱躺在我的眼前。果断下手!
  • 免费的午餐好不好吃不知道,反正好吃的不好吃到啊。我抢注了域名之后,开始寻找栖身的免费的vps,当然首选还是国内的,毕竟自家人,你来我往访问速度快。可惜没找到靠谱的,找到了一个主机屋貌似比较靠谱,一进去发现,人家刚刚开始不免费了。那就找国外的嘛,看来别人推荐的很多,有什么美国主机的、香港主机的、荷兰主机的、德国主机的,还是感觉不是不靠谱就是条件(限制条件、广告、访问速度)不意。后来找到了三蛋(000webhost),据说口碑不错,试着去注册了一个。可是一直处于认证过程,难道就是因为我的IP来自中国,你就可以这么剥夺我体验免费的资格吗?忍不住要质问,我天朝的那些nb技术人员早晚有一天黑了你的网站,到时出个更好的vps,专门不给你山姆人员用!

我还是很变通的,既然免费不行,那我付费还不行?当然不付给你们。我开始搜索价格公道、服务质量高的vps,最好是国产的。几经搜索,我终于发现了一个不错的vps。于是联系客服,谈谈优惠什么的服务什么的,价钱确实公道,于是就敲定了。设定好DSN、域名解析之后,我的网站上线啦

建站时间

这是振奋人心的一刻,这是里程碑式的成果,它翻开了一页崭新的篇章!

激动的情绪久久不能挥散去。

谨以此篇献给我这个小网站吧。

路漫漫其修远兮,吾将上下而求索

路还很长,也很宽……

屈原