文:/ 飛躍作碍岔,河許人改
AHK界一直有這么一個(gè)故事浴讯,講的是AHK星君和WIN大神之間通過小徒弟dllcall眉來眼去的故事。
第一章
我是一個(gè)AHK星君(AHK腳本)蔼啦,居住在九重天上(硬盤)榆纽,這九重天上由一位超級(jí)大神WIN大神(Windows系統(tǒng))掌管,跟我一樣的眾神捏肢,每天各司其職奈籽,維持這乾坤的運(yùn)轉(zhuǎn)和平衡,我作為效率之神鸵赫,每天幻化為億萬形態(tài)衣屏,解救人間低效之苦,深受人間的愛戴辩棒。
有一天我感應(yīng)到強(qiáng)烈的召喚(被雙擊了)狼忱,跳了起來說:WIN大神膨疏,我要臨凡(運(yùn)行),我要發(fā)威钻弄,我要表現(xiàn)了佃却!WIN大神微微睜開雙眼,“去吧窘俺!前途兇險(xiǎn)(問題不好解決)饲帅,受我加持(我這有好多寶貝你帶上),方可順利批销!”
“不用洒闸,老大你放心”
WIN大神沒說話,大手一揮均芽,云霧繚繞的九重天不見了丘逸,自由落體,好嗨呦掀宋!直奔一個(gè)藍(lán)色的星球(內(nèi)存)而去深纲,一瞬間,我已經(jīng)落地劲妙,站在一個(gè)寫著“中國”的界碑前湃鹊。
大神的聲音響起,“這是你的活動(dòng)空間(分配的內(nèi)存)镣奋,不準(zhǔn)亂跑币呵!這里我設(shè)了結(jié)界,別人也打擾不到你侨颈!”地上憑空出現(xiàn)一個(gè)方陣余赢,有標(biāo)準(zhǔn)工人(棧)組成」福“這些人妻柒,聽你調(diào)遣,應(yīng)付不了耘分,隨時(shí)打電話(dllcall)給我举塔!”
說罷,工人扛起我求泰,一路狂奔央渣,直奔呼叫處。
第二章
一邊走芽丹,一邊想,“什么玩意枉氮,我一身法力(命令或函數(shù))什么問題解決不了志衍!”楼肪,說著,已經(jīng)到了現(xiàn)場暂殖,經(jīng)過一番苦戰(zhàn)晨横,竟然沒能拿下手形,突然,WIN大神的最后一句話在我腦海中響起悯恍,CALL他库糠!
于是,我撥了直通老大法寶管理處(WinAPI)的電話涮毫,剛一接通瞬欧,管理處的領(lǐng)導(dǎo)說:“AHK星君啊窒百!老大早料到你會(huì)打電話黍判,讓你小徒弟(dllcall()函數(shù))過來拉吧!都給你準(zhǔn)備好了(Dll文件)篙梢∏晏”電話那頭掛了。
“shit渤滞!”
“小D(dllcall()函數(shù))贬墩,去把法寶取過來!”
法寶在WIN大神準(zhǔn)備好的Dll包裹中(Dll文件)妄呕,也在某個(gè)星球中(硬盤)陶舞,不一會(huì)兒,小D把它拉進(jìn)地球(內(nèi)存)的中國中绪励,這是我的地盤肿孵,然后通過法寶名字(函數(shù)名)找到了法寶的位置唠粥,準(zhǔn)備使用。
第三章
可是停做,WIN大神的法寶有點(diǎn)麻煩晤愧,要發(fā)動(dòng)它需要給上面每個(gè)掛件(參數(shù))都要一句咒語(聲明),WIN大神的法寶特別多蛉腌,掛件也特別多官份,每一個(gè)法寶掛不同的掛件效果還不一樣,不過好在對(duì)應(yīng)的咒語不多烙丛。
法寶只能通過標(biāo)準(zhǔn)工人(棧)來安裝掛件(獲取參數(shù))舅巷,我要把掛件(參數(shù))一個(gè)個(gè)裝入分配給標(biāo)準(zhǔn)工人(棧),每個(gè)掛件(參數(shù))都是一個(gè)整數(shù)河咽。補(bǔ)充一下钠右,WIN大神分兩種,一種是32位大神忘蟹,他生產(chǎn)的標(biāo)準(zhǔn)工人每人能貢獻(xiàn)四個(gè)單位(4個(gè)字節(jié)(1字節(jié)8位))爬舰,另一種是64位大神,他生產(chǎn)的標(biāo)準(zhǔn)工人每人能貢獻(xiàn)八個(gè)單位(8個(gè)字節(jié)(1字節(jié)8位))寒瓦,大神的法寶在制作時(shí)(編譯)情屹,已經(jīng)約定好按標(biāo)準(zhǔn)工人的能力(長度)來設(shè)計(jì)每個(gè)掛件(對(duì)齊每個(gè)參數(shù)),比如在64位大神的統(tǒng)治下(系統(tǒng)中)杂腰,即使是安裝一個(gè)1的掛件(傳遞參數(shù)1)垃你,它只需要1個(gè)單位的貢獻(xiàn),但是一個(gè)標(biāo)準(zhǔn)工人的8個(gè)貢獻(xiàn)能力(8字節(jié)共有64位)喂很,根本用不完(另外63位要補(bǔ)0湊成64位裝到集裝箱中惜颇,所以輸入?yún)?shù)的整數(shù)本來并不難,只要把參數(shù)的整數(shù)補(bǔ)齊到8字節(jié)裝入集裝箱即可少辣。)
第四章
小D揼著法寶說凌摄,“每個(gè)掛件的都要咒語才能發(fā)動(dòng)”(每個(gè)參數(shù)都要說明參數(shù)類型).
"我就納悶了,不是約定好了一個(gè)標(biāo)準(zhǔn)工人裝一個(gè)參數(shù)嗎漓帅,干嘛還要念咒語呢(說明類型)锨亏?硬要我念得話,全部念最大那個(gè)咒語(使用集裝箱的長度類型(Ptr))不行嗎忙干?"
小D小聲說器予,大神讓我給你傳個(gè)話,大神的法寶調(diào)用有下面幾種類型:
(1)第一種給它幾個(gè)地址和小整數(shù)它就可以操作捐迫,這種法寶沒必要叫你念咒語(特別說明類型)乾翔。
(2)第二種它需要一個(gè)特別大的整數(shù)(最大8字節(jié)),但是如果我們在32位大神那施戴,每個(gè)標(biāo)準(zhǔn)工人只有4能力(字節(jié))反浓,我就要把一個(gè)掛件(參數(shù))的整數(shù)分給兩個(gè)標(biāo)準(zhǔn)工人去做萌丈,這種情況你不是得用咒語(使用參數(shù)類型(int64))來喊一嗓子嗎?你如果不喊雷则,一個(gè)工人拿一半就走浓瞪,法寶就沒效果了(說明參數(shù)類型,我默認(rèn)把這個(gè)參數(shù)裝到一個(gè)集裝箱中(大整數(shù)會(huì)截?cái)嘁徊糠郑┣缮簦严乱粋€(gè)參數(shù)裝到下一個(gè)集裝箱),如果你喊一嗓子(涂乌,而法寶聲明了這個(gè)參數(shù)是64位的艺栈,)他們就知道咋回事了,兩人一起搞一個(gè)掛件湾盒,這樣后續(xù)的也不會(huì)亂了(它會(huì)讀取連續(xù)兩個(gè)集裝箱拼成一個(gè)參數(shù)(下一個(gè)參數(shù)在這兩個(gè)集裝箱后面)湿右,后續(xù)參數(shù)不就錯(cuò)位了嗎。)
(3)第三種它需要一個(gè)小數(shù)(浮點(diǎn)數(shù))作為掛件(參數(shù))罚勾,因?yàn)闃?biāo)準(zhǔn)工人里面只能裝整數(shù)毅人,所以小數(shù)是一種特殊構(gòu)造的整數(shù),系統(tǒng)約定好這個(gè)特殊整數(shù)的前面幾位表示尾數(shù)部分尖殃,后面幾位表示以2為底的指數(shù)部分丈莺,反正構(gòu)造很復(fù)雜,小數(shù)1.0構(gòu)造出的整數(shù)形式絕對(duì)不同于整數(shù)1的形式送丰,如果你不說明這個(gè)參數(shù)是小數(shù)(float是4字節(jié)浮點(diǎn)數(shù)缔俄,double是8字節(jié)浮點(diǎn)數(shù)),我就不會(huì)進(jìn)行特殊構(gòu)造器躏,直接取整傳遞整數(shù)俐载,而法寶聲明了這個(gè)掛件(參數(shù))是小數(shù),它會(huì)按照特殊構(gòu)造來讀取解析登失,不就搞錯(cuò)數(shù)字了嗎遏佣。
(4)第四種它需要一個(gè)數(shù)據(jù)結(jié)構(gòu),也就是一個(gè)班級(jí)的座位結(jié)構(gòu)揽浙,每個(gè)座位是一個(gè)字節(jié)状婶,按它聲明的規(guī)定,第一個(gè)數(shù)坐到第一個(gè)座位并占幾個(gè)字節(jié)(霸占后續(xù)幾個(gè)座位)馅巷,第二個(gè)數(shù)坐到后面某個(gè)座位并占幾個(gè)字節(jié)(霸占后續(xù)幾個(gè)座位)等等太抓,它需要你構(gòu)造這么一個(gè)班級(jí)的座位結(jié)構(gòu),并把第一個(gè)座位的地址作為掛件(參數(shù))分配給掛件令杈。這種地址不用你操心掛件(參數(shù))類型走敌,因?yàn)榈刂返恼麛?shù)字節(jié)長度剛好等于標(biāo)準(zhǔn)工人的能力。你可以用VarSetCapacity()劃分一個(gè)空閑的班級(jí)逗噩,用NumPut()把數(shù)字安放到各個(gè)座位上去掉丽,然后用 & 取班級(jí)第一個(gè)座位的地址作為參數(shù)跌榔。等法寶執(zhí)行完畢后,它可能修改了某個(gè)座位上的數(shù)字捶障,你可以用NumGet()從班級(jí)的某個(gè)座位中讀取需要的數(shù)字僧须。
(5)第五種它需要一個(gè)字符串,也就是一隊(duì)字符小朋友项炼,每個(gè)字符是一個(gè)編碼的整數(shù)担平,它需要隊(duì)伍的第一個(gè)字符的地址作為掛件(參數(shù))裝到分配給工人,本來你只要人工用 & 取隊(duì)伍的第一個(gè)字符的首地址作為參數(shù)的整數(shù)即可锭部,掛件(參數(shù))類型不重要(Ptr即可)暂论,反正這個(gè)地址的長度剛好是一個(gè)工人的能力。但是我還是建議你使用Str類型拌禾,因?yàn)椋?/p>
A取胎、字符串有著特殊性,系統(tǒng)中使用的字符串有ANSI和Unicode兩種編碼方式湃窍,法寶到底需要哪一種闻蛀,需要你自己判斷及轉(zhuǎn)換。聲明Str參數(shù)類型而不是無所謂的類型(int您市、Ptr)觉痛,我可以自動(dòng)幫你轉(zhuǎn)換(利用AStr和WStr類型轉(zhuǎn)為法寶需要的編碼)。
B茵休、另外秧饮,法寶要求你輸入一個(gè)地址,用于從這個(gè)地址輸出一隊(duì)字符串小朋友時(shí)泽篮,聲明Str類型可以由我?guī)湍阕詣?dòng)讀取字符串(更新字符串長度)盗尸,否則要你自己手動(dòng)讀取字符串。(Str自動(dòng)讀取的情況AHK自身的編碼與法寶名稱指示的編碼必須一致)
- 注意:輸出字符串必須由你先用VarSetCapacity()劃分一個(gè)空閑的班級(jí)帽撑,才允許法寶在這個(gè)班級(jí)中輸出數(shù)據(jù)泼各,否則法寶輸出的數(shù)據(jù)可能覆蓋了你的其他地盤。
(6)第六種本來法寶可以有一個(gè)返回值亏拉,但是當(dāng)它需要返回不止一個(gè)值時(shí)扣蜻,它需要你在參數(shù)中提供一個(gè)地址,用來把某個(gè)結(jié)果數(shù)值寫入到這個(gè)地址及塘,等法寶執(zhí)行結(jié)束后莽使,你可以從這個(gè)地址中讀取這個(gè)值。本來你可以手動(dòng)用 & 取一個(gè)變量的地址作為掛件(參數(shù))讓工人去取笙僚,如果法寶需要這個(gè)地址中有個(gè)初值芳肌,可以用NumPut()把數(shù)字放入這個(gè)地址中,等法寶執(zhí)行結(jié)束后,再用NumGet()從這個(gè)地址中讀取返回值亿笤,這種方式參數(shù)類型不重要翎迁,反正這個(gè)地址的長度剛好適合一個(gè)標(biāo)準(zhǔn)工人的能力。但是我還是建議你使用類型净薛,因?yàn)椋菏褂?/em>類型可以由我自動(dòng)地使用一個(gè)臨時(shí)地址汪榔,先把初值寫入,最后又把結(jié)果讀出到你的參數(shù)的變量中肃拜,完全不用你操心痴腌,絕對(duì)推薦使用(Ptr*即可)。
好了燃领,明白了小D(DllCall)講述的這6種情況士聪,你就會(huì)恰當(dāng)?shù)脑O(shè)定參數(shù)類型了。再學(xué)會(huì):用 & 取變量地址柿菩、VarSetCapacity()、NumPut()雨涛、NumGet()枢舶、StrPut()、StrGet()替久,和根據(jù)A_PtrSize地址長度來計(jì)算數(shù)據(jù)結(jié)構(gòu)的偏移凉泄,你就可以爐火純青地使用DllCall了。