解決.net開發問題的最終法寶
2024-07-10 12:57:22
供稿:網友
 
這兩天正在網上找工作。昨天一網友問了個問題,說sendmessage在.net中調用失敗。
我看了看他的代碼是用vb.net寫的。于是我改用c#寫了個小的測試程序
using system.runtime.interopservices;
[dllimport("user32.dll")]
private static extern long sendmessagew(int hwnd,int wmsg,int wparam,int lparam);
system.diagnostics.process[] p;
p=system.diagnostics.process.getprocessesbyname("notepad");
int i=p[0].handle.toint32();
sendmessagew(i,16,0,0); 
(因為sendmessage分兩個版本,一個是sendmessagea一個是sendmessagew,由于nt下內部使用的是sendmessagew,而sendmessagea的調用則是先將參數轉換后再調用sendmessagew,所以這里我是用sendmessagew。)
這個程序的功能是查找一個記事本程序,然后向他發送關閉消息。
試驗了一下,果然失敗了。
開始我懷疑是.net的問題,因為一個網友曾經說過在vb中調用成功的代碼在vb.net中調用失敗了。于是我是用ildasm對該程序進行反匯編。反編譯后il代碼如下。
 .entrypoint
 .custom instance void [mscorlib]system.stathreadattribute::.ctor() = ( 01 00 00 00 ) 
 // 代碼大小 40 (0x28)
 .maxstack 4
 .locals init ([0] class [system]system.diagnostics.process[] p,
 [1] int32 i,
 [2] native int cs$00000002$00000000)
 il_0000: ldstr "notepad"
 il_0005: call class [system]system.diagnostics.process[] [system]system.diagnostics.process::getprocessesbyname(string)
 il_000a: stloc.0
 il_000b: ldloc.0
 il_000c: ldc.i4.0
 il_000d: ldelem.ref
 il_000e: callvirt instance native int [system]system.diagnostics.process::get_handle()
 il_0013: stloc.2
 il_0014: ldloca.s cs$00000002$00000000
//這里是sendmessagew調用的部分將p[0].handle.toint32()放入參數1
 il_0016: call instance int32 [mscorlib]system.intptr::toint32()
 il_001b: stloc.1
 il_001c: ldloc.1
//放入16,參數2
 il_001d: ldc.i4.s 16
//放入0,參數3
 il_001f: ldc.i4.0
//放入0,參數4
 il_0020: ldc.i4.0
 il_0021: call int64 twin.class1::sendmessagew(int32,
 int32,
 int32,
 int32)
 il_0026: pop
 il_0027: ret
看不出有什么問題,本來我以為是不是某個值被裝箱之類的操作了。一看所有參數都是標準的int32類型,這個可是值啊。
我并沒有就此覺悟,反而還是執迷不悟的懷疑是.net出的問題。
于是運行程序,在sendmessagew(i,16,0,0)處設置斷點,看看匯編碼。(運行時,在代碼的旁邊有個反匯編的tab,通過它你就可以看到匯編碼了)
0000004f push 0 
00000051 push 0 
00000053 mov ecx,edi 
00000055 mov edx,10h 
0000005a call dword ptr ds:[009c50f8h] 
00000060 nop 
在win32匯編中api函數的調用使用的方法是將參數值壓入棧中(后進現出)的原則,所以參數壓入順序為4321。
匯編中的語句
0000004f push 0 
00000051 push 0 
00000053 mov ecx,edi 
00000055 mov edx,10h 
都沒錯。唯一有可能出錯的就是
0000005a call dword ptr ds:[009c50f8h] 
于是問題很清楚了,.net調用api函數的方法沒有錯,是傳遞的參數出了錯。用vc++的工具spy++看看吧,果然發現句柄與p[0].handle.toint32()不符。無意間發現p[0].mainwindowhandle與spy++的結果相符,忽然間恍然大悟。大罵自己愚蠢分明需要給程序的窗體傳送消息,你給那個進程id傳送,人家誰理你啊!
改用p[0].mainwindowhandle實驗,記事本被關閉了。雖然犯了傻不過倒是總結了些解決.net出的問題的一些方法,如果你有些問題感到莫名其妙,找不到方法就不如用ildasm去反編譯一下,看看il代碼說不定有幫助,如果還不行,干脆就用看看匯編碼,說不定問題就明白了。
告訴他后,他又問了我另一個問題,一個窗體如何得到自己的句柄呢,其實這個很簡單,this.handle.toint32()就是自己的句柄了。
 結尾打個廣告吧,本人軟開工作兩年想找一份月薪3000元的北京的工作。有意者請與我聯系[email protected]