0

“木乃伊”加入《特种部队》(更新:目前的完整演员阵容)



既然由《》(The Mummy)导演史蒂芬·索莫斯(Stephen Sommers)执导,那么在《特种部队》(G.I. Joe)中出现他的“老部下”也就情有可原了。据IESB报道,曾在《1、2》中扮演“木乃伊Imhotep”的男演员阿诺德·沃斯鲁(Arnold Vosloo)将在《特种部队》中扮演反派“扎坦”(Zartan)。

这个角色在动画版《特种部队》里是几个主要坏蛋之一,是一个为Destro和眼镜蛇部队工作的雇佣兵。他善于伪装成别人的外貌和声音,精通20种语言和方言,是一个腹语和武术专家,擅长的兵器是弓箭。他还是飞车党“Dreadnoks”的首领,患有多重人格和妄想型精神分裂症。

《特种部队》(G.I. Joe)是派拉蒙继《变形金刚》后又一部根据孩之宝玩具改编的大制作电影。“G.I. Joe”是美国特训特种敢死队的代号,该队组建的目的是维护人类的自由与安全。他们的对手是妄图统治世界的残忍的眼镜蛇部队。影片计划下个月中旬在洛杉矶开拍,并于2009年8月7日上映。

更新:丹尼斯·奎德(Dennis Quaid)也加入了《特种部队》,他将扮演霍克将军(General Hawk)。

至此,加盟此片的演员已经有“男爵夫人”西耶娜·米勒(Sienna Miller)、“Ripcord”马龙·韦恩斯(Marlon Wayans)、“Rex”约瑟夫·高登·拉维特(Joseph Gordon-Levitt)、“公爵”钱宁·塔图姆(Channing Tatum)、“蛇眼”雷·帕克(Ray Park)、“红发女郎”雷切尔·妮科尔斯(Rachel Nichols)、“忍者白幽灵”李秉宪(Byung-hun Lee)、“Breaker”萨伊德·塔马乌伊(Said Taghmaoui)以及“Heavy Duty”阿德沃尔·阿吉纽依-艾格拜吉(Adewale Akinnuoye-Agbaje)。

作者:Nemo
来源:http://mymovie.blogbus.com/logs/14657580.html

这是我小时就很喜欢看的一部动画片,哈,终于有电影可看了,Ye!

01

Google 坚信的 10 大信条


1. Focus on the user and all else will follow. 关注使用者,则一切将水到渠成.
(H:对我来说这就是客户关系的经营,设身处地的为客户着想,而不是把这些行为都当成新案子的酬庸;至于新案子?对我而言这绝对是第二个考虑… 我想只要用心,客户是可以感受到并给予回馈.)2. It’s best to do one thing really, really well. 尽力将一件事做到最好.
(H:手上正在进行的工作,别只是把他做完就好,也不要有太多的权宜、妥协!尽可能真的把他的「做好」,因为老想着之后再回过头来怎样又怎样,经验告诉我,通常回过头来怎样又怎样的机会是非常低的,然而这个不完美的作品却已经被客户在心中悄悄的打了分数.)
3. Fast is better than slow. 快比慢好.
(H:这不是指把事情做的快的意思,比如说:你写的程序跑起来效率要高、有新的点子想到就要快点实作、…. 太多了,说不完.)
4. Democracy on the works. 网络的民主效应.
(H: Web 2.0!!! Wikipedia, ….. )
5. You don’t need to be at your desk to need an answer. 您不一定要在桌子前找答案.
(手机通讯,行动通讯,3G….)
6. You can make money without doing evil. 不做坏事也能赚钱.
7. There’s always more information out there. 「信息」也无涯.
8. The need for information crosses all borders. 对信息的需求没有国界.
9. You can be serious without a suit. 不穿西装也可以很正经.
(H: 早上你可以晚点进公司,上班时间你可以开心的大声说笑,傍晚你也可以早点下班回家,这些我都不在乎;但是你不能上班时间不工作而回家报边加班边工作,是因为公司风水比较差吗?你必需要对自己开出来的Schedule负责,当你面对自己开的Schedule是一再的Delay,那我会势必质疑你的能力!也许我什么都没说,但请相信我,很多事情是看在眼里,放在心底的.我的重点是–你要对你自己的决定/行为负责,形式上的一些规定对我来讲并不是重点.)
10. Great just isn’t good enough. 精益求精.
(H:没啥好说说的,尽可能做到下面这句话吧 — Be the only one, not number one.)

0

中国惠普前总裁孙振耀谈人生


孙总的原文拷贝:http://blog.ccwebkey.com/articles/2007/12/10/hp%E5%A4%A7%E4%B8%AD%E5%8D%8E%E5%8C%BA%E6%80%BB%E8%A3%81%E5%AD%99%E6%8C%AF%E8%80%80%E6%92%B0%E6%96%87%E8%B0%88%E9%80%80%E4%BC%91%E5%B9%B6%E7%95%85%E8%B0%88%E4%BA%BA%E7%94%9F

一、关于工作与生活
我有个有趣的观察,外企公司多的是25-35岁的白领,40岁以上的员工很少,二三十岁的外企员工是意气风发的,但外企公司40岁附近的经理人是很尴尬的。我见过的40岁附近的外企经理人大多在一直跳槽,最后大多跳到民企,比方说,唐骏。外企员工的成功很大程度上是公司的成功,并非个人的成功,西门子的确比国美大,但并不代表西门子中国经理比国美的老板强,甚至可以说差得很远。而进外企的人往往并不能很早理解这一点,把自己的成功90%归功于自己的能力,实际上,外企公司随便换个中国区总经理并不会给业绩带来什么了不起的影响。好了问题来了,当这些经理人40多岁了,他们的薪资要求变得很高,而他们的才能其实又不是那么出众,作为外企公司的老板,你会怎么选择?有的是只要不高薪水的,要出位的精明强干精力冲沛的年轻人,有的是,为什么还要用你?
从上面这个例子,其实可以看到我们的工作轨迹,二三十岁的时候,生活的压力还比较小,身体还比较好,上面的父母身体还好,下面又没有孩子,不用还房贷,也没有孩子要上大学,当个外企小白领还是很光鲜的,挣得不多也够花了。但是人终归要结婚生子,终归会老,到了40岁,父母老了,要看病要吃药,要有人看护,自己要还房贷,要过基本体面的生活,要养小孩……那个时候需要挣多少钱才够花才重要。所以,看待工作,眼光要放远一点,一时的谁高谁低并不能说明什么。
从这个角度上来说,我不太赞成过于关注第一份工作的薪水,更没有必要攀比第一份工作的薪水,这在刚刚出校园的学生中间是很常见的。正常人大概要工作35年,这好比是一场马拉松比赛,和真正的马拉松比赛不同的是,这次比赛没有职业选手,每个人都只有一次机会。要知到,有很多人甚至坚持不到终点,大多数人最后是走到终点的,只有少数人是跑过终点的,因此在刚开始的时候,去抢领先的位置并没有太大的意义。刚进社会的时候如果进500强公司,大概能拿到3k-6k/ 月的工资,有些特别技术的人才可能可以到8k/月,可问题是,5年以后拿多少?估计5k-10k了不起了。起点虽然高,但增幅有限,而且,后面的年轻人追赶的压力越来越大。
我前两天问我的一个销售,你会的这些东西一个新人2年就都学会了,但新人所要求的薪水却只是你的一半,到时候,你怎么办?
职业生涯就像一场体育比赛,有初赛、复赛、决赛。初赛的时候大家都刚刚进社会,大多数都是实力一般的人,这时候努力一点认真一点很快就能让人脱颖而出,于是有的人二十多岁做了经理,有的人迟些也终于赢得了初赛,三十多岁成了经理。然后是复赛,能参加复赛的都是赢得初赛的,每个人都有些能耐,在聪明才智上都不成问题,这个时候再想要胜出就不那么容易了,单靠一点点努力和认真还不够,要有很强的坚忍精神,要懂得靠团队的力量,要懂得收服人心,要有长远的眼光……
看上去赢得复赛并不容易,但,还不是那么难。因为这个世界的规律就是给人一点成功的同时让人骄傲自满,刚刚赢得初赛的人往往不知道自己赢得的仅仅是初赛,有了一点小小的成绩大多数人都会骄傲自满起来,认为自己已经懂得了全部,不需要再努力再学习了,他们会认为之所以不能再进一步已经不是自己的原因了。虽然他们仍然不好对付,但是他们没有耐性,没有容人的度量,更没有清晰长远的目光。就像一只愤怒的斗牛,虽然猛烈,最终是会败的,而赢得复赛的人则象斗牛士一样,不急不躁,跟随着自己的节拍,慢慢耗尽对手的耐心和体力。赢得了复赛以后,大约已经是一位很了不起的职业经理人了,当上了中小公司的总经理,大公司的副总经理,主管着每年几千万乃至几亿的生意。
最终的决赛来了,说实话我自己都还没有赢得决赛,因此对于决赛的决胜因素也只能凭自己的猜测而已,这个时候的输赢或许就像武侠小说里写得那样,大家都是高手,只能等待对方犯错了,要想轻易击败对手是不可能的,除了使上浑身解数,还需要一点运气和时间。世界的规律依然发挥着作用,赢得复赛的人已经不只是骄傲自满了,他们往往刚愎自用,听不进去别人的话,有些人的脾气变得暴躁,心情变得浮躁,身体变得糟糕,他们最大的敌人就是他们自己,在决赛中要做的只是不被自己击败,等着别人被自己击败。这和体育比赛是一样的,最后高手之间的比赛,就看谁失误少谁就赢得了决赛。
二、根源
你工作快乐么?你的工作好么?
有没有觉得干了一段时间以后工作很不开心?有没有觉得自己入错了行?有没有觉得自己没有得到应有的待遇?有没有觉得工作像一团乱麻每天上班都是一种痛苦?有没有很想换个工作?有没有觉得其实现在的公司并没有当初想象得那么好?有没有觉得这份工作是当初因为生存压力而找的,实在不适合自己?你从工作中得到你想要得到的了么?你每天开心么?
天涯上愤怒的人很多,你有没有想过,你为什么不快乐?你为什么愤怒?
其实,你不快乐的根源,是因为你不知道要什么!你不知道要什么,所以你不知道去追求什么,你不知道追求什么,所以你什么也得不到。
我总觉得,职业生涯首先要关注的是自己,自己想要什么?大多数人大概没想过这个问题,唯一的想法只是——我想要一份工作,我想要一份不错的薪水,我知道所有人对于薪水的渴望,可是,你想每隔几年重来一次找工作的过程么?你想每年都在这种对于工作和薪水的焦急不安中度过么?不想的话,就好好想清楚。饮鸩止渴,不能因为口渴就拼命喝毒药。越是焦急,越是觉得自己需要一份工作,越饥不择食,越想不清楚,越容易失败,你的经历越来越差,下一份工作的人看着你的简历就皱眉头。于是你越喝越渴,越渴越喝,陷入恶性循环。最终只能哀叹世事不公或者生不逢时,只能到天涯上来发泄一把,在失败者的共鸣当中寻求一点心理平衡罢了。大多数人都有生存压力,我也是,有生存压力就会有很多焦虑,积极的人会从焦虑中得到动力,而消极的人则会因为焦虑而迷失方向。所有人都必须在压力下做出选择,这就是世道,你喜欢也罢不喜欢也罢。
一般我们处理的事情分为重要的事情和紧急的事情,如果不做重要的事情就会常常去做紧急的事情。比如锻炼身体保持健康是重要的事情,而看病则是紧急的事情。如果不锻炼身体保持健康,就会常常为了病痛烦恼。又比如防火是重要的事情,而救火是紧急的事情,如果不注意防火,就要常常救火。找工作也是如此,想好自己究竟要什么是重要的事情,找工作是紧急的事情,如果不想好,就会常常要找工作。往往紧急的事情给人的压力比较大,迫使人们去赶紧做,相对来说重要的事情反而没有那么大的压力,大多数人做事情都是以压力为导向的,压力之下,总觉得非要先做紧急的事情,结果就是永远到处救火,永远没有停歇的时候。(很多人的工作也像是救火队一样忙碌痛苦,也是因为工作中没有做好重要的事情。)那些说自己活在水深火热为了生存顾不上那么多的朋友,今天找工作困难是当初你们没有做重要的事情,是结果不是原因。如果今天你们还是因为急于要找一份工作而不去思考,那么或许将来要继续承受痛苦找工作的结果。
我始终觉得我要说的话题,沉重了点,需要很多思考,远比唐笑打武警的话题来的枯燥乏味,但是,天下没有轻松的成功,成功,要付代价。请先忘记一切的生存压力,想想这辈子你最想要的是什么?所以,最要紧的事情,先想好自己想要什么。
什么是好工作
当初微软有个唐骏,很多大学里的年轻人觉得这才是他们向往的职业生涯,我在清华bbs里发的帖子被这些学子们所不屑,那个时候学生们只想出国或者去外企,不过如今看来,我还是对的,唐骏去了盛大,陈天桥创立的盛大,一家民营公司。一个高学历的海归在500强的公司里拿高薪水,这大约是很多年轻人的梦想,问题是,每年毕业的大学生都在做这个梦,好的职位却只有500个。
人都是要面子的,也是喜欢攀比的,即使在工作上也喜欢攀比,不管那是不是自己想要的。大家认为外企公司很好,可是好在哪里呢?好吧,他们在比较好的写字楼,这是你想要的么?他们出差住比较好的酒店,这是你想要的么?别人会羡慕一份外企公司的工作,这是你想要的么?那一切都是给别人看的,你干吗要活得那么辛苦给别人看?另一方面,他们薪水福利一般,并没有特别了不起,他们的晋升机会比较少,很难做到很高阶的主管,他们虽然厌恶常常加班,却不敢不加班,因为”你不干有得是人干”,大部分情况下会找个台湾人香港人新加坡人来管你,而这些人又往往有些莫名其妙的优越感。你想清楚了么?500强一定好么?找工作究竟是考虑你想要什么,还是考虑别人想看什么?
我的大学同学们大多数都到美国了,甚至毕业这么多年了,还有人最近到国外去了。出国真的有那么好么?我的大学同学们,大多数还是在博士、博士后、访问学者地挣扎着,至今只有一个正经在一个美国大学里拿到个正式的教职。国内的教授很难当么?我有几个表亲也去了国外了,他们的父母独自在国内,没有人照顾,有好几次人在家里昏倒都没人知道,出国,真的这么光彩么?就像有人说的”很多事情就像看A片,看的人觉得很爽,做的人未必。”
人总想找到那个最好的,可是,什么是最好的?你觉得是最好的那个,是因为你的确了解,还是因为别人说他是最好的?即使他对于别人是最好的,对于你也一定是最好的么?
对于自己想要什么,自己要最清楚,别人的意见并不是那么重要。很多人总是常常被别人的意见所影响,亲戚的意见,朋友的意见,同事的意见……问题是,你究竟是要过谁的一生?人的一生不是父母一生的续集,也不是儿女一生的前传,更不是朋友一生的外篇,只有你自己对自己的一生负责,别人无法也负不起这个责任。自己做的决定,至少到最后,自己没什么可后悔。对于大多数正常智力的人来说,所做的决定没有大的对错,无论怎么样的选择,都是可以尝试的。比如你没有考自己上的那个学校,没有入现在这个行业,这辈子就过不下去了?就会很失败?不见得。
我想,好工作,应该是适合你的工作,具体点说,应该是能给你带来你想要的东西的工作,你或许应该以此来衡量你的工作究竟好不好,而不是拿公司的大小,规模,外企还是国企,是不是有名,是不是上市公司来衡量。小公司,未必不是好公司,赚钱多的工作,也未必是好工作。你还是要先弄清楚你想要什么,如果你不清楚你想要什么,你就永远也不会找到好工作,因为你永远只看到你得不到的东西,你得到的,都是你不想要的。
可能,最好的,已经在你的身边,只是,你还没有学会珍惜。人们总是盯着得不到的东西,而忽视了那些已经得到的东西。
三、普通人
我发现中国人的励志和国外的励志存在非常大的不同,中国的励志比较鼓励人立下大志愿,卧薪尝胆,有朝一日成富成贵。而国外的励志比较鼓励人勇敢面对现实生活,面对普通人的困境,虽然结果也是成富成贵,但起点不一样,相对来说,我觉得后者在操作上更现实,而前者则需要用999个失败者来堆砌一个成功者的故事。
我们都是普通人,普通人的意思就是,概率这件事是很准的。因此,我们不会买彩票中500万,我们不会成为比尔盖茨或者李嘉诚,我们不会坐飞机掉下来,我们当中很少的人会创业成功,我们之中有30%的人会离婚,我们之中大部分人会活过65岁……
所以请你在想自己要什么的时候,要得”现实”一点,你说我想要做李嘉诚,抱歉,我帮不上你。成为比尔盖茨或者李嘉诚这种人,是靠命的,看我写的这篇文章绝对不会让你成为他们,即使你成为了他们,也绝对不是我这篇文章的功劳。”王侯将相宁有种乎”但真正当皇帝的只有一个人,王侯将相,人也不多。目标定得高些对于喜欢挑战的人来说有好处,但对于大多数普通人来说,反而比较容易灰心沮丧,很容易就放弃了。
回过头来说,李嘉诚比你有钱大致50万倍,他比你更快乐么?或许。有没有比你快乐50万倍,一定没有。他比你最多也就快乐一两倍,甚至有可能还不如你快乐。寻找自己想要的东西不是和别人比赛,比谁要得更多更高,比谁的目标更远大。虽然成为李嘉诚这个目标很宏大,但你并不见得会从这个目标以及追求目标的过程当中获得快乐,而且基本上你也做不到。你必须听听你内心的声音,寻找真正能够使你获得快乐的东西,那才是你想要的东西。
你想要的东西,或者我们把它称之为目标,目标其实并没有高低之分,你不需要因为自己的目标没有别人远大而不好意思,达到自己的目标其实就是成功,成功有大有小,快乐却是一样的。我们追逐成功,其实追逐的是成功带来的快乐,而非成功本身。职业生涯的道路上,我们常常会被攀比的心态蒙住眼睛,忘记了追求的究竟是什么,忘记了是什么能使我们更快乐。
社会上一夜暴富的新闻很多,这些消息,总会在我们的心里面掀起很多涟漪,涟漪多了就变成惊涛骇浪,心里的惊涛骇浪除了打翻承载你目标的小船,并不会使得你也一夜暴富。”只见贼吃肉,不见贼挨揍。”我们这些普通人既没有当贼的勇气,又缺乏当贼的狠辣绝决,虽然羡慕吃肉,却更害怕挨揍,偶尔看到几个没挨揍的贼就按奈不住,或者心思活动,或者大感不公,真要叫去做贼,却也不敢。
我还是过普通人的日子,要普通人的快乐,至少,晚上睡得着觉。
四、跳槽与积累
首先要说明,工作是一件需要理智的事情,所以不要在工作上耍个性,天涯上或许会有人觉得你很有个性而叫好,煤气公司电话公司不会因为觉得你很有个性而免了你的帐单。当你很帅地炒掉了你的老板,当你很酷地挖苦了一番招聘的HR,账单还是要照付,只是你赚钱的时间更少了,除了你自己,没人受损失。
我并不反对跳槽,但跳槽决不是解决问题的办法,而且频繁跳槽的后果是让人觉得没有忠诚度可言,而且不能安心工作。现在很多人从网上找工作,很多找工作的网站常常给人出些馊主意,要知道他们是盈利性企业,当然要从自身盈利的角度来考虑,大家越是频繁跳槽频繁找工作他们越是生意兴隆,所以鼓动人们跳槽是他们的工作。所以他们会常常告诉你,你拿的薪水少了,你享受的福利待遇差了,又是”薪情快报”又是”赞叹自由奔放的灵魂”。至于是否会因此让你不能安心,你跳了槽是否解决问题,是否更加开心,那个,他们管不着。
要跳槽肯定是有问题,一般来说问题发生了,躲是躲不开的,很多人跳槽是因为这样或者那样的不开心,如果这种不开心,在现在这个公司不能解决,那么在下一个公司多半也解决不掉。你必须相信,90%的情况下,你所在的公司并没有那么烂,你认为不错的公司也没有那么好。就像围城里说的,”城里的人拼命想冲出来,而城外的人拼命想冲进去。”每个公司都有每个公司的问题,没有问题的公司是不存在的。换个环境你都不知道会碰到什么问题,与其如此,不如就在当下把问题解决掉。很多问题当你真的想要去解决的时候,或许并没有那么难。有的时候你觉得问题无法解决,事实上,那只是”你觉得”。
人生的曲线应该是曲折向上的,偶尔会遇到低谷但大趋势总归是曲折向上的,而不是象脉冲波一样每每回到起点,我见过不少面试者,30多岁了,四五份工作经历,每次多则3年,少则1年,30多岁的时候回到起点从一个初级职位开始干起,拿基本初级的薪水,和20多岁的年轻人一起竞争,不觉得有点辛苦么?这种日子好过么?
我非常不赞成在一个行业超过3年以后换行业,基本上,35岁以前我们的生存资本靠打拼,35岁以生存的资本靠的就是积累,这种积累包括人际关系,经验,人脉,口碑……如果常常更换行业,代表几年的积累付之东流,一切从头开始,如果换了两次行业,35岁的时候大概只有5年以下的积累,而一个没有换过行业的人至少有了10年的积累,谁会占优势?工作到2-3年的时候,很多人觉得工作不顺利,好像到了一个瓶颈,心情烦闷,就想辞职,乃至换一个行业,觉得这样所有一切烦恼都可以抛开,会好很多。其实这样做只是让你从头开始,到了时候还是会发生和原来行业一样的困难,熬过去就向上跨了一大步,要知道每个人都会经历这个过程,每个人的职业生涯中都会碰到几个瓶颈,你熬过去了而别人没有熬过去你就领先了。跑长跑的人会知道,开始的时候很轻松,但是很快会有第一次的难受,但过了这一段又能跑很长一段,接下来会碰到第二次的难受,坚持过了以后又能跑一段,如此往复,难受一次比一次厉害,直到坚持不下去了。大多数人第一次就坚持不了了,一些人能坚持到第二次,第三次虽然大家都坚持不住了,可是跑到这里的人也没几个了,这点资本足够你安稳活这一辈子了。
一份工作到两三年的时候,大部分人都会变成熟手,这个时候往往会陷入不断的重复,有很多人会觉得厌倦,有些人会觉得自己已经搞懂了一切,从而懒得去寻求进步了。很多时候的跳槽是因为觉得失去兴趣了,觉得自己已经完成比赛了。其实这个时候比赛才刚刚开始,工作两三年的人,无论是客户关系,人脉,手下,和领导的关系,在业内的名气……还都是远远不够的,但稍有成绩的人总是会自我感觉良好的,每个人都觉得自己跟客户关系铁得要命,觉得自己在业界的口碑好得很。其实可以肯定地说,一定不是,这个时候,还是要拿出前两年的干劲来,稳扎稳打,积累才刚刚开始。
你足够了解你的客户吗?你知道他最大的烦恼是什么吗?你足够了解你的老板么?你知道他最大的烦恼是什么吗?你足够了解你的手下么?你知道他最大的烦恼是什么吗?如果你不知道,你凭什么觉得自己已经积累够了?如果你都不了解,你怎么能让他们帮你的忙,做你想让他们做的事情?如果他们不做你想让他们做的事情,你又何来的成功?

