| 津津's profile溪流漫话BlogLists | Help |
|
|
8/10/2009 激进一点点还是保守一些?最近觉得 RD 和 QA 是天敌……老是被鸡蛋里挑骨头,而且经常不得不承认,这的确是骨头。 有个比较郁闷的是,对一些需求上不怎么明确的、可算可不算的问题,总被拿另一个项目当参照物:XXX里是怎样的?XXX里做到了,所以也必须做到……有时候看上去更像是 QA 在提需求了。 说实话这让我感到很压抑。进而想到一个基本原则问题——碰到某些用的不太顺手的东西,该果断采用新技术呢,还是沿用原先的一套?后者的好处是,大多数不太好解决的问题,都可以规避掉,因为“原先的XXX也没做到”,而坏处是,要永远这么吃力下去;前者的好处是,可能可以解决掉大多数问题,但是一旦遇到一个不好解决的问题,压力就会很大——谁叫你当初推崇用这个的呢? 有说,“保守是混日子,激进是干大事,自觉得有能力就干大事,没能力就混吧”。是啊,我算什么呀,我何德何能去审视一些不该由我去关心的东西呢?可是呢,老这么混,自己也会觉得意思不大,而且拿XXX当挡箭牌的时候,自己也觉得自己很无耻,这是一个“朝气蓬勃”的人所该有的态度吗?或者……1、3、5保守,2、4、6激进? 突然强烈地感到出来混太早,毕业得太快,灰常灰常后悔最后一个学期没有好好享受清福了…… 8/5/2009 Visual Studio 2010 及 C++ 0x、C# 4.0(二)前面说到 C++ 0x 的 Lambda 表达式,前几天我总是感觉它缺了点什么,但说不出来。
现在觉得可能可以表达出来了。那就是,C++ 中没有明确的“委托”类型。
(为了表达这个概念,又不与 C++ 中已有概念混淆,这里请允许我使用 C# 中的名词。)
其实也不是没有,C++ 的函数指针其实就是形式上很精确的“委托”类型。虽然它归根结底却是一个模糊得不能再模糊的普通指针而已,但起码,一个这样的函数放在那里:
void sort(int arr[], int size, bool (*comparer)(int, int)); 给人的信息是非常明确且严格的。
但是如上篇所试验,不能像这样传入 Lambda 表达式:
sort(arr, N, [](int a, int b){ return a >= b; }); 而只能先定义一个小函数,然后使用:
bool greater_than(int a, int b) { return a >= b; }
sort(arr, N, greater_than); 但是 Lambda 的引入,不就是为了解决这种小函数的问题的吗?
另外,如果把函数改为
template <typename T> void sort(int elem[], int n, T comparer); 这样,虽然(可能)确实可以 sort(arr, N, [](int a, int b){ return a >= b; }); ,
但是实际使用的时候,我却不能知道 comparer 到底要符合什么样的形式。
而 C# 中,由于有明确的委托类型存在,这种问题也就不存在了:
delegate bool BinaryIntComparer(int a, int b); void sort(int[] arr, BinaryIntComparer comparer); 使用的时候:
sort(arr, (int a, int b) => a >= b); 所以,对于 C++ 0x 来说,作为语法糖的 Lambda,似乎还不够甜……
==============================华丽的分隔线==============================
今天随意看了一下 C# 4.0 的特性。所谓的协变性和逆变性一下子还看不明白。。。(果然 C# 是用来玩设计的)
动态特性倒是理解了一点点:
class Plane { public void Fly() { Console.WriteLine("Plane flies."); } }
class Car { public void Run() { Console.WriteLine("Car runs"); } }
class Bird { public void Fly() { Console.WriteLine("Bird flies."); } }
class Program { static void LetItFly(dynamic thing) { try { thing.Fly(); } catch { Console.WriteLine("Method \"Fly()\" does not exists."); } }
static void Main(string[] args) { LetItFly(new Plane()); LetItFly(new Car()); LetItFly(new Bird()); } } 结果:
Plane flies.
Method "Fly()" does not exists. Bird flies. 我们所折腾的就是被声明为 dynamic 类型的 thing。“thing.Fly();”中的句点后面可以随意写个方法名称,编译的时候不来检查,到运行的时候才检查。
如果没有 dynamic,参数就要被声明为 object,然后根据反射特性,去查询 Fly 方法有没有……
看起来 dynamic 只是把这一堆繁琐的过程省略了。
至于网上牛人们说的动态语言静态语言大融合这高度上的东东,我暂时是没有体会到,大概是我动态语言没怎么玩过的缘故吧。。。呃……JavaScript 也是动态语言?我怎么没感觉呢。。。
7/29/2009 Visual Studio 2010 及 C++ 0x(一)我记得之前下过 Visual Studio 2010 CTP 的,昨晚翻来翻去找不着了,只好重新下过。最新版本 beta1 了。
之前看到过 C++ 0x 的一些新特性,忍不住试一试。
首先是 lambda 表达式。网上有很多介绍 C++ 0x 特性的文章,其中关于 lambda 表达式的文章几乎是千篇一律的
std::for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); 比较感兴趣的是 lambda 表达式本身的类型,也就是,上述 for_each 中的第三个参数该怎么声明?
试验一:
bool greater_than(int a, int b, bool (*comparer)(int, int)) { return comparer(a, b); }
int _tmain(int argc, _TCHAR* argv[]) { bool b = greater_than(1, 2, [](int a, int b)->bool { return a > b; });
return 0; } 编译不过:
Error 1 error C2664: 'greater_than' : cannot convert parameter 3 from '`anonymous-namespace'::<lambda0>' to 'bool (__cdecl *)(int,int)'
可见 Lambda 表达式不能向下兼容到函数指针。
看了一下 std::for_each 的定义,它的第三个参数是一个 functor。所以,
试验二:
template <typename Comparer> bool greater_than(int a, int b, Comparer compare) { return compare(a, b); }
int _tmain(int argc, _TCHAR* argv[]) { bool b = greater_than(1, 2, [](int a, int b)->bool { return a > b; });
return 0; } 编译通过,运行也正确。
所以,似乎 Lambda 表达式的本质是 functor?
有点怀疑能否进行严格的类型检查在上例中,故意传给 greator_than 一个不实现 operator()(int, int) 的对象,即
试验三:
template <typename Comparer> bool greater_than(int a, int b, Comparer compare) { return compare(a, b); }
int _tmain(int argc, _TCHAR* argv[]) { bool b = greater_than(1, 2, [](int a)->bool { return true; });
return 0; } 这里这个 Lambda 表达式只接受一个参数,意味着 Comparer 只实现了 operator()(int),而没有实现 operator()(int, int)。
结果:
Error 2 error C2064: term does not evaluate to a function taking 2 arguments
突然醒悟了一下,觉得自己灰常灰常土了,C++ 的 functor 应该本来就是强类型的,支持编译期类型检查的吧?
怪不得那些库都抛开了函数指针,而使用 functor 了。
==============================华丽的分隔线==============================
强类型 enum 似乎 VS2010 里没有实现(据说 g++ 4.4 实现了)?怎么试怎么不行
enum Enum1 : double { a1, b1, c1 };
enum class Enum1 { a2, b2, c2 }; 都通不过……
[待续] 3/22/2009 发现其实周末挺忙的昨天白天把俞老师要的小站给草草做了下,顺便尝试下 ASP 上新的写法。其中最主要的是搞了一段 DBHelper:
Class DBHelper
Private ConnectionString Private Connection
Private Sub Class_Initialize() ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & Server.MapPath(DBPath) Connection = Server.CreateObject("ADODB.Connection") Connection.Open(ConnectionString) DbgPrint("DBOpen") End Sub
Private Sub Class_Terminate() Connection.Close() Connection = Nothing DbgPrint("DBClosed") End Sub
Public Sub ExecNonQuery(ByVal sql) DbgPrint("ExecNonQuery:" & sql) Connection.Execute(sql) End Sub
Public Function ExecQueryScale(ByVal sql) DbgPrint("ExecQueryScale:" & sql) ExecQueryScale = Connection.Execute(sql)(0) End Function
Public Function ExecQueryReader(ByVal sql) DbgPrint("ExecQueryReader:" & sql) ExecQueryReader = Server.CreateObject("ADODB.RecordSet") ExecQueryReader.Open(sql, Connection, 1, 3) End Function
End Class
Set DB = new DBHelper
之后操作起来就方便了些。。。VBScript 的 Class 虽然不强,但还凑合哈
郁闷的是,今天收到回复,还要查询、统计,还要界面漂亮。。。晕,过两天再说了,也许又是一周
前几天一直在看 SVN 版本库该如何组织。我自去年九月份就在自己机器上给装了个 SVN 服务端,自己用。一直都是一个项目一个版本库的,也没去多想。看到公司里都 trunk、tag、branch,很是奇怪,去查了下才知道。另外,我一直不知道许多项目改放一个版本库里呢,还是分开放。分开放就是不能互相引用了,为了这个看了两三天网上评论。最后决定还是用同一个版本库了,那以前的全部重新组织,到昨天晚上十多点才搞好,除了移文件、删 .svn 目录外,做了 60 次 commit 动作……最后的结果:
然后开始构思着,是不是自己搞个小型库出来。以前写过 Vector、String,这两个就很常用了,可以避开 STL 以及 CString。但是仅仅有这个还不够,上次写 xlWarKey 的时候,在 CList 中存指针,为了不每次 detele,简单地包装了一下,这回要写个通用的。于是去查怎么实现 -> 的操作不变性,发现原来 -> 是可以重载的,原来这个就叫“智能指针”……除了这些,又有新的想法了,是不是也得搞个 List,是不是给 Vector 和 List 抽象出 IEnumerable,那么还得搞个类似迭代器的 IEnumerator 了。对,是不是可以实现同一的 foreach?!又去查了下,原来有好事者早就做过这事儿了。到最后,几乎啥也没干,智能指针实现了,foreach 的可行性试过了。觉得这么想下来,这个库可就庞大起来了,那该如何组织呢……回过头来想想,当初的 String 写得也很弱,想要搞得好用一点要写好多,而这些,STL 里不是都有么,干嘛要重复劳动呢?于是找出 C++ Primer 电子书,找 STL 内容看,终于知道除了 vector、list、deque、queue、stack 等外还有 map 和 set。怪不得当初百度GG问我一篇文章里查单词出现次数我说hash但不知道怎么设计这个hash算法后有点小惊讶。他大概在想,这个人连 map 都不知道。。。不过我还是认为,C++ 是 C++,STL 只不过是一个库而已,仅仅是一个库……
下午突然想到了很久以前有个电视剧里的什么歌有一句蛮好听的,于是去查七侠五义、三侠五义,最后发现是《救姻缘》,那个我觉得蛮好听的一句是“生生世世,姻缘不断”。
昨晚发现了一大堆适合我这种民工吃饭的地方,想不到滨江饭店都开得这么偏僻……
周五拍的办公室照片(趁这几天两台电脑在哈,坐在那里好有感觉呀):
又没时间做毕设的事了,充实呀充实
话说今晚出去吃饭的时候,路边一个四五岁的小MM无端地叫我大笨蛋,!
3/16/2009 Linux 处女程前两天在 CSDN 上混分混上了瘾,今晚继续混。瞄到一个 Linux 下遍历文件的问题,只是楼主的问题提得有点逗:
“现有的思路: readdir()获取所有文件、然后按照指定格式(后缀名)进行解析、stat(文件名)获取文件信息。
现在的问题: readdir函数在头文件 <dirent.h>中,但是VC6.0里找不到该头文件。” 到底是 Linux 还是 Windows 呢?不管这么多,这两天由 50 多分跳到 350 多分的事实证明,最好的得分方式就是给出源代码。所以无论如何,一定要“帮”到楼主。(阿。。。我是不是有点邪恶阿~~&^&*##)
于是我重启来到狗系统下。请广大 Linux 粉丝允许我这么昵称之,我并没有恶意。只是我现在还不懂这个系统,在里面干什么事都不顺,于是称之狗系统以解心头之郁闷。等那天哥哥我也熟悉了,我就不这么叫了~~~bow~^_^
开个命令行,vi temp.c
然后一边又去查 Linux 系统提供的 C 函数,结合楼主的提示,找到了 opendir()、readdir() 这些函数的说明,然后写呀写:
#include <sys/types.h> #include <dirent.h> #include <stdio.h>
void showhelp() { printf("Usage: ./listfile <ext>\n"); printf("\n"); }
int is_same_ext(char *fname, char *ext) { char *p; for (p = fname; *p != '\0'; p++ ); for (p--; *p != '.' && p != fname; p--);
if (p == fname) { return 0; }
p++;
while (*ext++ == *p++) { if (*ext == '\0' && *p == '\0') { return 1; } }
return 0; }
int main(int argc, char *argv[]) { if (argc != 2) { showhelp(); return 0; }
DIR *dir = opendir("./"); struct dirent *p = NULL; int found = 0;
while ((p = readdir(dir)) != NULL) { if (is_same_ext(p->d_name, argv[1])) { found = 1; printf("%s\n", p->d_name); } }
if (!found) { printf("no such file(s) found.\n"); }
printf("\n");
return 0; }
哈哈哈。小小纪念一下 ,虽然很没水平。 上周某一天下午我从 18 楼走到 1 楼,想找个早上早点起来从 1 楼走到 18 楼。
这几天混得还算行吧,只是毕设老师催得紧了,我就是懒得看那个破破的会议系统,55555555
话说下午吃饭的时候,正当我准备埋头攻掉最后三口的时候,听到一句“没人吧?”抬头看到一个小姐姐做到了我对面。长得不能用学校里的标准来说,但很有气质。。。可我只剩下两口饭了呀。。。再怎么慢也很快吃完了……
明天去学校但愿别被敲,一定不能被敲!!一定要坚持到第二个月的工资发下来以后……
3/10/2009 出个单曲哈又一个月没出了,趁室友加班没回来搞一动,把落下的作业补了
今天本来快要写好 demo 程序了的,可惜突然出现了好些我没有接触到的复杂情况,调了老半天,明天继续调去。
周末任务:
毕设文献综述开题报告
愈老师要的小站
xlWarKey 2.1
切记,切记!
3/9/2009 换灯泡了,总算告别了烦人的嗡嗡声这房间里的日光灯嗡嗡嗡的响了一个星期了,一直在忍受。刚才要听些有点音质的歌,它还在嗡嗡叫,忍无可忍啊。据说日光灯叫是因为镇流器不好。想把那镇流器拆下来看看,无奈手头没有钳子转不动那螺丝。又据说,想要自己“修”好镇流器是不大会成功的,只有换。查了下镇流器的价格,不便宜阿,再加上拆不下来就换不上。于是用备选方案——装节能灯。30W 的 3U 的节能灯,亮得一塌糊涂!这下舒心多了。顺便带回一坨细铁丝,找时间把阳台晒衣服的架子给绑好。
昨天发现梦之旅终于出新唱片了。作为梦迷,当然得收藏了。有点失望的是,这两张的歌都是些革命歌曲,而且是我不大熟悉的革命歌曲。不过听听就熟了。翻翻自己所存的,流淌的歌声之真情依旧 20CD,粤语歌曲集 2CD,以及现在的流淌的歌声续集 2CD。不过从百度贴吧上的一些帖子来看,我怀疑我漏掉了一两张,得尽快去想办法确认一下。
再看了些梦之旅的新闻和照片,好像近年来还是没什么活动,只有常安在去年开了次独唱音乐会,也是只有图片没有视频。从照片上看,常安姐姐显老了,完全中年妇女的打扮了。前几年的一次歌迷见面会的照片,以及那些她个人的 CD 封面,还都是青春靓丽型打扮的。想想她也该有三十四五左右了吧,岁月不饶人啊。我一直只喜欢她在梦之旅里面的歌,不很关注她的个人专辑,看来得好好回头欣赏欣赏了,再过几年就更不会有新的了。
刚刚又发现原来常安在去年还唱过赈灾歌曲《让爱满天下》,到现在我才知道,真是太落伍了。怪不得我说我是凉粉人家说我是伪歌迷,还好知道梦之旅的不多,不然我说我是梦迷还是会被戴上伪歌迷的帽子……话说,这还是第一次看常安在视频中的镜头,也算是耳闻目睹了这真人真嗓音了。现在到处都是在线视频,不知道哪里去找高清的 MPG 或 AVI 版了。
词:郭轩宇 曲:王厚明
你伸出温暖的手 我说着贴心的话
齐心协力肩并肩 共建和谐幸福家 让爱传天下 困难都不怕 温暖每一个心灵 平安你我他 天上有难一起挡 地上有坎共同跨
携手走过艰难岁月 用心温暖咱的家 再苦无所畏 再难也不怕 到处都是好兄弟 五洲四海都是家 让爱满天下 让真情留下
真情真爱暖万家 大爱无疆牵手走天涯 让爱满天下 让温暖飘洒 让你我留住彼此的牵挂 你离开温馨的家 我捧出关爱的心
万众一心度难关 建设强盛大中华 让爱传天下 困难都不怕 温暖每一个心灵 平安你我他 天上有难一起挡 地上有坎共同跨
携手走过艰难岁月 用心温暖咱的家 再苦无所畏 再难也不怕 到处都是好兄弟 五洲四海都是家 让爱满天下 让真情留下
真情真爱暖万家 大爱无疆牵手走天涯 让爱满天下 让温暖飘洒 让你我留住彼此的牵挂 3/8/2009 本周小结第一周过去得还真快,明天又要去上班了。
我感觉基本上没太做什么事,基本上就查查资料,这个要怎么做,那个要怎么做,再整理一下。好像就跟自己有时候遇到一个问题、钻研一个什么东西的时候差不多。区别是,那时候叫不务正业,周围有着跟我一样不务正业玩游戏的人,和在自习教室务正业的人,而现在则是本职工作。其实几天的时间学到的还是蛮多的。但这样学虽然学得细,印象也深,但是效率却不高,有时候会浪费好多时间。但我有点期待各方面入门性质的培训。上周虽然也有个小培训会,但是这已经是在我了解了几乎所有我暂时需要的知识之后了,会上所讲的内容都是我一两天前已经看过了的。当然,听人讲和自己看还是不一样的,听别人讲,有人在引导,让我知道孰轻孰重。会后收到会上所用例子代码等等,想礼节性地回个“谢谢你的精彩演讲”之类的,可是这个好像也不是演讲,不知道怎么叫,这措辞有点太造作了,于是就没回了,又好像不太礼貌……不管了,我是新人,请原谅我吧。可能是因为现在我是实习吧,希望以后能有这样子的培训。另外一方面,我都不知道怎么问别人问题,甚至该不该问。常识性问题,网上查查就可以了;非常识性问题的话,特别是诡异的问题,问别人,别人就要和我一起进入诡异的世界,要是那个问题他也没遇到过,就会耽误他的很多时间。而本来仅仅耽误我一个人的时间就够了的。处事难啊处事难……
周末叫个把同学来我的“新居”玩,顺便交流下工作“经验”。他们都说要珍惜现在没事干的时候,再过段时间要是真的来事情了就没这么惬意了。也许是吧。反正主管不压地紧,我可以放松点心情,看问题的时候可以看得更细一点,该整理的整理得详细一点。可能实习的意义就是给这么个环境让我去适应,等有事情来的时候,可以从容点应付吧。
一个人的时候,顺手翻翻业界新闻,欣赏那些油菜的评论,再胡乱写些文字,这就是后大学生活?
3/7/2009 Writing a Windows Service programYesterday I searched the Internet for articles about how to write a Windows Service program. It is a pity that few of them explains main points clearly. Many of those articles give steps under .Net Framework, using C# or Managed C++. Some just show a class that helps in Windows Service programing. Only a few of them talk under Win32 SDK, that is what I want, yet they do not point out where should I put my task code. Finally, I find a sample code in http://hi.baidu.com/borland82/blog/item/b538341b1ea2f4fdae5133f7.html, and successfully wrote a simple Service. (BTW, this author's article is not clear, too). And today, I find articles in MSDN tell whatever we need in Windows Service programming, according to which I rewrote a sample. For other beginners and myself, I am recording something about this. Please excuse me that I wrote in English. In fact I hate English. But for some further reasons I want some attempts.
A Service program of Windows is not that special as I imagined before. It could be a simple Win32 console Application. In my case here, I do it in a Win32 console Application. Open Visual Studio and create a Win32 Console Application in C++. This is my main() function:
int _tmain(int argc, _TCHAR* argv[])
{ // To support self-install and self-uninstall if (argc == 2) { _wcslwr(argv[1]); if (lstrcmp(argv[1], _T("/install")) == 0)
{ InstallService(); return 0;
} else if (lstrcmp(argv[1], _T("/uninstall")) == 0) { UninstallService(); return 0;
} } PrepareService(); return 0;
} Here I use command line arguments to support self-install and self-uninstall. Ignore them at this stage, look at PrepareService(). When we start a service in Microsoft Management Control (MMC), the system runs our executable file, just like executing an application manually. Our program will go to PrepareService() function. Turn to the function:
void PrepareService()
{ SERVICE_TABLE_ENTRY ste[2]; ste[0].lpServiceName = g_lpszServiceName; ste[0].lpServiceProc = ServiceMain; ste[1].lpServiceName = NULL;
ste[1].lpServiceProc = NULL; StartServiceCtrlDispatcher(ste); }
In this function we did nothing but calling StartServiceCtrlDispatcher(). It is an important function. I strongly recommend you to look up the function in MSDN. Follow what there said you will be able to write a Service. But now, please follow me.
The function StartServiceCtrlDispatcher() need an array of SERVICE_TABLE_ENTRY to work. Each item in the array contain enough information to start a service, and the array should be end with a null item. We are to start only one service, so here we need an array of two elements, the last of which is set to null. There are two members in SERVICE_TABLE_ENTRY struct. The first one, lpServiceName describes the name of out service. (It will be ignored by the system Service Control Manager (SCM) if we set so-called "service type" to a speacial value. Just go ahead first.) Here I set it to g_lpszServiceName, which is a global variable defined as:
TCHAR g_lpszServiceName[] = _T("MyService");
We will use it several times. The other member ServiceProc should be point to a callback function, which is usually name ServiceMain(). After calling of StartServiceCtrlDispatcher(), the SCM will call ServiceMain() in a new thread, thus our service process continues.
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
{ g_hServiceStatus = RegisterServiceCtrlHandlerEx(g_lpszServiceName, HandlerProc, NULL); // Here you could do some initializing work g_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_Status.dwCurrentState = SERVICE_RUNNING; g_Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;// | SERVICE_ACCEPT_PAUSE;
g_Status.dwWin32ExitCode = NO_ERROR; g_Status.dwServiceSpecificExitCode = NO_ERROR; g_Status.dwCheckPoint = 0; g_Status.dwWaitHint = 0; if (!SetServiceStatus(g_hServiceStatus, &g_Status)) { // Failed to set status to RUNNING return; } OnStart(); } We should immediately call RegisterServiceCtrlHandlerEx() in ServiceMain(). Another callback function HandleProc will be register to SCM, to respond when the service is paused, or stopped, etc. The funtion RegisterServiceCtrlHandlerEx() returns a SERVICE_STATUS_HANDLE. It will be used in HanderProc(), so here I make it global.
After that we are to tell the SCM that our service is started(running) by calling SetServiceStatus(). Before calling, you could do some initializing work. If initializing work fails, we instead told SCM that our service is still stopped. The SetServiceStatus() needs a SERVICE_STATUS struct. Pay attention to its first three members. I set the ServiceType to SERVICE_WIN32_OWN_PROCESS here, it means the service runs in its own process. Additionally, the SCM will ignore our service name. CurrentState tells the SCM the status of our service. Normally we set it SERVICE_RUNNING. The ControlsAccepted determines how the user could control the service. SERVICE_ACCEPT_STOP means user can stop the service, and SERVICE_ACCEPT_PAUSE means user can pause the service. Here I enabled SERVICE_ACCEPT_STOP but disabled SERVICE_ACCEPT_PAUSE. The rest members of SERVICE_STATUS is not so important. Besides, If your initializing work will last for more then one second, you should set the WaitHin member to a well-estimated value.
Finally, our service is started, after calling SetServiceStatus() with SERVICE_RUNNING. If we have nothing to do at the moment, ServiceMain() will return and the thread ServiceMain in will terminate automatically. That means the service stops immediately after being started. Obviously, we write a Service not only to start and stop it. We need to do some work. So, where should we put our task code? It is an important thing we need to know. The answer is, HERE! Please take notice of what I said before, in PrepareService(). The ServiceMain is already in a new thread. We do not need to create another thread. To make the code more clear, I put task code in a separate function OnStart(). In the function we do our task and keep the thread running. Only when we need to stop our service, we could and should try to terminate this thread safely, that means let OnStart() and ServiceMain() return.
Here is the function OnStart():
void OnStart()
{ g_bRunning = TRUE; while (g_bRunning)
{ // Put task code here // I have really nothing to do at the moment, leaving it blank. } }
I simply used a global variable to control the service thread. When the service need to be stopped, just turn it to FALSE and the thread will terminate.
Last function we should put attention to is HandleProc():
DWORD WINAPI HandlerProc(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
{ switch (dwControl) { case SERVICE_CONTROL_PAUSE: OnPause(); g_Status.dwCurrentState = SERVICE_PAUSED; SetServiceStatus(g_hServiceStatus, &g_Status); break; case SERVICE_CONTROL_CONTINUE: OnContinue(); g_Status.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(g_hServiceStatus, &g_Status); break; case SERVICE_CONTROL_STOP: OnStop(); g_Status.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(g_hServiceStatus, &g_Status); break; default: break; } return NO_ERROR;
} The SCM calls this function when the service is paused/continued/stopped/... by the user. We should call SetServiceStatus() to notify the SCM that the status id changed successfully. Before that, we may need to do something to control our own task. I put them in separate functions too. For an example, I only respond to SERVICE_CONTROL_PAUSE, SERVICE_CONTROL_CONTINUE and SERVICE_CONTROL_STOP. You can add or delete cases when needed. This service does not support pause/continue (reference to ServiceMain()), so here will never receives SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE indeed.
The rest three "smart" function is:
void OnPause()
{ // Not supported } void OnContinue()
{ // Not supported } void OnStop()
{ // Set the variable to FALSE to terminate the service thread. g_bRunning = FALSE; } I have not told what we did in InstallService() and UninstallService(). First I believed I could directly write to the system register in HKLM\SYSTEM\CurrentControlSet\Services, but failed. In fact Windows provides APIs for installing services. Reference to MSDN articles "Installing a Service" and "Deleting a Service". There give sample codes. I just copied codes from there.
It is time to go and test out service. Use "/install" to install our service, run services.msc, find our service in the list, and, start it.
Sample Codes:
2009-03-07 23:08 3/5/2009 第四天昨天晚上 QQ 上碰到一个好久未联系的初中同学(
这时候大概10点多了,想想日记还没写,白天也没做好什么事情,啥事也没有干,真是有种说不出来的“落魄”感。就随便这看看那看看。后来突然间知道了下午的一个问题了,搞起来,成功了。把关键过程记下来,发到公司给开的邮箱明天用。总算有了点小成就感。
现在开始说今天的事。今天一早我就依照自己的记录,重复昨晚的事,谁知遇到了一个挺麻烦的问题。就这样搞了一上午没搞明白。实在没办法了,问lora要了前面的版本看看,运行一下,仍然是有问题,可是在lora的电脑里是没问题的。。。难道是我系统的原因?这两天瞎折腾把系统折腾坏了?。。。不过我可以确定昨晚的那些是没有问题的,只不过荒废了一个上午。后来去richie机器上测,果然是可以的。那么我现在就还剩下一个相对小的问题了——可是好像查了两个多小时查不到相关资料,明天再说了。
回来的时候突然不想去动漫吃饭了,又贵又难吃,买了7个天天早上吃的贼好吃的小包子,边走边吃掉。听说加班可以有晚饭票,晚饭票可以吃15米,15米吃起来就不特别难吃了,我对传说中的万恶的加班有憧憬了……反正回来也没事干,只不过比白天多聊几句Q,多看几下无关网站而已了。不过抱着纯蹭饭的目的去加班不好吧,加上最近什么也没干……先预谋着吧,呵呵
hr好像又给我布置任务了。但我总觉得在hr面前炫面经是件危险的事,尽管自己其实没干什么亏心事。还是危险,危险……或许我什么时候可以出个删节版来(抹去最后一段)。
3/3/2009 上班第二天今天跟昨天比起来,就没那么大的不确定感了。一早开始坐在座位上,直到下午,除了吃饭上厕所。也没干其它事情,就找资料,看。下午最后的一个多小时把《COM技术内幕》粗看了80页,小有成就感的,带回来继续看。也不知道该掌握到何种程度,给我的任务上今天比昨天有点小进展,lora简单地说了一句“进展还挺快的”,但也没说接下来如何。明天,应该还是继续吧……
对了,一件有意思的事,碰到了当初面试我的一面面试官,他居然还能叫出我名字来,太感动了呀~~~回想当初这个公司的面试应该说最怡然的一个了。。我好像好久以前就计划要写面经了的,到现在为止还没开始……
好了,COM,COM,我要用 SDK 写成功个 COM 出来……
3/2/2009 上班第一天昨天这个时候,我还在诚惶诚恐,还在忙不迭地告诉这个告诉那个我要上班了以及,我很惶恐。
早上9点不算太早,8点半出发,买5个包子,到公司楼下使劲地吃完刚好9点差3分。由于是第一次去上班,在前台等。alice mm 又像前两次去的时候一样把我带到了会议室并倒了一杯水。今天我发现 alice mm 其实也是姐姐,但是前两次看上去好像年纪特别小。接下来vivi姐姐,不,还是叫mm吧,vivi mm用那甜甜的声音介绍了一些情况,再让我签了一份保密协议。期间vivi说我晚上回去可以写一篇日记,记记今天第一天上班,“我很希望看到你的这篇日记”。虽然她不是我的直接上司,但hr吩咐的还是要做的,所以我现在也是在工作,我在加班哈~ 当然,我是不会故意把这篇文章地址发给她的,看不看得到那是要看缘分的。
然后我被领到了我的位置。坐在我后面的lora mm就是我的主管,呃,,还是叫lora姐姐吧,否则有点不敬了。其实心里还忐忑的,主管坐在身后听说好像是比较可怕的事情。桌上放着新的液晶显示器,鼠标,键盘,从jeff gg那里搬来主机开始搭,干这活儿就像自己买了台电脑那样舒服。搞得差不多了就没事干了,等主管安排,有事没事的拿起鼠标随便点点,心里又不安起来了。
终于,lora姐姐忙完了,把我叫到会议室开始讲课……开始讲。也是些介绍性的,vivi讲的那些是hr相关的,lora讲的是部门里头行政上的、产品上的等等,然后说了说对我的大致安排。我虔诚地听着。这堂课上得蛮久的,上完后就快12点了,于是lora说带我去吃饭,我就说好。
到楼下,刚巧办饭卡的同志不在,lora说先用我的吧。我没敢说好,只是跟着她,心里想这样好吗?这样不好吧?这样还好吧?不过没卡吃不了饭,所以就从了,我挑便宜的点,并且被发现了,真不好意思。
整个下午就装装软件,查查资料。期间lora带我跟本部门每一个同事介绍了一下,我都很腼腆地笑笑。临近下班了,就把下午所查的那一部分简单总结了一下向lora汇报,她来看了下,最后说“知道了”。我不知道该如何汇报工作,第一天反正也不能做太多事,想想这样应该马马虎虎还算中规中矩吧。就是还是有点怕怕,不敢稍微大声点说话,虽然我本来声音也不大。然后应该是下班走人的时候,我看lora还没走,也不知道怎么说,于是也就呆着,直到她问我怎么还不走,我站起来才发现周围好多都神不知鬼不觉地走掉了。
接下来就回来了。室友说主管一般比你下班晚的。我想起刚才lora好像在电话里说她要加班。看来主管也不是太轻松就能当的。
发现考研成绩出来了,在此晒晒分数:
这下我脸丢大了。
中午吃饭的时候lora跟我问起考研,我说考了。她觉得很奇怪,接着说考上了去不去。我知道这个问题很敏感的,但也不好随便说,就说是考不上的,然后就算考上可能也不会去读,毕竟三年之后形势也可能不会太好。她跟以前vivi说的一样,也说去读研也是不错的选择,公司鼓励之类的话。这种表态我一直挺欣赏、也挺感动的。不过我是确实不准备读研了的,说的话也是真心话,反正问心无愧就好。只是我不想把话说死,万一奇迹发生我考上了呢,万一因为莫名其妙的原因我又去读了呢?现在,终于没有这种不确定性了。
剩下的不确定性就是,,,我被因故开除^_^
所以不码字了,想想明天该干点啥了
|
|
|