五、等待
这是个浮躁的人们最不喜欢的话题,本来不想说这个话题,因为会引起太多的争论,而我又无意和人争论这些,但是考虑到对于职业生涯的长久规划,这是一个躲避不了的话题,还是决定写一写,不爱看的请离开吧。
并不是每次穿红灯都会被汽车撞,并不是每个罪犯都会被抓到,并不是每个错误都会被惩罚,并不是每个贪官都会被枪毙,并不是你的每一份努力都会得到回报,并不是你的每一次坚持都会有人看到,并不是你每一点付出都能得到公正的回报,并不是你的每一个善意都能被理解……这个,就是世道。好吧,世道不够好,可是,你有推翻世道的勇气么?如果没有,你有更好的解决办法么?有很多时候,人需要一点耐心,一点信心。每个人总会轮到几次不公平的事情,而通常,安心等待是最好的办法。
有很多时候我们需要等待,需要耐得住寂寞,等待属于你的那一刻。周润发等待过,刘德华等待过,周星驰等待过,王菲等待过,张艺谋也等待过……看到了他们如今的功成名就的人,你可曾看到当初他们的等待和耐心?你可曾看到金马奖影帝在街边摆地摊?你可曾看到德云社一群人在剧场里给一位观众说相声?你可曾看到周星驰的角色甚至连一句台词都没有?每一个成功者都有一段低沉苦闷的日子,我几乎能想象得出来他们借酒浇愁的样子,我也能想象得出他们为了生存而挣扎的窘迫。在他们一生最中灿烂美好的日子里,他们渴望成功,但却两手空空,一如现在的你。没有人保证他们将来一定会成功,而他们的选择是耐住寂寞。如果当时的他们总念叨着”成功只是属于特权阶级的”,你觉得他们今天会怎样?
曾经我也不明白有些人为什么并不比我有能力却要坐在我的头上,年纪比我大就一定要当我的领导么?为什么有些烂人不需要努力就能赚钱?为什么刚刚改革开放的时候的人能那么容易赚钱,而轮到我们的时候,什么事情都要正规化了?有一天我突然想,我还在上学的时候他们就在社会里挣扎奋斗了,他们在社会上奋斗积累了十几二十年,我们新人来了,他们有的我都想要,我这不是在要公平,我这是在要抢劫。因为我要得太急,因为我忍不住寂寞。二十多岁的男人,没有钱,没有事业,却有蓬勃的欲望。
人总是会遇到挫折的,人总是会有低潮的,人总是会有不被人理解的时候的,人总是有要低声下气的时候,这些时候恰恰是人生最关键的时候,因为大家都会碰到挫折,而大多数人过不了这个门槛,你能过,你就成功了。在这样的时刻,我们需要耐心等待,满怀信心地去等待,相信,生活不会放弃你,机会总会来的。至少,你还年轻,你没有坐牢,没有生治不了的病,没有欠还不起的债。比你不幸的人远远多过比你幸运的人,你还怕什么?路要一步步走,虽然到达终点的那一步很激动人心,但大部分的脚步是平凡甚至枯燥的,但没有这些脚步,或者耐不住这些平凡枯燥,你终归是无法迎来最后的那些激动人心。
逆境,是上帝帮你淘汰竞争者的地方。要知道,你不好受,别人也不好受,你坚持不下去了,别人也一样,千万不要告诉别人你坚持不住了,那只能让别人获得坚持的信心,让竞争者看着你微笑的面孔,失去信心,退出比赛。胜利属于那些有耐心的人。
在最绝望的时候,我会去看电影《The Pursuit of Happyness》《Jerry Maguire》,让自己重新鼓起勇气,因为,无论什么时候,我们总还是有希望。当所有的人离开的时候,我不失去希望,我不放弃。每天下班坐在车里,我喜欢哼着《隐形的翅膀》看着窗外,我知道,我在静静等待,等待属于我的那一刻。
原贴里伊吉网友的话我很喜欢,抄录在这里:
每个人都希望,自己是独一无二的特殊者
含着金匙出生、投胎到好家庭、工作安排到电力局拿1w月薪这样的小概率事件,当然最好轮到自己
红军长征两万五、打成右派反革命、胼手胝足牺牲尊严去奋斗,最好留给祖辈父辈和别人
自然,不是每个吃过苦的人都会得到回报
但是,任何时代,每一个既得利益者身后,都有他的祖辈父辈奋斗挣扎乃至流血付出生命的身影
羡慕别人有个好爸爸,没什么不可以
问题是,你的下一代,会有一个好爸爸吗?
至于问到为什么不能有同样的赢面概率?我只能问:为什么物种竞争中,人和猴子不能有同样的赢面概率?
物竞天择。猴子的灵魂不一定比你卑微,但你身后有几十万年的类人猿进化积淀。
六、入对行跟对人
在中国,大概很少有人是一份职业做到底的,虽然如此,第一份工作还是有些需要注意的地方,有两件事情格外重要,第一件是入行,第二件事情是跟人。第一份工作对人最大的影响就是入行,现代的职业分工已经很细,我们基本上只能在一个行业里成为专家,不可能在多个行业里成为专家。很多案例也证明即使一个人在一个行业非常成功,到另外一个行业,往往完全不是那么回事情,”你想改变世界,还是想卖一辈子汽水?”是乔布斯邀请百事可乐总裁约翰•斯考利加盟苹果时所说的话,结果这位在百事非常成功的约翰,到了苹果表现平平。其实没有哪个行业特别好,也没有哪个行业特别差,或许有报道说哪个行业的平均薪资比较高,但是他们没说的是,那个行业的平均压力也比较大。看上去很美的行业一旦进入才发现很多地方其实并不那么完美,只是外人看不见。
说实话,我自己都没有发大财,所以我的建议只是让人快乐工作的建议,不是如何发大财的建议,我们只讨论一般普通打工者的情况。我认为选择什么行业并没有太大关系,看问题不能只看眼前。比如,从前年开始,国家开始整顿医疗行业,很多医药公司开不下去,很多医药行业的销售开始转行。其实医药行业的不景气是针对所有公司的,并非针对一家公司,大家的日子都不好过,这个时候跑掉是非常不划算的,大多数正规的医药公司即使不做新生意撑个两三年总是能撑的,大多数医药销售靠工资撑个两三年也是可以撑的,国家不可能永远捏着医药行业不放的,两三年以后光景总归还会好起来的,那个时候别人都跑了而你没跑,那时的日子应该会好过很多。有的时候觉得自己这个行业不行了,问题是,再不行的行业,做得人少了也变成了好行业,当大家都觉得不好的时候,往往却是最好的时候。大家都觉得金融行业好,金融行业门槛高不说,有多少人削尖脑袋要钻进去,竞争激励,进去以后还要时时提防,一个疏忽,就被后来的人给挤掉了,压力巨大,又如何谈得上快乐?也就未必是”好”工作了。
太阳能这个东西至今还不能进入实际应用的阶段,但是中国已经有7家和太阳能有关的公司在纽交所上市了,国美苏宁永乐其实是贸易型企业,也能上市,鲁泰纺织连续10年利润增长超过50%,卖茶的一茶一座,卖衣服的海澜之家都能上市……其实选什么行业真的不重要,关键是怎么做。事情都是人做出来的,关键是人。
有一点是需要记住的,这个世界上,有史以来直到我们能够预见得到的未来,成功的人总是少数,有钱的人总是少数,大多数人是一般的,普通的,不太成功的。因此,大多数人的做法和看法,往往都不是距离成功最近的做法和看法。因此大多数人说好的东西不见得好,大多数人说不好的东西不见得不好。大多数人都去炒股的时候说明跌只是时间问题,大家越是热情高涨的时候,跌的日子越近。大多数人买房子的时候,房价不会涨,而房价涨的差不多的时候,大多数人才开始买房子。不会有这样一件事情让大家都变成功,发了财,历史上不曾有过,将来也不会发生。有些东西即使一时运气好得到了,还是会在别的时候别的地方失去的。
年轻人在职业生涯的刚开始,尤其要注意的是,要做对的事情,不要让自己今后几十年的人生总是提心吊胆,更不值得为了一份工作赔上自己的青春年华。我的公司是个不行贿的公司,以前很多人不理解,甚至自己的员工也不理解,不过如今,我们是同行中最大的企业,客户乐意和我们打交道,尤其是在国家打击腐败的时候,每个人都知道我们做生意不给钱的名声,都敢于和我们做生意。而勇于给钱的公司,不是倒了,就是跑了,要不就是每天睡不好觉,人还是要看长远一点。很多时候,看起来最近的路,其实是最远的路,看起来最远的路,其实是最近的路。
跟对人是说,入行后要跟个好领导好老师,刚进社会的人做事情往往没有经验,需要有人言传身教。对于一个人的发展来说,一个好领导是非常重要的。所谓”好”的标准,不是他让你少干活多拿钱,而是以下三个。
首先,好领导要有宽广的心胸,如果一个领导每天都会发脾气,那几乎可以肯定他不是个心胸宽广的人,能发脾气的时候却不发脾气的领导,多半是非常厉害的领导。中国人当领导最大的毛病是容忍不了能力比自己强的人,所以常常可以看到的一个现象是,领导很有能力,手下一群庸才或者手下一群闲人。如果看到这样的环境,还是不要去的好。
其次,领导要愿意从下属的角度来思考问题,这一点其实是从面试的时候就能发现的,如果这位领导总是从自己的角度来考虑问题,几乎不听你说什么,这就危险了。从下属的角度来考虑问题并不代表同意下属的说法,但他必须了解下属的立场,下属为什么要这么想,然后他才有办法说服你,只关心自己怎么想的领导往往难以获得下属的信服。
第三,领导敢于承担责任,如果出了问题就把责任往下推,有了功劳就往自己身上揽,这样的领导不跟也罢。选择领导,要选择关键时刻能抗得住的领导,能够为下属的错误买单的领导,因为这是他作为领导的责任。
有可能,你碰不到好领导,因为,中国的领导往往是屁股决定脑袋的领导,因为他坐领导的位置,所以他的话就比较有道理,这是传统观念官本位的误区,可能有大量的这种无知无能的领导,只是,这对于你其实是好事,如果将来有一天你要超过他,你希望他比较聪明还是比较笨?相对来说这样的领导其实不难搞定,只是你要把自己的身段放下来而已。多认识一些人,多和比自己强的人打交道,同样能找到好的老师,不要和一群同样郁闷的人一起控诉社会,控诉老板,这帮不上你,只会让你更消极。和那些比你强的人打交道,看他们是怎么想的,怎么做的,学习他们,然后跟更强的人打交道。
七 选择
我们每天做的最多的事情,其实是选择,因此在谈职业生涯的时候不得不提到这个话题。
我始终认为,在很大的范围内,我们究竟会成为一个什么样的人,决定权在我们自己,每天我们都在做各种各样的选择,我可以不去写这篇文章,去别人的帖子拍拍砖头,也可以写下这些文字,帮助别人的同时也整理自己的思路,我可以多注意下格式让别人易于阅读,也可以写成一堆,我可以就这样发上来,也可以在发以前再看几遍,你可以选择不刮胡子就去面试,也可以选择出门前照照镜子……每天,每一刻我们都在做这样那样的决定,我们可以漫不经心,也可以多花些心思,成千上万的小选择累计起来,就决定了最终我们是个什么样的人。
从某种意义上来说我们的未来不是别人给的,是我们自己选择的,很多人会说我命苦啊,没得选择阿,如果你认为”去微软还是去IBM””上清华还是上北大””当销售副总还是当厂长”这种才叫选择的话,的确你没有什么选择,大多数人都没有什么选择。但每天你都可以选择是否为客户服务更周到一些,是否对同事更耐心一些,是否把工作做得更细致一些,是否把情况了解得更清楚一些,是否把不清楚的问题再弄清楚一些……你也可以选择在是否在痛苦中继续坚持,是否抛弃掉自己的那些负面的想法,是否原谅一个人的错误,是否相信我在这里写下的这些话,是否不要再犯同样的错误……生活每天都在给你选择的机会,每天都在给你改变自己人生的机会,你可以选择赖在地上撒泼打滚,也可以选择咬牙站起来。你永远都有选择。有些选择不是立杆见影的,需要累积,比如农民可以选择自己常常去浇地,也可以选择让老天去浇地,诚然你今天浇水下去苗不见得今天马上就长出来,但常常浇水,大部分苗终究会长出来的,如果你不浇,收成一定很糟糕。
每天生活都在给你机会,他不会给你一叠现金也不会拱手送你个好工作,但实际上,他还是在给你机会。我的家庭是一个普通的家庭,没有任何了不起的社会关系,我的父亲在大学毕业以后就被分配到了边疆,那个小县城只有一条马路,他们那一代人其实比我们更有理由抱怨,他们什么也没得到,年轻的时候文化大革命,书都没得读,支援边疆插队落户,等到老了,却要给年轻人机会了。他有足够的理由象成千上万那样的青年一样坐在那里抱怨生不逢时,怨气冲天。然而在分配到边疆的十年之后,国家恢复招研究生,他考回了原来的学校。研究生毕业,他被分配到了安徽一家小单位里,又是3年以后,国家第一届招收博士生,他又考回了原来的学校,成为中国第一代博士,那时的他比现在的我年纪还大。生活并没有放弃他,他也没有放弃生活。10年的等待,他做了他自己的选择,他没有放弃,他没有破罐子破摔,所以时机到来的时候,他改变了自己的人生。你最终会成为什么样的人,就决定在你的每个小小的选择之间。
你选择相信什么?你选择和谁交朋友?你选择做什么?你选择怎么做?……我们面临太多的选择,而这些选择当中,意识形态层面的选择又远比客观条件的选择来得重要得多,比如选择做什么产品其实并不那么重要,而选择怎么做才重要。选择用什么人并不重要,而选择怎么带这些人才重要。大多数时候选择客观条件并不要紧,大多数关于客观条件的选择并没有对错之分,要紧的是选择怎么做。一个大学生毕业了,他要去微软也好,他要卖猪肉也好,他要创业也好,他要做游戏代练也好,只要不犯法,不害人,都没有什么关系,要紧的是,选择了以后,怎么把事情做好。
除了这些,你还可以选择时间和环境,比如,你可以选择把这辈子最大的困难放在最有体力最有精力的时候,也可以走一步看一步,等到了40岁再说,只是到了40 多岁,那正是一辈子最脆弱的时候,上有老下有小,如果在那个时候碰上了职业危机,实在是一件很苦恼的事情。与其如此不如在20多岁30多岁的时候吃点苦,好让自己脆弱的时候活得从容一些。你可以选择在温室里成长,也可以选择到野外磨砺,你可以选择在办公室吹冷气的工作,也可以选择40度的酷热下,去见你的客户,只是,这一切最终会累积起来,引导你到你应得的未来。
我不敢说所有的事情你都有得选择,但是绝大部分事情你有选择,只是往往你不把这当作一种选择。认真对待每一次选择,才会有比较好的未来。
八 选择职业
职业的选择,总的来说,无非就是销售、市场、客服、物流、行政、人事、财务、、管理几个大类,有个有趣的现象就是,500强的CEO当中最多的是销售出身,第二多的人是财务出身,这两者加起来大概超过95%。现代IT行业也有技术出身成为老板的,但实际上,后来他们还是从事了很多销售和市场的工作,并且表现出色,公司才获得了成功,完全靠技术能力成为公司老板的,几乎没有。这是有原因的,因为销售就是一门跟人打交道的学问,而管理其实也是跟人打交道的学问,这两者之中有很多相通的东西,他们的共同目标就是”让别人去做某件特定的事情。”而财务则是从数字的层面了解生意的本质,从宏观上看待生意的本质,对于一个生意是否挣钱,是否可以正常运作有着最深刻的认识。
公司小的时候是销售主导公司,而公司大的时候是财务主导公司,销售的局限性在于只看人情不看数字,财务的局限性在于只看数字不看人情。公司初期,运营成本低,有订单就活得下去,跟客户也没有什么谈判的条件,别人肯给生意做已经谢天谢地了,这个时候订单压倒一切,客户的要求压倒一切,所以当然要顾人情。公司大了以后,一切都要规范化,免得因为不规范引起一些不必要的风险,同时运营成本也变高,必须提高利润率,把有限的资金放到最有产出的地方。对于上市公司来说,股东才不管你客户是不是最近出国,最近是不是那个省又在搞严打,到了时候就要把业绩拿出来,拿不出来就抛股票,这个时候就是数字压倒一切。
前两天听到有人说一句话觉得很有道理,开始的时候我们想”能做什么?”,等到公司做大了有规模了,我们想”不能做什么。”很多人在工作中觉得为什么领导这么保守,这也不行那也不行,错过很多机会。很多时候是因为,你还年轻,你想的是”能做什么”,而作为公司领导要考虑的方面很多,他比较关心”不能做什么”。
我并非鼓吹大家都去做销售或者财务,究竟选择什么样的职业,和你究竟要选择什么样的人生有关系,有些人就喜欢下班按时回家,看看书听听音乐,那也挺好,但就不适合找个销售的工作了,否则会是折磨自己。有些人就喜欢出风头,喜欢成为一群人的中心,如果选择做财务工作,大概也干不久,因为一般老板不喜欢财务太积极,也不喜欢财务话太多。先想好自己要过怎样的人生,再决定要找什么样的职业。有很多的不快乐,其实是源自不满足,而不满足,很多时候是源自于心不定,而心不定则是因为不清楚究竟自己要什么,不清楚要什么的结果就是什么都想要,结果什么都没得到。
我想,我们还是因为生活而工作,不是因为工作而生活,生活是最要紧的,工作只是生活中的一部分。我总是觉得生活的各方方面都是相互影响的,如果生活本身一团乱麻,工作也不会顺利。所以要有娱乐、要有社交、要锻炼身体,要有和睦的家庭……最要紧的,要开心,我的两个销售找我聊天,一肚子苦水,我问他们,2年以前,你什么都没有,工资不高,没有客户关系,没有业绩,处于被开的边缘,现在的你比那时条件好了很多,为什么现在却更加不开心了?如果你做得越好越不开心,那你为什么还要工作?首先的首先,人还是要让自己高兴起来,让自己心态好起来,这种发自内心的改变会让你更有耐心,更有信心,更有气质,更能包容……否则,看看镜子里的你,你满意么?
有人会说,你说得容易,我每天加班,不加班老板就会把我炒掉,每天累得要死,哪有时间娱乐、社交、锻炼?那是人们把目标设定太高的缘故,如果你还在动不动就会被老板炒掉的边缘,那么你当然不能设立太高的目标,难道你还想每天去打高尔夫?你没时间去健身房锻炼身体,但是上下班的时候多走几步可以吧,有楼梯的时候走走楼梯不走电梯可以吧?办公的间隙扭扭脖子拉拉肩膀做做俯卧撑可以吧?谁规定锻炼就一定要拿出每天2个小时去健身房?你没时间社交,每月参加郊游一次可以吧,周末去参加个什么音乐班,绘画班之类的可以吧,去尝试认识一些同行,和他们找机会交流交流可以吧?开始的时候总是有些难的,但迈出这一步就会向良性循环的方向发展。而每天工作得很苦闷,剩下的时间用来咀嚼苦闷,只会陷入恶性循环,让生活更加糟糕。

0

PHP招聘信息-PHP/MySQL DEVELOPER-TORONTO


Divaris Alexander Corporation is looking for an experienced PHP to contribute as a contractor in the current development of our based property tax platform.
Duties/ Responsibilities:
Database Modeling.
Preparation of application architecture.
Design and implement application.
We are looking for a well-organized, conscientious person with skills in PHP programming and a working knowledge of . You will be required to interact with our team and deploy the application features quickly, maintaining quality and reliability.
Experience required:
Organizations Skills
Communication Skills (oral and written in English)
Understanding of standards
Working knowledge of XML, CSS and
PHP 4 and 5 (4 years +)
MySQL 4.11 and 5.1 (4 years +)
Additional Skills:
Working knowledge in a Environment
Knowledgeable in database modeling and tools(programs)
Flex 2 or 3 and
Coldfusion
Based in , Divaris Alexander Corporation, incorporated in 1987, provides property assessment and municipal tax consulting services for industrial, commercial, investment and special use property owners and occupants.
We require that you be based in Toronto and able to work onsite.
Apply via email to info[at]dival.com

0

XCache & XDebug on road


终于配置上 XCache 和 XDebug 了,可惜的是 --bridge 一直没搞好,只有双击运行 JavaBridge 后才行,唉,要是能内置到 PHP 里就好了。

继续研究 &

如果说之前在 UUSee 是向上研究,既“抽象”、“架构”的话,那么来 IMobile 之后研究方向则是向下,研究底层,研究以前没注意到的更细节的地方了。

:)

Good days, good luck.

0

redhad下的openssl(安装和卸载)


转至: http://.csdn.net/baitianhai/archive/2004/10/27/155461.aspx

最近在鼓捣redhat ,想自己以源代码方式安装软件,不想用rpm方式安装。

首先从httpd开始,先卸载在安装倒是比较容易,不过后来像添加ssl功能,发现编译的时候需要用openssl的安装目录,本人比较愚笨,一顿好找也没有找到,于是就想把openssl也以源代码方式安装。先卸载,此时出现问题,系统好多东西依赖于openssl的库,我查了好多资料也没找到什么办法,于是我最后一狠心,用rpm -e –nodeps给卸载了,然后手动安装了openssl,然后重新启动,这下坏了,好多服务都起不来了,smb,ssh等等,图形模式也起不来了,我欲哭无泪。

因为我是在虚拟机上安装的,smb起不来了,我只能重新安装系统了。这次安装我大多数东西都没选择,一路安装完毕,结果在文本方式发现vi编辑没有颜色了,哎,也不知道是少装了那个东西弄得(各位谁知道麻烦告诉告诉我一下),只能按照猜测重新安装了又添加了一些东西。不过幸运的vi高亮显示功能又有了,遗憾的是具体是那个软件我还是不清楚。有了上次的教训我不敢轻易卸掉系统原来的openssl了,我从网上搜索到了一篇安装openssl的英文文章,地址在 http://www.devside.net///linux/ 我按照上面说的安装了zlib,。步骤简介如下(怕以后忘了)

安装zlib

Home : http://www.gzip.org/zlib/

Package(linux source) : http://www.gzip.org/zlib/

Our Configuration

Install to : /usr/local

Module types : dynamically and staticly loaded modules, *.so and *.a

Build Instructions

zlib library files are placed into /usr/local/lib and zlib header files are placed into /usr/local/include, by default.

Build static libraries

…/zlib-1.2.1]# ./configure

…/zlib-1.2.1]# make test

…/zlib-1.2.1]# make install

Build shared libraries

…/zlib-1.2.1]# make clean

…/zlib-1.2.1]# ./configure –shared

…/zlib-1.2.1]# make test

…/zlib-1.2.1]# make install

…/zlib-1.2.1]# cp zutil.h /usr/local/include

…/zlib-1.2.1]# cp zutil.c /usr/local/include

/usr/local/lib should now contain…

libz.a

libz.so -> libz.so.1.2.1

libz.so.1 -> libz.so.1.2.1

libz.so.1.2.1

/usr/local/include should now contain…

zconf.h

zlib.h

zutil.h

[Optional] Instructions for non-standard placement of zlib

Create the directory that will contain zlib

…/zlib-1.2.1]# mkdir /usr/local/zlib

Follow the given procedure above, except

…/zlib-1.2.1]# ./configure –prefix=/usr/local/zlib

Update the Run-Time Linker

/etc/ld.so. will need to be updated with the new zlib shared lib: libz.so.1.2.1

For standard zlib installation…

Add /usr/local/lib to /etc/ld.so.conf, if specified path is not present

/etc]# ldconfig

If zlib was installed with a prefix…

Add /usr/local/zlib/lib to /etc/ld.so.conf

/etc]# ldconfig

安装openssl

Download

Home : http://www.openssl.org/

Package(source) : openssl-0.9.7d.tar.gz

Our Configuration

install to : /usr/local/ssl

module types : dynamically and staticly loaded modules, *.so *.a

Build Instructions

…/openssl-0.9.7d]# ./config

–prefix=/usr/local/ssl

[default location]

shared

[in addition to the usual static libraries, create shared libraries]

zlib-dynamic

[like "zlib", but has OpenSSL load the zlib library dynamically when needed]

…/openssl-0.9.7d]# ./config -t

[display guess on system made by ./config]

…/openssl-0.9.7d]# make

…/openssl-0.9.7d]# make test

…/openssl-0.9.7d]# make install

Update the Run-time Linker

ld.so.cache will need to be updated with the location of the new OpenSSL shared libs: libcrypto.so.0.9.7 and libssl.so.0.9.7

Sometimes it is sufficient to just add these two files to /lib, but we recommend you follow these instructions instead.

Edit /etc/ld.so.conf

Add /usr/local/ssl/lib to the bottom.

…]# ldconfig

Update the PATH

Edit /root/.bash_profile

Add /usr/local/ssl/bin to the PATH variable.

Re-login

Testing

…]# openssl version

Should display OpenSSL 0.9.7d 17 Mar 2004

If an older version is shown, your system contains a previously installed OpenSSL.

Repeate the steps in Update the PATH, except place the specified location at the start of the PATH variable.

[the older openssl, on most systems, is located under /usr/bin]

[the command 'which openssl' should display the path of the openssl that your system is using]

/usr/local/ssl/bin]# ./openssl version should display the correct version.

但是我最后没有得到想要的结果,系统原来的openssl还是没能卸载掉,我该怎么做那?我继续搜索资料,哈,幸运的我找了,在一个国内论坛上是这么说的

cd /usr/local/ssl/lib

ln -s libcrypto.so.0.9.7 libcrypto.so.2

ln -s libssl.so.0.9.7 libssl.so.2

//最后要刷新系统的动态连接库配置

echo /usr/local/ssl/lib >> /etc/ld.so.conf

ldconfig -v

这下子我豁然开朗,原来依赖的那2个文件是个软链接啊,我把它修改为我现在真正的openssl库文件不是就行了吗?于是一顿忙碌后,我终于执行了 rpm -e -nodeps ,然后重新启动系统,一路运行下去,全是绿灯。一时间感觉自己好幸福啊

为了这个问题我查了国内的几个比较大的unix/linux网站都没找到资料,不过从这里http://bbs.netbuddy.org//737.html还是找到了(国外的E文大概意思能看懂,但是查找起来还是没找到,也不知道这方面好点的网站),

0

实现和IE浏览器交互的几种方法的介绍


内容
实现和IE浏览器交互的几种方法的介绍
—- 1.引言

—- 如何实现对IE浏览器中对象的操作是一个很有实际意义问题,通过和IE绑定的DLL我们可以记录IE浏览过的网页的顺序,分析用户的使用行为和模式。我们可以对网页的内容进行过滤和翻译,可以自动填写网页中经常需要用户填写的Form内容等等,我们所有的例子代码都是通过VC来表示的,采用的原理是通过和IE对象的接口的交互来实现对IE的访问。实际上是采用COM的技术,我们知道COM是和语言无关的一种二进制对象交互的模式,所以实际上我们下面所描述的内容都可以用其他的语言来实现,比如VB,DELPHI,C++ Builder等等。

—- 2.IE实例遍历实现

—- 首先我们来看系统是如何知道当前有多少个IE的实例在运行。

—- 我们知道在Windows体系结构下,一个应用程序可以通过操作系统的运行对象表来和这些应用的实例进行交互。但是IE当前的实现机制是不在运行对象表中进行注册,所以需要采用其他的方法。我们知道可以通过ShellWindows集合来代表属于shell的当前打开的窗口的集合,而IE就是属于shell的一个应用程序。

—- 下面我们描述一下用VC实现对当前 IE实例的进行遍历的方法。IShellWindows是关于系统shell的一个接口,我们可以定义一个如下的接口变量:

SHDocVw::IShellWindowsPtr m_spSHWinds;
然后创建变量的实例:
   m_spSHWinds.CreateInstance
   (__uuidof(SHDocVw::ShellWindows));
通过IShellWindows接口的方法GetCount
可以得到当前实例的数目:
      long nCount = m_spSHWinds- >GetCount();
通过IShellWindows接口的方法Item
可以得到每一个实例对象
    IDispatchPtr spDisp;
    _variant_t va(i, VT_I4);
    spDisp = m_spSHWinds->Item(va);
然后我们可以判断实例对象是不是
属于IE浏览器对象,通过下面的语句实现:
    SHDocVw::IWebBrowser2Ptr spBrowser(spDisp);
    assert(spBrowser != NULL)

—-在得到了IE浏览器对象以后,我们可以调用IWebBrowser2Ptr接口的方法来得到当前的文档对象的指针: MSHTML::IHTMLDocument2Ptr spDoc(spBrowser->GetDocument());

—- 然后我们就可以通过这个接口对这个文档对象进行操作,比如通过Gettitle得到文档的标题。

—- 我们在浏览网络的时候,一般总会同时开很多IE的实例,如果这些页面都是很好的话,我们可能想保存在硬盘上,这样,我们需要对每一个实例进行保存,而如果我们采用上面的原理,我们可以得到每一个IE的实例及其网页对象的接口,这样就可以通过一个简单的程序来批量的保存当前的所有打开的网页。采用上面介绍的方法实现了对当前IE实例的遍历,但是我们希望得到每一个IE实例所产生的事件,这就需要通过DLL的机制来实现。

—- 3.和IE相绑定的DLL的实现

—- 我们介绍一下如何建立和IE进行绑定的DLL的实现的过程。为了和IE的运行实例进行绑定,我们需要建立一个能够和每一个IE实例进行绑定的DLL。IE的启动过程是这样的,当每一个IE的实例启动的时候,它都会在注册表中去寻找这个的一个CLSID,具体的注册表的键位置为:

HKEY_LOCALL_MACHINESOFTWAREMicrosoftWindows
CurrentVersionExplorerBrowser Helper Objects

—- 当在这个键位置下存在CLSIDs的时候,IE会通过使用CoCreateInstance()方法来创建列在该键位置下的每一个对象的实例。注意对象的CLSIDs必须用子键而非启动过程是这样的,当每一个IE的实例启动的时候名字值的形式表现,比如{DD41D66E-CE4F-11D2-8DA9-00A0249EABF4} 就是一个有效的子键。我们使用DLL的形式而非EXE的形式的原因是因为DLL和IE实例运行在同一个进程空间里面。每一个这种形式的DLL必须实现接口IObjectWithSite,其中方法SetSite必须被实现。通过这个方法,我们自己的DLL就可以得到一个指向IE COM对象的IUnknown的指针,实际上通过这个指针我们就可以通过COM对象中的方法QueryInterface来遍历所有可以得到的接口,这是COM的基本的机制。当然我们需要的只是IWebBrowser2这个接口。

—- 实际上我们建立的是一个COM对象,DLL只不过是COM对象的一种表现形式。我们建立的COM对象需要建立和实现的方法有:

—-1. IOleObjectWithSite接口的方法SetSite必须实现。实际上IE实例通过这个方法向我们的COM对象传递一个接口的指针。假设我们有一个接口指针的变量,不妨设为:

—-CComQIPtr< IWebBrowser2, &IID_IWebBrowser2 > m_myWebBrowser2;

—- 我们就可以在方法SetSite中把这个传进来的接口指针赋给m_myWebBrowser2。 2. 在我们得到了指向IE COM对象的接口后,我们需要把自己的DLL和IE实例所发生的事件相关连,为了实现这个目的,需要介绍两个接口:

—-(1) IConnectionPointContainer。:

—-CComQIPtr< IWebBrowser2, &这里使用这个接口的目的是用来根据它得到的IID来建立和DLL的一个特定的连接。比如我们可以进行如下的定义:

CComQIPtr< IConnectionPointContainer,
&IID_IConnectionPointContainer >          
spCPContainer(m_myWebBrowser2);

—-然后,我们需要把所有IE中发生的事件和我们的DLL进行通讯,可以使用 IConnectPoint。

—-(2) IConnectPoint。通过这个接口,客户可以对连接的对象开始或者是终止一个advisory循环。IConnectPoint有两个主要的方法,一个为Advice,另一个为Unadvise。对于我们的应用来说,Advise是用来在每一个IE发生的事件和DLL之间建立一个通道。而Unadvise就是用来终止以前用Advise建立的通知关系。比如我们可以定义IConnectPoint接口如下: CComPtr< IConnectionPoint > spConnectionPoint;

—- 然后,我们要使所有在IE实例中发生的事件和我们的DLL相关,可以使用 如下的方法:

hr = spCPContainer->FindConnectionPoint(
DIID_DWebBrowserEvents2, &spConnectionPoint);

—-然后我们通过IConnectPoint接口的方法Advice使每当IE有一个新的事件发生的时候,都能够让我们的DLL知道。可以用如下的语句实现:

hr = spConnectionPoint- >Advise(
(IDispatch*)this, &m_dwIDCode);

—-在把IE实例中的事件和我们的DLL之间建立联系以后,我们可以通过IDispatch接口的Invoke()方法来处理所有的IE的事件。

—-3. IDispatch接口的Invoke()方法。IDispatch是从IUnknown中继承的一个接口的类型,通过COM接口提供的任何服务都可以通过IDispatch接口来实现。IDispatch::Invoke的工作方式同vtbl幕后的工作方式是类似的,Invoke将实现一组按索引来访问的函数,我们可以对Invoke方法进行动态的定制以提供不同的服务。Invoke方法的表示如下:

STDMETHOD(Invoke)(DISPID dispidMember,REFIID
riid, LCID lcid, WORD wFlags,
DISPPARAMS * pdispparams, VARIANT * pvarResult,
EXCEPINFO * pexcepinfo, UINT * puArgErr);

—-其中,DISPID是一个长整数,它标识的是一个函数。对于IDispatch的某一个特定的实现,DISPID都是唯一的。IDispatch的每一个实现都有其自己的IID,这里dispidMemeber实际上是可以认为是和IE实例所发生的每一个事件相关的方法,比如:DISPID_BEFORENAVIGATE2,DISPID_NAVIGATECOMPLETE2等等。 这个方法中另外一个比较重要的参数是DISPPARAMS,它的结构如下:

typedef struct tagDISPPARAMS
   {
       VARIANTARG* rgvarg;
//VARIANTARG是同VARAIANT相同的,可以在
    //OAIDL.IDL中找到。所以实际上rgvarg是一个参数数
     //组
       DISPID*  rgdispidNameArgs;  //命名参数的DISPID
       unsigned int cArgs;    //表示数组中元素的个数
       unsigned int CnameArgs;  //命名元素的个数
   }DISPPARAMS

—-要注意的是每一个参数的类型都是VARIANTARG,所以在IE和我们DLL之间可以传递的参数类型的数目是有限的。只有那些能够被放到VARIANTARG结构中的类型才可以通过调度接口进行传递。 比如对于事件DISPID_NAVIGATECOMPLETE2来说:第一个参数表示IE在访问的URL的值,类型是VT_BYREF|VT_VARIANT。注意DISPID_NAVIGATECOMPLETE2等DISPID已经在VC中被定义,我们可以直接进行使用。 如上说述,我们在方法Invoke中可以得到所有IE实例所发生的事件,我们可以把这些数据放到文件中进行事后的分析,也可以放到一个列表框中实时的显示。

—- 4.微软的HTML文档对象模型和应用分析

—- 下面我们来看如何得到网页文档的接口:网页文档的接口为IHTMLDocument2,可以通过调用IE COM对象的get_Document方法来得到网页的接口。使用如下的语句:

hr = m_spWebBrowser2- >get_Document(&spDisp);
CComQIPtr< IHTMLDocument2,
&IID_IHTMLDocument2 > spHTML;
spHTML = spDisp;

—- 这样我们就得到了网页对象的接口,然后我们就可以对网页进行分析,比如通过IHTMLDocument2提供的方法get_URL我们可以得到和该网页相关的URL的地址值,通过get_forms方法可以该网页中所有的Form对象的集合。实际上W3C组织已经制定了一个DOM(Document Objec Model)标准,当然这个标准不仅仅是针对HTML,同时还是针对XML制定的。W3C组织只是定义了网页对象的接口,不同的公司可以采用不同的语言和方法进行具体的实现。按照W3C组织定义的网页对象被认为是动态的,即用户可以动态的对网页对象里面所包含的每一个对象进行操作。这里的对象可以是指一个输入框,也可以是图象和声音等对象。同时按照W3C的正式文档的说明,网页对象是可以动态增加和删除的。事实上,很少有厂商实现了DOM定义的所有功能。微软对网页对象的定义也基本上是按照这个标准实现的。但是当前的接口还不支持动态的增加和删除元素,但是可以对网页中的基本元素进行属性的修改。比如IHTMLElementCollection表示网页中一些基本的元素的集合,IHTMLElement表示网页中的一个基本的元素。而象IHTMLOptionElement接口就表示一个特定的元素Option。基本的元素都有setAttribute和geAttribute方法来动态的设置和得到元素的名称和值。

—- 较为常见的一个应用是我们能够分析网页中是否有需要填写的Forms,如果这个网址的Forms以前已经填写过而且数据我们已经保存下来的话,我们就可以把数据自动放到和该URL下的Forms的相关的位置中去。另外,我们可以总结网页上需要填写的Form的数据项,先对这些数据项进行赋值,以后碰到有相同的数据项的时候就自动把我们赋值的内容填写进去。实际上Form是对象,Form中包含的元素,比如INPUT,OPTION,SELECT等类型的输入元素都是对象。

—- 另外一个可以想到的应用是自动对网页中的文本进行翻译,因为我们可以修改网页中任何对象的属性,所以我们可以把里面不属于本国语言的部分自动翻译成本国语言,当然真正的实现还要靠自然语言理解方面技术的突破,但是IE浏览器的接口和对象的形式使我们能够灵活的控制整个IE,无论是从事件对象还是到网页对象。

—- 5.小结

—- 上面我们分析了如何得到所有IE的实例,同时介绍了和IE实例相捆绑的DLL的详细的实现机制,同时对网页的对象化进行了分析。并且介绍了几个相关的应用和实现的方法及存在的技术问题。IE是一个组件化的以COM为基础的浏览器,它具有强大的功能,同时为应用开发者留下了广阔的空间,当然它也存在体积比较大,速度相对比较慢的缺点。但是它的体系结构代表了微软先进的创新的技术,因此具有强大的生命力。

0

Toolband (Toolbar for IE) sample using WTL


转至: http://www.codeproject.com

Sample Image - toolband10.gif


Credits and Acknowlegements

This module is based on the ATL DeskBand Wizard article that was created by Erik Thompson. My thanks goes to him for producing a great wizard that saves you the nity grity of creating DeskBands.

Please note that this project does not use MFC, for all those MFC die hards that want to use MFC in their Tool Bands I suggest you down load the KKBar sample from microsofts MSDN site.

The KBBar Sample can be downloaded from here

Creating the ToolBand Module

You will need to install the ATL DeskBand Wizard in order to create ToolBands. Please follow the instruction in this article.

The best way to kick start a Tool band project is to use the ATL COM App Wizard. The COM Object needs to be in-proc therefore choose ‘DLL’ as the Type. The rest of the options can be kept in there default state. (Note this project does not use MFC, as the project is based on ATL and )

Once you have a ATL COM Project, You can use the ATL DeskBand Wizard to create the Initial Tool Band.

Adding Support for WTL

You will require the WTL Libraries, these can be downloaded from the microsoft site

See Installation of WTL

The following header files needs to be added to stdafx.h file

atlapp.hatlwin.hatlctrls.hatlmisc.h

Create the

You can create your toolbar in the usual way via the resource editor, Once you have your toolbar you need to create the toolbar dynamically. The CBandToolBarCtrl is inherited from CToolBarCtrl and is used to create the toolbar dynamically.

DWORD dStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |                CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN |                TBSTYLE_TOOLTIPS | TBSTYLE_FLAT;    HWND hWnd = m_wndToolBar.CreateSimpleToolBarCtrl(hWndChild, IDR_TOOLBAR_TEST,                                                  FALSE, dStyle); 

This is done in the RegisterAndCreateWindow function that is called from SetSite method.

Message Reflection

The best way to handle the messages of the toolbar is to let the control handle its own messages via "Message Reflection". The best way to reflect the messages is to create an invisible control that acts as the parent for the toolbar. The invisible control will reflect the toolbar messages back to itself. See CBandToolBarReflectorCtrl for the invisible control that will be used.

The following code shows the parent child relationship that is used to achieve Message Reflection.

BOOL CToolBandObj::RegisterAndCreateWindow(){    RECT rectClientParent;    ::GetClientRect(m_hWndParent, &rectClientParent);    // We need to create an Invisible Child Window using the Parent Window,     // this will also be used to reflect Command    // messages from the rebar    HWND hWndChild = m_wndInvisibleChildWnd.Create(m_hWndParent,                                                    rectClientParent,                                                    NULL, WS_CHILD);        // Now we can create the Tool Bar, using the Invisible Child    DWORD dStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |                    CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN |                    TBSTYLE_TOOLTIPS | TBSTYLE_FLAT;        HWND hWnd = m_wndToolBar.CreateSimpleToolBarCtrl(hWndChild,

                                                     IDR_TOOLBAR_TEST,                                                      FALSE, dStyle);     m_wndToolBar.SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);              m_wndToolBar.m_ctlBandEdit.m_pBand = this;    return ::IsWindow(m_wndToolBar.m_hWnd);}

The following Macros are used to identify the reflected messages from the ordinary messages. e.g WM_COMMAND reflected comes back as OCM_COMMAND.

#define OCM_COMMAND_CODE_HANDLER(code, func) \if(uMsg == OCM_COMMAND && code == HIWORD(wParam)) \{ \    bHandled = TRUE; \    lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \    if(bHandled) \    return TRUE; \}#define OCM_COMMAND_ID_HANDLER(id, func) \if(uMsg == OCM_COMMAND && id == LOWORD(wParam)) \{ \    bHandled = TRUE; \    lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \    if(bHandled) \    return TRUE; \}#define OCM_NOTIFY_CODE_HANDLER(cd, func) \if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \{ \    bHandled = TRUE; \    lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \    if(bHandled) \    return TRUE; \}

Browser Navigation

In order to Navigate on the browser you need to instantiate the IWebBrowser2 COM Object. This is usually done on the SetSite Method e.g.

IServiceProviderPtr pServiceProvider = pUnkSite;if (_Module.m_pWebBrowser)    _Module.m_pWebBrowser = NULL; if(FAILED(pServiceProvider->QueryService(SID_SWebBrowserApp, IID_IWebBrowser,                                             (void**)&_Module.m_pWebBrowser)))return E_FAIL;

Once you have the COM Object Instantiated, you can move to your URL using the navigate method

	_variant_t varURL = _bstr_t(www.codeproject.com); _variant_t varEmpty;_Module.m_pWebBrowser->Navigate2(&varURL, &varEmpty, &varEmpty,                                     &varEmpty, &varEmpty);

Drag and Drop Edit and ComboBox Control

The CBandEditCtrl class is inherited from a WTL CEdit control that has drag and drop facility. i.e. you can drag text from the browser straight to the CEdit Control.

The CBandComboBoxCtrl class is inherited from a WTL CComboBox control that has drag and drop facility. i.e. you can drag text from the browser straight to the CComboBox Control.

Drag and Drop URL - toolband2.gif

The Edit control in this sample module allows you to drag a URL from Explorer or any other Dragable enabled container. Once you have dropped the URL the toolband will go to that site.

Configurable Toolbar Button Styles

The CBandToolBarCtrl class allows you to have the follwoing button styles on the toolbar

  • Image and Text on the right
  • Image and Text on the bottom
  • Image only

Text on Right - toolband3.gif

No Text - toolband4.gif

Text Under - toolband5.gif

Pop-up Menu Tracking

A pop up menu is used to get to the configuration options

Popup Menu Tracking - toolband6.gif

ToolTips

This has been taken from MSDN to explain why you need to handle the tooltips on the toolbar your self.

Tool tips are automatically displayed for buttons and other controls contained in a parent window derived from CFrameWnd. This is because CFrameWnd has a default handler for the TTN_GETDISPINFO notification, which handles TTN_NEEDTEXT notifications from tool tip controls associated with controls.

However, this default handler is not called when the TTN_NEEDTEXT notification is sent from a tool tip control associated with a control in a window that is not a CFrameWnd, such as a control on a dialog box or a form view. Therefore, it is necessary for you to provide a handler function for the TTN_NEEDTEXT notification message in order to display tool tips for child controls.

This can be easily done in WTL by using the following Message Handler in the overriden ToolBar Control

NOTIFY_CODE_HANDLER(TTN_NEEDTEXT, OnToolbarNeedText)

The following is the code that loads the tool tips from the resources and sets the tool tip text.

LRESULT CBandToolBarCtrl::OnToolbarNeedText(int /*idCtrl*/, LPNMHDR pnmh, BOOL&                                             bHandled)	{    CString sToolTip;        //-- make sure this 1is not a seperator    if (idCtrl != 0)     {        if (!sToolTip.LoadString(idCtrl))        {            bHandled = FALSE;            return 0;        }    }    LPNMTTDISPINFO pttdi = reinterpret_cast<LPNMTTDISPINFO>	    (pnmh);pttdi->lpszText = MAKEINTRESOURCE(idCtrl);    pttdi->hinst = _Module.GetResourceInstance();    pttdi->uFlags = TTF_DI_SETITEM;    //-- message processed    return 0;}

Update the Status Bar

You can update the status bar using the browser method put_StatusText, this method can be used typically in the WM_MENUSELECT event

The following is the code that loads up the menu text from the resources and displays it on the browser status bar.

Collapse
LRESULT CBandToolBarCtrl::OnMenuSelect(UINT /*uMsg*/,                                        WPARAM wParam, LPARAM lParam,                                        BOOL& bHandled) {    WORD nID = LOWORD(wParam);    WORD wFlags = HIWORD(wParam);        //-- make sure this is not a seperator    CString sStatusBarDesc;    if ( !(wFlags & MF_POPUP) )    {        if (nID != 0)         {            if (!sStatusBarDesc.LoadString(nID))            {	        bHandled = FALSE;                return 0;            }            int nPos = sStatusBarDesc.Find(_T("\n"));            if (nPos != -1)            {                sStatusBarDesc =                 sStatusBarDesc.Left(nPos+1);                _Module.m_pWebBrowser->                put_StatusText(_bstr_t(sStatusBarDesc));                return 0;            }        }    }    return 0;}

How to add a Chevron to your toolband

In order to add a chevron to your toolband you need to add the DBIMF_USECHEVRON flags to your GetBandInfo method in the DBIM_MODEFLAGS mask.

 ... if(pdbi->dwMask == DBIM_MODEFLAGS)     {         //AddChevron        pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT |                                   DBIMF_USECHEVRON | DBIMF_BREAK;    }...

This basically add the ability to show the chevron, if you want to see it appear on your toolband, then you must make sure the pdbi->ptMinSize.x value is less then your pdbi->ptActual.x value (Again this values can be set in the GetBandInfo method.

In order to handle the events of the button in the chevron menu, you must subclass the rebar control which is hosting your toolbar. The following steps have been used to sublass the rebar control

1. Find the rebar control – This can be achieved by getting the browsers window handle and searching for all its child , until you find the rebar control.

2. Once you have found the rebar control you can simply subclass it using an ATL CContainedWindow.

    BOOL CBandToolBarCtrl::SetBandRebar()    {         HWND hWnd(NULL);        _Module.m_pWebBrowser->get_HWND((long*)&hWnd);         if (hWnd == NULL) 	    return FALSE;	m_ctlRebar.m_hWnd = FindRebar(hWnd);	if (m_ctlRebar.m_hWnd == NULL) 	    return FALSE;	m_RebarContainer.SubclassWindow(m_ctlRebar);	return TRUE;    }

Once you have subclass the window, the events should reach the toolbar class.

Append to the Browser Context Menu

Sample Image - toolband11.gif

I tried to duplicate the and codeproject toolband right mouse browser context menu searches without any luck, until I looked at the binary resources, I found that you can extend the internet explorer menu by adding the option in the registry. This can easily be achieved by adding an entry in your .rgs file.

HKCU{    NoRemove Software    {        NoRemove Microsoft        {            NoRemove 'Internet Explorer'            {                NoRemove MenuExt                {                    ForceRemove '&Sample Toolband Serach' = s'res://%MODULE%/MENUSEARCH.HTM'                    {                        val Contexts = b '10'                    }                }            }        }    }}

Note the value of the registry item (a script that exist in the resources of the module).

see MENUSERACH.HTM under HTML in the module resource to see what the script is doing

01

Internet Explorer Toolbar (Deskband) Tutorial


转至http://www.codeproject.com

The Motley Fool Quote IE Toolbar

Introduction

Having recieved a number of requests for a tutorial of sorts on developing Internet Explorer Toolbars with the RBDeskband and CWindowImpl wizards that I created, I have come up with a simple sample which can be used as a reference when developing your own toolbars or explorer bars. The tutorial will walk you through the stages of developing a for that is very similar to the Address bar that is already present in . I wanted to do a tutorial that would provide a realistic sample and would produce an end result that could be used by others after the tutorial was finish. So, the tutorial is going to show you how to develop an toolbar to get stock quote information from The Motley Fool website. So with that, let us get started.

Prequisites

This tutorial assumes that you already know how to program in C++ and know some information about ATL and COM. To work through this tutorial, you will need the following installed on your development machine:

  • Visual C++6 installed
  • RBDeskBand ATL Object Wizard (Version 2.0) [get it here]
  • CWindowImpl ATL Object Wizard [get it here]

The Framework

The IE toolbar consists of a COM component supporting IDeskband and a few other necessary interfaces for which IE looks for when loading registered toolbars, explorer bars and deskbands. The RBDeskband ATL Object Wizard provides most of the framework for this article. What we will need to do is create our project, a new COM object to house our toolbar, and a few CWindowImpl classes using the CWindowImpl ATL Object Wizard. Then connecting these parts together we will produce the IE toolbar in the picture at the top of the article. Visually the toolbar consists of an editbox and a toolbar with one button on it. In actuality the toolbar consists of the fore mentioned and a non visible window that is used to reflect messages to the Toolbar window, which will process or forward messges to itself and the edit box.

Creating The

We will not work through the steps in creating the shell for our toolbar.

Creating The Project

  • If you have not done so already, start Visual C++6.
  • Then, from the File menu select New menu item; the New Dialog pops up.
  • In the New Dialog, select the Projects tab, if not already selected.
  • Select ATL COM AppWizard from the list view, if not already selected.
  • In the Project name, type "MotleyFool". See Figure 1.
  • Click the OK Button.

Figure 1. New Dialog.
Figure 1. New Dialog.
  • The ATL COM AppWizard will kick in.
  • Clicking the Finish Button, accepting the default AppWizard attributes. See Figure 2.
  • The New Project Information Dialog will present itself requesting confirmation of your project settings.
  • Click the OK Button.

Figure 2. ATL COM AppWizard
Figure 2. ATL COM AppWizard.

Creating The DeskBand Object

Now that we have our project container we need to add our IDeskBand derived component so that the DLL actually exposes something.

  • From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked.
  • In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed.
  • Next select the DeskBand item from the Objects list.
  • Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3.
  • On the Names property page, type "StockBar" into the Short Name field. See Figure 4.
  • Select the DeskBand ATL Object Wizard property page
  • Check the Internet Explorer Toolbar checkbox. See Figure 5.
  • Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our DeskBand’s base implementation.

Figure 3. ATL Object Wizard.
Figure 3. ATL Object Wizard.
Figure 4. ATL Object Wizard Properties - Names.
Figure 4. ATL Object Wizard Properties – Names.
Figure 5. ATL Object Wizard Properties - DeskBand ATL Object Wizard.
Figure 5. ATL Object Wizard Properties – DeskBand ATL Object Wizard

Now our project has the DeskBand implementation that we will modify to produce the toolbar pictured at the top of the article. First we will create the window classes we will need and then come back to the Desbkand object and update it to use our window classes.

Creating The Window Classes

So back in the Framework section we said that we would need three window classes. One for the Edit Box, one for the toolbar, and one for message reflection back to the toolbar. Let us now create these window classes.

The Edit Window

We need to create a derived from the standard EDIT button window because we are going to be adding methods to our to help support functionality of the toolbar. This is one reason why we cannot use a CContainedWindow object directly.

  • From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked.
  • In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed.
  • Next select the CWindowImpl item from the Objects list.
  • Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3.
  • On the Names property page, type "EditQuote" into the Short Name field.
  • Select the CWindowImpl property page. See Figure 6.
  • Select the SUPERCLASS radio button from the DECLAR_WND_* group.
  • In the Window Class Name field, type "EDITQUOTE".
  • In the Original Class Name list, select the EDIT listbox item. See Figure 7.
  • Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our CWindowImpl derived class implementation.

Figure 6. ATL Object Wizard Properties - Names.
Figure 6. ATL Object Wizard Properties – Names.
Figure 7. ATL Object Wizard Properties - Names.
Figure 7. ATL Object Wizard Properties – CWindowImpl.

The Toolbar Window

We need to create a derived class from the standard TOOLBARCLASSNAME window class because we are going to be adding methods to our class to help support functionality of the toolbar. It will also be the parent for the edit box and the window which the IE host will request from our DeskBand.

  • From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked.
  • In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed.
  • Next select the CWindowImpl item from the Objects list.
  • Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3.
  • On the Names property page, type "MFToolbar" into the Short Name field.
  • Select the CWindowImpl property page. See Figure 8.
  • Select the SUPERCLASS radio button from the DECLAR_WND_* group.
  • In the Window Class Name field, type "MOTLEYFOOLTOOLBAR".
  • In the Original Class Name list, select the TOOLBARCLASSNAME listbox item. See Figure 9.
  • Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our CWindowImpl derived class implementation.

Figure 8. ATL Object Wizard Properties - Names.
Figure 8. ATL Object Wizard Properties – Names.
Figure 9. ATL Object Wizard Properties - Names.
Figure 9. ATL Object Wizard Properties – CWindowImpl.

The Reflection Window

We need to create a reflection window. It’s just a CWindowImpl window implmented class. We are going to be adding a small bit of functionality just to create the toolbar object and be able to access the toolbar member from our deskband class.

  • From the Insert menu, select New ATL Object menu item; the ATL Object Wizard dialog is invoked.
  • In the ATL Object Wizard dialog, select the RadBytes Category. If this category is missing then make sure that the RBDeskband and CWindowImpl ATL Object Wizards are installed.
  • Next select the CWindowImpl item from the Objects list.
  • Click the Next button to invoke the ATL Object Wizard Properties dialog for the Deskband object. See Figure 3.
  • On the Names property page, type "ReflectionWnd" into the Short Name field. See Figure 10.
  • We will not change any of the CWindowImpl property page values this time.
  • Click the OK button on the ATL Object Wizard Properties Dialog. The ATL Object Wizard will create the files necessary for our CWindowImpl derived class implementation.

Figure 10. ATL Object Wizard Properties - Names.
Figure 10. ATL Object Wizard Properties – Names.

Adding The Details

Now that we have our window classes available we can add our functionality for our toolbar to the appropriate window classes. Let us start with the deepest window class and work our way back out.

The EditQuote Details

For the EditQuote implementation, we need to be able to process keystrokes from the user and let the host that created our deskband object know our edit box has focus. To accomplish the first part, we need to look ahead and see that our DeskBand object will be implementing the IInputObject interface. So the host will query for that interface and know that we want to recieve messages and be given the chance to recieve focus. When the host sends our band messages to process they come through the IInputObject::TranslateAccelerator method. Our DeskBand will implement this method and it is best if our edit box, which will process the message, copy the TranslateAcceleratorIO method definition so our deskband can forward the message easily through a logical method call.

Figure 11. FileView Pane.
Figure 11. FileView Pane.

In the FileView pane (See Figure 11), double click the EditQuote.h item under Header Files. This will open the header file in the editing area. We now need to define the method definition for TranslateAcceleratorIO. To do this, add below the virtual CEditQuote destructor the following line of code:

STDMETHOD(TranslateAcceleratorIO)(LPMSG lpMsg);

Now Open the EditQuote.cpp source file and add the implementation of TranslateAcceleratorIO to the file

STDMETHODIMP CEditQuote::TranslateAcceleratorIO(LPMSG lpMsg){   TranslateMessage(lpMsg);   DispatchMessage(lpMsg);   return S_OK;}

Now our DeskBand implementation can call this message and the edit box will process the key strokes properly. But wait, our edit box should notify the toolbar to load the quote details entered if the key stroke is the enter key. For this, we will need to define a message id and send that message to the parent window to process. In the EditQuote.h header file below the include statement, add the definition of our message id as shown below in bold.

#include <commctrl.h>const int WM_GETQUOTE = WM_USER + 1024;			

In our EditQuote.cpp file we will add code to our TranslateAcceleratorIO method to process the enter key. Add the code below in bold to the EditQuote.cpp file.

STDMETHODIMP CEditQuote::TranslateAcceleratorIO(LPMSG lpMsg){   int nVirtKey = (int)(lpMsg->wParam);   if (VK_RETURN == nVirtKey)   {      // remove system beep on enter key by setting key code to 0      lpMsg->wParam = 0;      ::PostMessage(GetParent(), WM_GETQUOTE, 0, 0);      return S_OK;   }   TranslateMessage(lpMsg);   DispatchMessage(lpMsg);   return S_OK;}

Now our edit box will notify the parent when the user presses the enter key so that the parent can retrieve the requested ticker symbol details, this part will be implemented when we get to the toolbar details.

The first part of the Edit boxes implementation is finished. Now we need to be able for the edit box to have the deskband notify the host that we have focus or that we don’t have focus any longer. To do this we will need to add a method for the deskband to pass us it’s address so that we can call a method of the deskband class. These next steps will involve adding code to the CEditQuote class and to our Deskband class implementation.

Open the EditQuote.h file and add a forward reference to the CStockBar class so that we can defined our methods and members in our class header without knowing the implementation details of our deskband class, add the line in bold.

#include <commctrl.h>const int WM_GETQUOTE = WM_USER + 1024;class CStockBar;

For our class to notify the host that our deskband has focus, we need to add a message handler for EN_SETFOCUS. Add the command code handler code below in bold to your EditQuote.h file.

   BEGIN_MSG_MAP(CEditQuote)      COMMAND_CODE_HANDLER(EN_SETFOCUS, OnSetFocus)   END_MSG_MAP()

Then add the method definition for OnSetFocus to the header file below the commented out handler prototypes as follows below in bold.

// Handler prototypes:// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);   LRESULT OnSetFocus(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);

Before we implement the OnSetFocus method, we need to define a method for our deskband to tells of it’s address and to retain that address for later use. Add the following lines of code to your EditQuote.h file below the TranslateAcceleratorIO definition.

   void SetBand(CStockBar* pBand);private:   CStockBar* m_pBand;

Now we can move to your EditQuote.cpp source file and implement the message handler, the SetBand method, and update the TranslateAcceleratorIO method for focus change. At the top of the EditQuote.cpp file add the following includes to the include list as shown below in bold.

#include "stdafx.h"#include "EditQuote.h"#include "MotleyFool.h"#include "StockBar.h"

Now when we can use the methods of the CStockBar class in our code. Add to the end of the constructor, the initalization of m_pBand. Don’t forget the colon operator.

CEditQuote::CEditQuote(): m_pBand(NULL){}

Next we will add the SetBand implementation to our CEditQuote class. Notice that since it is not a com object we don’t call AddRef or Release on it. It’s just a pointer to the class and when it’s destroyed our CEditQuote instance will also be destroyed. We could have also done this inline in our header file.

void CEditQuote::SetBand(CStockBar* pBand){   m_pBand = pBand;}

Next we need to add our message handler for our EN_SETFOCUS message. Add the code below to the end of the EditQuote.cpp source file.

LRESULT CEditQuote::OnSetFocus(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled){   //Notify host that our band has the focus so TranslateAcceleratorIO    //messages are directed towards our band.   if (m_pBand) m_pBand->FocusChange(TRUE);   return 0;}

We have one more section of code to add to our CEditQuote implementation then we can move to our CStockBar class to define and implement the FocusChange method. Add the following code to the CEditQuote TranslateAcceleratorIO method as shown in bold. We add this code so the host knows that we are no longer needing messages.

STDMETHODIMP CEditQuote::TranslateAcceleratorIO(LPMSG lpMsg){   int nVirtKey = (int)(lpMsg->wParam);   if (VK_RETURN == nVirtKey)   {      // remove system beep on enter key by setting key code to 0      lpMsg->wParam = 0;      ::PostMessage(GetParent(), WM_GETQUOTE, 0, 0);      return S_OK;   }   else if (WM_KEYDOWN == lpMsg->message && nVirtKey == VK_TAB)   {      // we no longer need messages forwarded to our band      if (m_pBand) m_pBand->FocusChange(FALSE);      return S_FALSE;   }   TranslateMessage(lpMsg);   DispatchMessage(lpMsg);   return S_OK;}

Open the StockBar.h header file and add the definition of FocusChange to it as shown below in bold.

// IStockBarpublic:   void FocusChange(BOOL bHaveFocus);

Now open the StockBar.cpp source file and add the implementation of FocusChange to it at the bottom.

void CStockBar::FocusChange(BOOL bHaveFocus){   if (m_pSite)   {      IUnknown* pUnk = NULL;      if (SUCCEEDED(QueryInterface(IID_IUnknown, (LPVOID*)&pUnk)) && pUnk != NULL)      {         m_pSite->OnFocusChangeIS(pUnk, bHaveFocus);         pUnk->Release();         pUnk = NULL;      }   }}

We have finished off the work needed for the edit box to work properly in our toolbar. Now we need to build our toolbar up so that it has a button and contains our edit box. Then we will add the nessecities to our reflection window and update our IDeskBand to provide the correct information to our host. We are almost there. If you were to compile the project and run it, it would except that the band would look like the following in figure X.

The MFToolbar Details

For the implementation of the MFToolbar window, we need to be able to have it do the following things. It must be able to process the WM_GETQUOTE message from the EditQuote window, communicate with the browser in which the toolbar is located, create the buttons and place the child on itself, forward messages to the EditQuote child window and size itself appropriately to the users actions.

So, the first thing we should do since our toolbar is going to contain an instance of CEditQuote is include the header file for the CEditQuote class. We will do this by opening the MFToolbar.h file and inserting the include statement for the CEditQuote class as shown in bold below.

#include <commctrl.h>#include "EditQuote.h"		

Next we need to add a member to our toolbar class for the CEditQuote class. We will do this by adding a private section to the end of our class and defining a member variable as shown below in bold.

   CMFToolbar();   virtual ~CMFToolbar();private:   CEditQuote m_EditWnd;

Now that we have our member defined for our EditQuote window, we need to forward window messages to it so that keyboard inputs are processed appropriately. We do this by updating the toolbar message map to chain messages to our member as shown below in bold.

   BEGIN_MSG_MAP(CMFToolbar)      CHAIN_MSG_MAP_MEMBER(m_EditWnd)   END_MSG_MAP()

Looking forward, our deskband will need to get the EditQuote member to deterimine if it has focus and also to make it function. We could just expose the EditQuote member directly by having made it a public member instead of private, but by making it private we can expose a method that will expose our member giving us flexibility later to modify the class if the need should arise. So to expose the EditQuote member, we will add a fuction to our toolbar class to return the reference to the EditQuote member. In the toolbar header file, add the method definition and implementation below in bold to it.

   CMFToolbar();   virtual ~CMFToolbar();   inline CEditQuote& GetEditBox() {return m_EditWnd;};

Now we will create our toolbar window. Our toolbar consists of the EditQuote box and a button with an icon and text on it. To house the icon, our toolbar will need an image list handle to send to the toolbar window. So we need to add a few things to our toolbar header file before we go and implement the toolbar’s creation. The first thing we will add is the member variable for our image list. Add the line in bold below to your toolbar header file.

private:   CEditQuote m_EditWnd;   HIMAGELIST m_hImageList;

Then we will add a message handler to our toolbar’s message map and define the message handlers function definition to our header file and the follow lines of code in bold to your header file.

   BEGIN_MSG_MAP(CMFToolbar)      CHAIN_MSG_MAP_MEMBER(m_EditWnd)      MESSAGE_HANDLER(WM_CREATE, OnCreate)   END_MSG_MAP()// Handler prototypes://  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);   LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

Before we can implement our toolbar’s creation, we need to create a icon resource that our toolbar button will use next to its text. So go to the resource view and add a new icon to the project resources. You can do this by right clicking on "MotleyFool resources" and selecting "Insert…" from the context menu. In the Insert Resource dialog box, select Icon from the Resource type list and click the New button. This will insert a blank icon resource into your project. Rename the icon’s resource ID by right clicking on the icon resource in the resource view and selecting the properties menu item from the context menu. Change the id to IDI_MOTLEY. Then draw or graciously borrow an icon from The Motley Fool to use on the toolbar. I graciously borrowed the icon from their website and adapted it into the icon.

Now we can implement it our toolbars creation. Open the MFToolbar source file and implement the details of the toolbar creation as described below.

First we need to include the project resource file so we can use the icon ID in our code. Add the line in bold below to our toolbar’s source file as shown.

#include "stdafx.h"#include "resource.h"#include "MFToolbar.h"

Next we need to update our constructor implementation. We need to initialize our handle to the image list by setting it to NULL. Don’t forget the colon.

CMFToolbar::CMFToolbar(): m_hImageList(NULL){}

Next we need to update our destructor, it should destroy the image list and destroy the window if it has not yet been destroyed.

CMFToolbar::~CMFToolbar(){   ImageList_Destroy(m_hImageList);   if (IsWindow()) DestroyWindow();}

Before we can implement our toolbar’s creation, we need to add a resource symbol to our project for the toolbar button’s ID. We could just use a #define statement at the top of the source file, but for cleanliness and since we are already including the resource.h file, we will add it to our resource file. Go to the "View" menu and select "Resource Symbols" menu item. Click the "New" button on the Resource Symbols dialog. Then enter a name of "IDM_GETQUOTE" and click OK. Then close the Resource Symbols dialog.

Now we can create our toolbar, we defined the OnCreate method in our header file and need to now implement it. Add the following function and its implementation to the end of the toolbar source file.

Collapse
LRESULT CMFToolbar::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){   // buttons with images and text   SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, (LPARAM)TBSTYLE_EX_MIXEDBUTTONS);   // Sets the size of the TBBUTTON structure.   SendMessage(m_hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);   // Set the maximum number of text rows and bitmap size.   SendMessage(m_hWnd, TB_SETMAXTEXTROWS, 1, 0L);   // add our button's caption to the toolbar window   TCHAR* pCaption = _T("Get Quote");   int iIndex = ::SendMessage(m_hWnd, TB_ADDSTRING, 0,(LPARAM)pCaption);   // load our button's icon and create the image list to house it.   HICON hMotley = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_MOTLEY));   m_hImageList = ImageList_Create(16,16, ILC_COLOR16, 1, 0);   int iImageIndex = ImageList_AddIcon(m_hImageList, hMotley);   DestroyIcon(hMotley);   // Set the toolbar's image   ::SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)m_hImageList);   // add the button for the toolbar to the window   TBBUTTON Button;   ZeroMemory((void*)&Button, sizeof(TBBUTTON));   Button.idCommand = IDM_GETQUOTE;   Button.fsState = TBSTATE_ENABLED;   Button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT;   Button.dwData = 0;   Button.iString = iIndex;   Button.iBitmap = 0;   ::SendMessage(m_hWnd, TB_INSERTBUTTON, 0, (LPARAM)&Button);   // create our EditQuote window and set the font.   RECT rect = {0,0,0,0};   m_EditWnd.Create(m_hWnd, rect, NULL, WS_CHILD|WS_VISIBLE, WS_EX_CLIENTEDGE);   m_EditWnd.SetFont(static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT)));   return 0;}

If you try to compile at this point, you will see that there are unresolved externals for the image list method calls. We need to add a library to the project. To do this select the "Project|Settings" menu item. On the Project Settings dialog, Select All Configurations from the "Settings For" combo box. Then select the "Link" tab and append to the "Object/Library modules" edit box "comctl32.lib". Then click OK. If you compile the project now, it will compile successfully and the image list unresolved externals will disappear.

We still have a few things we need to do to the Toolbar window. It needs to process Command messages, resopnd to WM_GETQUOTE messages, and resize itself. Let’s conquer the latter first.

To orgainze the tooblar correctly, we should have the toolbar responsd to WM_SIZE messages. To do this, we will add to our tooblar header file a message handler for the WM_SIZE message and add a function definition for OnSize which WM_SIZE messages will be sent to. Open our toolbar header file and add the lines in bold below to it as shown.

   BEGIN_MSG_MAP(CMFToolbar)      CHAIN_MSG_MAP_MEMBER(m_EditWnd)      MESSAGE_HANDLER(WM_CREATE, OnCreate)      MESSAGE_HANDLER(WM_SIZE, OnSize)   END_MSG_MAP()// Handler prototypes://  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);   LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);   LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

Now we need to implement our OnSize function. Open the toolbar source file and add the function implementation below to the end of the file.

Collapse
LRESULT CMFToolbar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){   // based on the size of the window area minus the size of the toolbar button,    // indent the toolbar so that we can place the edit box before the toolbar    // button. This will right justify the toolbar button in the toolbar and the    // edit box will use the vaction space to the left of the button but after the    // toolbar text as it's usable space.   RECT wndRect, btnRect;   GetClientRect(&wndRect);   ::SendMessage(m_hWnd, TB_GETITEMRECT, 0, (LPARAM)&btnRect);   wndRect.right -= (btnRect.right - btnRect.left);   SendMessage(TB_SETINDENT, wndRect.right - wndRect.left);   // put a small spacing gap between the edit box's right edge and the toolbar button's left edge   wndRect.right -= 3;   m_EditWnd.MoveWindow(&wndRect, FALSE);   return 0;}

We still need to respond to user input for the toolbar button and from the edit box when the user presses the enter key. What we want the toolbar to do is tell the web browser host to navigate to the motely fool website and retrieve the stock quotes requested. First we need for the Deskband object to tell our toolbar window what the web browser instance is so that the toolbar window can communicate with it. To do this, we will add a private member variable and a public method in which the deskband can set the web browser instance. Our window will then use the member variable set to tell the web browser where to navigate and what to retrieve.

To do this, open the toolbar header file and add the lines in bold to the file.

   CMFToolbar();   virtual ~CMFToolbar();   inline CEditQuote& GetEditBox() {return m_EditWnd;};   void SetBrowser(IWebBrowser2* pBrowser);private:   CEditQuote m_EditWnd;   HIMAGELIST m_hImageList;   IWebBrowser2* m_pBrowser;

Now, open the toolbar source file. We will update the constructor and initialize our member variable to null. Then we will update the toolbar destructor and release the member variable if it hasn’t been. Then we will implement the SetBrowser method.

Initialize the web browser member variable.

CMFToolbar::CMFToolbar(): m_hImageList(NULL), m_pBrowser(NULL){}

Release the web browser object if held.

CMFToolbar::~CMFToolbar(){   ImageList_Destroy(m_hImageList);   SetBrowser(NULL);   if (IsWindow()) DestroyWindow();}

Implement SetBrowser()

void CMFToolbar::SetBrowser(IWebBrowser2* pBrowser){   if (m_pBrowser) m_pBrowser->Release();   m_pBrowser = pBrowser;   if (m_pBrowser) m_pBrowser->AddRef();}

If you try and compile the project, you will notice that IWebBrowser2 is undefine in our header file. This is because we need to update our stdafx.h header file to include system files that define IWebBrowser2. To do this, open stdafx.h and add the following lines in bold to the file, then recompile.

extern CComModule _Module;#include <atlcom.h>#include <atlwin.h>//// These are needed for IDeskBand//#include <shlguid.h>#include <shlobj.h>

Now we can add message handlers for WM_COMMAND and WM_GETQUOTE to our toolbar class to handle the toolbar button being pressed and the enter key being pressed in the edit box by the user. To do this, we will need to add to our toolbar header file message handlers and function definitions for WM_COMMAND and WM_GETQUOTE. We will also need to add a private method which both will call if they need to to preform the same functionality (better than repeating code that does the same thing). So let’s add the message handlers to the header file.

Collapse
   BEGIN_MSG_MAP(CMFToolbar)      CHAIN_MSG_MAP_MEMBER(m_EditWnd)      MESSAGE_HANDLER(WM_CREATE, OnCreate)      MESSAGE_HANDLER(WM_SIZE, OnSize)      MESSAGE_HANDLER(WM_COMMAND, OnCommand)      MESSAGE_HANDLER(WM_GETQUOTE, OnGetQuote)   END_MSG_MAP()// Handler prototypes://  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);   LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);   LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);   LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);   LRESULT OnGetQuote(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

Now we can add the function delcaration for our GetQuote privaet method.

private:   CEditQuote m_EditWnd;   HIMAGELIST m_hImageList;   IWebBrowser2* m_pBrowser;   void GetQuote();

Now let’s switch to our source file and implement our message handler functions and the GetQuote method. Add the code below to the end of the toolbar source file.

Collapse
LRESULT CMFToolbar::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){   if (!HIWORD(wParam))   {      long lSite = LOWORD(wParam);      if ( lSite == IDM_GETQUOTE)      {         GetQuote();         return 0;      }   }   return -1;}LRESULT CMFToolbar::OnGetQuote(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){   GetQuote();   return 0;}void CMFToolbar::GetQuote(){   // if we have a web browser pointer then try to navigate to The Motley Fool site to retrieve stock quotes.   if (m_pBrowser)   {      VARIANT vEmpty;      VariantInit(&vEmpty);      m_pBrowser->Stop();      _bstr_t bsSite;      // if the user has entered stock quotes then append them to the url      if (m_EditWnd.GetWindowTextLength())      {         BSTR bstrTickers = NULL;         m_EditWnd.GetWindowText(&bstrTickers);         bsSite = "http://quote.fool.com/news/symbolnews.asp?Symbols=";         bsSite += bstrTickers;         SysFreeString(bstrTickers);      }      // if the user has not entered any stock quotes then just take them to The Motley Fool website.      else         bsSite = "http://www.fool.com";      // have the webrowser navigate to the site URL requested depending on user input.      m_pBrowser->Navigate(bsSite, &vEmpty, &vEmpty, &vEmpty, &vEmpty);   }}

If you try to compile, you will notice that _bstr_t is undefined. That is because the class is defined in comdef.h. We need to add this to our stdafx.h header file so that we can use it as well as any other class in our project (which we will need to for IInputObject). Open the stdafx.h header file and add the lines in bold to the file as indicated.

#include <shlobj.h>// needed for IInputObject and _bstr_t#include <comdef.h>

Our implementation of the toolbar window is complete. Now we can move on to the Reflection window which creates our toolbars and forwards command messages to it.

The Reflection Window Details

For the Reflection Window, it’s only purpose is to create the toolbar window (which it doesn’t need to really do, but by doing so eases message forwarding) and forward messages to it. The reflection window is not visible, it’s just a layer added so that message from the toolbar get to the toolbar. If we didn’t have this window present, toolbar messages would get sent to the parent window (which we do not control) and we would never get them. This is not good since we need to respond to WM_COMMAND messages from the toolbar. Thus the need for the reflection window. So let’s create the toolbar window and the message forwarding for it.

Open the ReflectionWnd.h header file. We will need to include the toolbar header file and add a private member variable to our reflection window to create it and to pass it to the message chain. First things first, add the include statement below so we can use the CMFToolbar class.

#include <commctrl.h>#include "MFToolbar.h"

Next add a private member variable to the end of the reflection window class for the toolbar as shown below.

	CReflectionWnd();   virtual ~CReflectionWnd();private:   CMFToolbar m_ToolbarWnd;

Next update the reflection window message map to forward messages to the toolbar window as shown below.

   BEGIN_MSG_MAP(CReflectionWnd)      CHAIN_MSG_MAP_MEMBER(m_ToolbarWnd)   END_MSG_MAP()

We will also need a public function for our deskband class to get at our toolbar window. We will do the same as we did with the EditQuote window by providing a function to get at the member variable indirectly. Add the line of code in bold below to the header file as indicated.

   CReflectionWnd();   virtual ~CReflectionWnd();   inline CMFToolbar& GetToolBar() { return m_ToolbarWnd;};

Lastly, we need to create the toolbar window and will do so in the WM_CREATE message handler for our reflection window. Add the code below in bold to the reflection window header file. Then we will implement the OnCreate method in the source file.

   BEGIN_MSG_MAP(CReflectionWnd)      MESSAGE_HANDLER(WM_CREATE, OnCreate)      CHAIN_MSG_MAP_MEMBER(m_ToolbarWnd)   END_MSG_MAP()// Handler prototypes://  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);   LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

Now open the ReflectionWnd.cpp source file and add the implementation of OnCreate to its end.

const DWORD DEFAULT_TOOLBAR_STYLE =       /*Window styles:*/ WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | WS_TABSTOP |      /*Toolbar styles:*/ TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_LIST | TBSTYLE_CUSTOMERASE |                          TBSTYLE_WRAPABLE |      /*Common Control styles:*/ CCS_TOP | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE;LRESULT CReflectionWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){   RECT rect;   GetClientRect(&rect);   m_ToolbarWnd.Create(m_hWnd, rect, NULL, DEFAULT_TOOLBAR_STYLE);   return 0;}

You will notice that we defined a constant for the toolbar style. This was done to make the code more readable.

The only thing left to do to the reflection window code is update the destructor to destory the window if it’s still present.

CReflectionWnd::~CReflectionWnd(){   if (IsWindow()) DestroyWindow();}

 

Finishing Off The Deskband Toolbar

All that’s left is for our deskband to create the toolbar window, have the host use the toolbar window, remove the unused IPersistStream implementation, implement IInputObject (for focus control) and do some code tweaking. So lets wrap this toolbar up. Open the StockBar.h header file. Remove the following lines of code that are in bold since we moved them to our stdafx.h for our other classes to also use.

#include "resource.h"       // main symbols//// These are needed for IDeskBand//#include <shlguid.h>#include <shlobj.h>

Next remove the following line from the class delcaration.

public IPersistStream,

The top of the class declaration should now look like this,

class ATL_NO_VTABLE CStockBar :    public CComObjectRootEx<CComSingleThreadModel>,   public CComCoClass<CStockBar, &CLSID_StockBar>,   public IDeskBand,   public IObjectWithSite,   public IDispatchImpl<IStockBar, &IID_IStockBar, &LIBID_MOTLEYFOOLLib>{

Next scroll down to the COM Map and remove the following two lines of code,

   COM_INTERFACE_ENTRY(IPersist)   COM_INTERFACE_ENTRY(IPersistStream)

Your COM Map should now look like this,

BEGIN_COM_MAP(CStockBar)   COM_INTERFACE_ENTRY(IStockBar)   COM_INTERFACE_ENTRY(IOleWindow)   COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow)   COM_INTERFACE_ENTRY(IObjectWithSite)   COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)   COM_INTERFACE_ENTRY(IDispatch)END_COM_MAP()

Scroll down the header file further and remove the sections of function declarations for IPersist and IPersistStream, which includes the following lines.

// IPersistpublic:   STDMETHOD(GetClassID)(CLSID *pClassID);// IPersistStreampublic:   STDMETHOD(IsDirty)(void);   STDMETHOD(Load)(IStream *pStm);   STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty);   STDMETHOD(GetSizeMax)(ULARGE_INTEGER *pcbSize);

There should now be nothing related to IPersist or IPersistStream between the IDockingWindow and IStockBar function declaration sections.

Now we need to remove the IPersist and IPersistStream function implementations from the StockBar.cpp source file. Find the GetClassID, IsDirty, Load, Save, and GetSizeMax function implementations and remove them from the file. They should be directly above the FocusChange Method we added earlier.

Now we can start adding code to our deskband. Open the stockbar.h header file and add the include for the reflection window class as shown below in bold.

#include "resource.h"       // main symbols#include "ReflectionWnd.h"

Next, find the protected section at the end of the file and replace the line

   HWND m_hWnd;

with

   CReflectionWnd m_ReflectWnd;

If you try to compile, you will find that it will be unsuccessful since we have removed m_hWnd and have not removed all occurances of m_hWnd from the class source file. We will replace all occurances with more appropriate code for our Reflection window and toolbar window. Open the StockBar.cpp source file, Remove the following line from the class constructor

   m_hWnd(NULL),

your class constructor should now look as follows with a SetBand call added,

CStockBar::CStockBar():    m_dwBandID(0),    m_dwViewMode(0),    m_bShow(FALSE),    m_bEnterHelpMode(FALSE),    m_hWndParent(NULL),    m_pSite(NULL){	m_ReflectWnd.GetToolBar().GetEditBox().SetBand(this);}

Next, update the RegisterAndCreateWindow function by replacing the temporary m_hWnd construction with the Reflection Window construction. Your RegisterAndCreateWindow implementation should look as follows:

BOOL CStockBar::RegisterAndCreateWindow(){   RECT rect;   ::GetClientRect(m_hWndParent, &rect);   m_ReflectWnd.Create(m_hWndParent, rect, NULL, WS_CHILD);   // The toolbar is the window that the host will be using so it is the window that is important.   return m_ReflectWnd.GetToolBar().IsWindow();}

As we scroll through the code, we should fix some other things. A toolbar has a default height of 22 so we need to update our GetBandInfo method so that all the y measurements are 22 not 20. We also want our Integral sizing to be non sizeable so we need to set the DBIM_INTEGRAL x and y values to 0. While we are at it, we should fix the title of our toolbar so it says "The Motley Fool". You’ll find this constant defined near the top of the source file, update it now.

We will now update the GetWindow call so that the toolbar window handle is returned and not the invalid m_hWnd variable. Update your GetWindow method so it looks as follows,

STDMETHODIMP CStockBar::GetWindow(HWND* phwnd){   HRESULT hr = S_OK;   if (NULL == phwnd)   {      hr = E_INVALIDARG;   }   else   {      *phwnd = m_ReflectWnd.GetToolBar().m_hWnd;   }   return hr;}

Now we need to update teh CloseDW method so that it does not destory our window buy hide it. We do this much like the MFC CToolbar class does, the class destructor will destroy the window. Your CloseDW method should look as follows,

STDMETHODIMP CStockBar::CloseDW(unsigned long dwReserved){   ShowDW(FALSE);   return S_OK;}

Working our way through our class implementation, we will update the next method that needs updating. Update the ShowDW class to show or hide the toolbar window which the host is using. Your ShowDW class should look as follows,

STDMETHODIMP CStockBar::ShowDW(BOOL fShow){   m_bShow = fShow;   m_ReflectWnd.GetToolBar().ShowWindow(m_bShow ? SW_SHOW : SW_HIDE);   return S_OK;}

We are almost done modifying the CStockBar class we need to do one last bit of updating. We need to modify the SetSite implementation to release the browser window that the toolbar may be using if we have a IInputObjectSite object and we need to query the OleCommandTarget’s ServiceProvider for the IWebBrowser2 interface which we will then set to our toolbar. The modified parts of the SetSite method implementation are below in bold.

Collapse
STDMETHODIMP CStockBar::SetSite(IUnknown* pUnkSite){//If a site is being held, release it.   if(m_pSite)   {      m_ReflectWnd.GetToolBar().SetBrowser(NULL);      m_pSite->Release();      m_pSite = NULL;   }   //If punkSite is not NULL, a new site is being set.   if(pUnkSite)   {      //Get the parent window.      IOleWindow  *pOleWindow = NULL;      m_hWndParent = NULL;      if(SUCCEEDED(pUnkSite->QueryInterface(IID_IOleWindow, (LPVOID*)&pOleWindow)))      {         pOleWindow->GetWindow(&m_hWndParent);         pOleWindow->Release();      }      if(!::IsWindow(m_hWndParent))         return E_FAIL;      if(!RegisterAndCreateWindow())         return E_FAIL;      //Get and keep the IInputObjectSite pointer.      if(FAILED(pUnkSite->QueryInterface(IID_IInputObjectSite, (LPVOID*)&m_pSite)))      {         return E_FAIL;      }        IWebBrowser2* s_pFrameWB = NULL;      IOleCommandTarget* pCmdTarget = NULL;      HRESULT hr = pUnkSite->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pCmdTarget);      if (SUCCEEDED(hr))      {         IServiceProvider* pSP;         hr = pCmdTarget->QueryInterface(IID_IServiceProvider, (LPVOID*)&pSP);         pCmdTarget->Release();         if (SUCCEEDED(hr))         {            hr = pSP->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID*)&s_pFrameWB);            pSP->Release();            _ASSERT(s_pFrameWB);            m_ReflectWnd.GetToolBar().SetBrowser(s_pFrameWB);            s_pFrameWB->Release();         }      }   }   return S_OK;}

If you try to compile and use the toolbar right now, it will function partially. Tabbing and input control will not work correctly since we have yet to implement IInputObject for our deskband. Let’s do that now since it’s the last bit of code we will write for our simple deskband. You may also notice that the Toolbars context menu and View|Toolbars menus still say CStockBar Class. we will fix this problem in the Finishing Touches section below.

IInputObject Implementation

To get tabbing and input control to work correctly for any deskband is quite simple. You need but to implement IInputObject. The host will query our deskband to see if this interface is implemented and if it is will call the methods to see if we require input focus and let us also process messages from the user through the host. To do this, open the stockbar.h header file. To the stockbar class declaration add the line below in bold,

class ATL_NO_VTABLE CStockBar :    public CComObjectRootEx<CComSingleThreadModel>,   public CComCoClass<CStockBar, &CLSID_StockBar>,   public IDeskBand,   public IObjectWithSite,   public IInputObject,    public IDispatchImpl<IStockBar, &IID_IStockBar, &LIBID_MOTLEYFOOLLib>{

Next scroll down to the COM Map and add an entry for IInputObject as shown below in bold,

BEGIN_COM_MAP(CStockBar)   COM_INTERFACE_ENTRY(IStockBar)   COM_INTERFACE_ENTRY(IInputObject)   COM_INTERFACE_ENTRY(IOleWindow)   COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow)   COM_INTERFACE_ENTRY(IObjectWithSite)   COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)   COM_INTERFACE_ENTRY(IDispatch)END_COM_MAP()

Next add the following section of function declarations to your header file, I placed mine before the IStockBar section.

// IInputObjectpublic:   STDMETHOD(HasFocusIO)(void);   STDMETHOD(TranslateAcceleratorIO)(LPMSG lpMsg);   STDMETHOD(UIActivateIO)(BOOL fActivate, LPMSG lpMsg);

All that remains is to implement these three functions. Add the function implementations below to the end of the stockbar.cpp source file.

Collapse
STDMETHODIMP CStockBar::HasFocusIO(void){   // if any of the windows in our toolbar have focus then return S_OK else S_FALSE.   if (m_ReflectWnd.GetToolBar().m_hWnd == ::GetFocus())      return S_OK;   if (m_ReflectWnd.GetToolBar().GetEditBox().m_hWnd == ::GetFocus())     return S_OK;   return S_FALSE;}STDMETHODIMP CStockBar::TranslateAcceleratorIO(LPMSG lpMsg){   // the only window that needs to translate messages is our edit box so forward them.   return m_ReflectWnd.GetToolBar().GetEditBox().TranslateAcceleratorIO(lpMsg);}STDMETHODIMP CStockBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg){   // if our deskband is being activated then set focus to the edit box.   if(fActivate)   {      m_ReflectWnd.GetToolBar().GetEditBox().SetFocus();   }   return S_OK;}

Our toolbar is functionaly done, compile, run it and see. It works as described and is fairly simple. Let’s put some finishing UI touches on it for IE and our users to use.

Finishing Touches

The are only 2 finishing touches to make, One is to fix the context menu text. The other is to add button support to the main IE toolbar. Let’s do them in order.

To fix the context menu text problem, open the StockBar.rgs project file and change all occurances of "StockBar Class" to "The Motley Fool Quotes". Compile it, run it, and see. While you only need to change one of them, it’s nicer if they all match.

Now let’s add button support for our toolbar. Update the stockbar.rgs file contents by appending the text below to it’s contents.

Collapse
HKLM{   Software   {      Microsoft      {         'Internet Explorer'         {            Extensions            {               ForceRemove	{A26ABCF0-1C8F-46e7-A67C-0489DC21B9CC} = s 'The Motley Fool Quotes'               {                  val BandClsid = s '{A6790AA5-C6C7-4BCF-A46D-0FDAC4EA90EB}'                  val ButtonText = s 'The Motley Fool'                  val Clsid = s '{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}'                  val 'Default Visible' = s 'Yes'                  val 'Hot Icon' = s '%MODULE%,425'                  val Icon = s '%MODULE%,425'                  val MenuStatusBar = s 'The Motley Fool Stock Quote Toolbar'                  val MenuText = s 'The Motley Fool'               }            }         }      }   }}

The replace the 425 with the id from resource.h of IDI_MOTLEY. Also replace the BandClsid value with the GUID of our toolbar, the above values represent the source code for the article. Now compile the toolbar again. Then start IE and right click on the Standard Buttons toolbar, Select "Customize" from the context menu. Scroll down the Available toolbar buttons listbox and find "The Motley Fool" item, See Figure 12. Select it and click the Add button in the middle of the dialog. The item will move to the right as in Figure 13. Click the Close Button. You’ll see the button added as shown in the before figure 14 and after figure 15.

Figure 12. Customize Toolbar - Available Toolbar Buttons.
Figure 12. CustomizeToolbar – Available Toolbar Buttons.
Figure 13. Customize Toolbar - Current Toolbar Buttons.
Figure 13. Customize Toolbar – Current Toolbar Buttons.
Figure 14. IE Standard Buttons - Before.
Figure 14. IE Standard Buttons – Before.
Figure 15. IE Standard Buttons - After.
Figure 15. IE Standard Buttons – After.

Conclusion

While this tutorial is long hopefully the explaination was clear. From writing this tutorial it is easy to see that the RBDeskband ATL Object Wizard has some room for improvement but provided enough of a base for us to develop our simple example. In the end you can see that the toolbar we created is much like the Address bar. The differences lie in how MS implemented theirs versus how I implemented mine. As always feedback is welcome. Enjoy.


About Erik Thompson

Site Builder

Erik lives in Redmond, Washington. He works as a Senior Software Engineer specializing in C++, COM, ATL and the middle-tier and now .NET. When he isn’t coding for work, he can be found trying to extend Internet Explorer with yet another Desk band or simplifying his development process with ATL Object Wizards.

He spends his free time snowboarding, mountain biking, reading, dining out at those hidden finds.

Click here to view Erik Thompson’s online profile.

Other popular ATL articles:

0

IE编程 – Document


定制浏览器
作者:冯明德

浏览器控件是个典型的Active控件,提供了大量的接口及自动化对象,可以灵活的加以控制,需要的时候,可以通过这些接口控制浏览器的行为,或提供相应的出接口定制浏览器。

一、概述
浏览器对象CLSID:
CLSID_WebBrowser

提供的主要接口
IWebBrowser2 浏览器的接口

当文档建立后,可以得到相应的文档接口,文档中各标记元素的接口。
在DHTML中,大量的对象和事件就是又这些接口提供和管理的。

IHTMLDocument2
IHTMLWindow2
IHTMLEventObj
IHTMLElement
….

浏览器还将调用宿主提供的接口,以发出事件或给用户提供定制机会。
出接口
DIID_DWebBrowserEvents2
DIID_HTMLDocumentEvents
DIID_HTMLWindowEvents

(ICustomDoc)
IDocHostUIHandler

二、事件的相应
除了使用MFC缺省的事件响应机制外,也可以自建事件接受器,来响应事件
也就是,在封装对象中提供DIID_DWebBrowserEvents2 接口,然后将此接口作为接受器连接到浏览器对象。

一种做法是
在派生类中,使用MFC建立接口方案提供一个DIID_DWebBrowserEvents2接口对象嵌套成员。

 CFMDBrowser : public CWebBrowser{	...	//事件接收器接口	//DWebBrowserEvents	//这是一个IDispatch分发接口	BEGIN_INTERFACE_PART(BrowserEventSink,DWebBrowserEvents)		STDMETHOD(GetTypeInfoCount)(UINT *pctinfo);			STDMETHOD(GetTypeInfo)(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo);		STDMETHOD(GetIDsOfNames)(REFIID riid,				LPOLESTR *rgszNames,UINT cNames,				LCID lcid,DISPID *rgDispId);		STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid,				WORD wFlags,DISPPARAMS *pDispParams,				VARIANT *pVarResult,EXCEPINFO *pExcepInfo,				UINT  *puArgErr);		END_INTERFACE_PART(BrowserEventSink)	DWORD m_dwEventSinkCookie;	...}

这是一个接收器接口,无需添入到对象的接口表中。
(无需:BEGIN_INTERFACE_MAP、END_INTERFACE_MAP)

这是一个以分发接口(IDispatch)作为出接口的典型例子。在接口函数的实现中。Invoke负责又分发ID调用不同的虚拟函数。(事件函数作为虚拟函数,供派生类重载)

STDMETHODIMP CFMDBrowser::XBrowserEventSink::Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,				  WORD wFlags,DISPPARAMS *pDispParams,				  VARIANT *pVarResult,EXCEPINFO *pExcepInfo,				  UINT  *puArgErr){	METHOD_PROLOGUE(CFMDBrowser,BrowserEventSink)	//将事件分发到各虚拟函数	//分发ID的定义见 exdispid.h	switch(dispIdMember)	{	case DISPID_BEFORENAVIGATE:		...		HRESULT hr=pThis->OnBeforeNavigate(..) //事件对应的虚拟函数		...		break;        case DISPID_NAVIGATECOMPLETE:        		...	case ...	case ...}

建立与浏览器的连接
得到IConnectionPointContainer接口,查找与DIID_DWebBrowserEvents对应的接收器,建立连接,记录连接的标号(m_dwEventSinkCookie);

BOOL CFMDBrowser::Connect(){	IUnknown *p_Unk=GetControlUnknown();	if(p_Unk==NULL)		return FALSE;	BOOL bOK=FALSE;	//查找连接点对象	IConnectionPointContainer *i_cpc=0;	HRESULT hr=p_Unk->QueryInterface(IID_IConnectionPointContainer,		(void **)(&i_cpc));	if (SUCCEEDED(hr))	{		IConnectionPoint *i_cp=0;		hr=i_cpc->FindConnectionPoint(DIID_DWebBrowserEvents,&i_cp);		if (SUCCEEDED(hr))		{			hr=i_cp->Advise(&m_xBrowserEventSink,&m_dwEventSinkCookie);			i_cp->Release();			bOK=TRUE;		}		i_cpc->Release();	}		return bOK;}

结束时,断开与浏览器的连接

BOOL CFMDBrowser::DisConnect(){	IUnknown *p_Unk=GetControlUnknown();	if(p_Unk==NULL)		return FALSE;		BOOL bOK=FALSE;		//查找连接点对象	IConnectionPointContainer *i_cpc=0;	HRESULT hr=p_Unk->QueryInterface(IID_IConnectionPointContainer,		(void **)(&i_cpc));	if (SUCCEEDED(hr))	{		IConnectionPoint *i_cp=0;		hr=i_cpc->FindConnectionPoint(DIID_DWebBrowserEvents,&i_cp);		if (SUCCEEDED(hr))		{			hr=i_cp->Unadvise(m_dwEventSinkCookie);			i_cp->Release();			bOK=TRUE;		}		i_cpc->Release();	}		return bOK;}

三、定制浏览器UI
浏览器提供了IDocHostUIHandler出接口,向用户查询界面特性
可以提供这个接口,与浏览器连接上,在其实现中,定制界面

1.建立接口

class CFMDBrowser : public CWebBrowser{	...	//IDocHostUIHandler接口,控制浏览器界面	BEGIN_INTERFACE_PART(UIHandlerSink,IDocHostUIHandler)		STDMETHOD(ShowContextMenu)(DWORD,POINT*,IUnknown*,IDispatch*);		STDMETHOD(GetHostInfo)(DOCHOSTUIINFO*);		STDMETHOD(ShowUI)(DWORD,			IOleInPlaceActiveObject*,			IOleCommandTarget*,			IOleInPlaceFrame*,			IOleInPlaceUIWindow*);		STDMETHOD(HideUI)();		STDMETHOD(UpdateUI)();		STDMETHOD(EnableModeless)(INT);		STDMETHOD(OnDocWindowActivate)(INT);		STDMETHOD(OnFrameWindowActivate)(INT);		STDMETHOD(ResizeBorder)(LPCRECT,IOleInPlaceUIWindow*,INT);		STDMETHOD(TranslateAccelerator)(LPMSG,const GUID*,DWORD);		STDMETHOD(GetOptionKeyPath)(LPOLESTR*,DWORD);		STDMETHOD(GetDropTarget)(IDropTarget*,IDropTarget**);		STDMETHOD(GetExternal)(IDispatch**);		STDMETHOD(TranslateUrl)(DWORD,OLECHAR*,OLECHAR**);		STDMETHOD(FilterDataObject)(IDataObject*,IDataObject**);	END_INTERFACE_PART(UIHandlerSink)	...}

无需添加接口映射

2.连接到浏览器
需要在NavigateComplete时间发生后,得到
ICustomDoc接口,由此接口的
SetUIHandler成员设置UI接口。

//设置界面接口IDispatch *i_dispatch=0;if (SUCCEEDED(i_dispatch=pThis->GetDocument())){	IHTMLDocument2 *i_htmldoc2=0;	if (SUCCEEDED(i_dispatch->QueryInterface(IID_IHTMLDocument2,			(void **)(&i_htmldoc2))))	{			// force connection of IDocHostUIHandler			ICustomDoc *i_customdoc=0;			if (SUCCEEDED(i_htmldoc2->QueryInterface(						IID_ICustomDoc,						(void **)(&i_customdoc))))			{				i_customdoc->SetUIHandler(					&(pThis->m_xUIHandlerSink));				i_customdoc->Release();			}	}	i_dispatch->Release();}

3.在接口的实现中,控制用户界面
例如更改右键菜单
在STDMETHOD(ShowContextMenu)(DWORD,POINT*,IUnknown*,IDispatch*);
的实现中:

HRESULT CFMDBrowser::ShowContextMenu(DWORD,POINT*,IUnknown*,IDispatch*){	..建立自己的菜单        return S_OK;         }

Previous Page Next Page

Random Posts Recent Comments

  • Nouramohsen88 Says:

    http://goo.gl/vFWge لدينا ثلاجات عرض جديدة ومستعملة للبيع ولدينا ثلاجات عرض سوبر ماركت وحلويات في ست...

  • Nouramohsen88 Says:

    http://www.drdrahem.com/home دكتور رجيم دكتور تخسيس الكرش والارداف مركز تخسيس في مدينة نصر ...

  • Nouramohsen88 Says:

    شركه تصنيع صاعق ناموس http://www.grandelectronic-eg.com/...

  • Nouramohsen88 Says:

    شركة كشافات اضاءة في مصر http://www.grandelectronic-eg.com/ ...

  • Nouramohsen88 Says:

    http://www.grandelectronic-eg.com/ شركة كشافات طواريء في مصر...

  • Nouramohsen88 Says:

    anti-mosquitocompany.blogspot.com شركة جراند الكترونيك هي شركة مصرية متخصصة في تصنيع الكشافات الكهرب...

  • Nouramohsen88 Says:

    insect--killer.blogspot.com شركة جراند الكترونيك هي شركة مصرية متخصصة في تصنيع الكشافات الكهربية وك...

  • Nouramohsen88 Says:

    http://genius-square.com/ شركه للتدريب والاستشارات | متخصصون في التنمية البشرية...

  • Er Says:

    我了个去,我也是用的phpo ..... 看来大家的思绪差不多。。。。...

  • Fasf Says:

    SYM_TYPE * pType;改为SYM_TYPE pType;...

Tag Cloud

arm audio blog brew cache class debug flash google html j2me java javascript Joke linux lua mobile mtk php python ror ruby server shell stream unix web windows 优化 动态加载 女人 女生 平台 开发 手机 技术 流媒体 测试 漫画 生活 男人 男生 缓存 芯片