2012-09-10 64 views
0

我想通過系統插件和netapi32庫從窗口獲取一些信息。調用系統插件後從struct獲取信息

我嘗試在分配適合作爲WKSTA_INFO_100的結構之後調用NetWkstaGetInfo()

在MSDN的NetWkstaGetInfo()原型狀態:

NET_API_STATUS NetWkstaGetInfo(
    _In_ LPWSTR servername, 
    _In_ DWORD level, 
    _Out_ LPBYTE *bufptr 
); 

雖然WKSTA_INFO_100

typedef struct _WKSTA_INFO_100 { 
    DWORD wki100_platform_id; 
    LMSTR wki100_computername; 
    LMSTR wki100_langroup; 
    DWORD wki100_ver_major; 
    DWORD wki100_ver_minor; 
} WKSTA_INFO_100, *PWKSTA_INFO_100, *LPWKSTA_INFO_100; 

對於初步測試,我嘗試在一個消息顯示的結構成員。我首先用dummy信息初始化結構,以檢查api調用是否替換分配的塊的內容。

但直到現在,我在第一個結構成員之後幾乎沒有任何東西,我想結構沒有正確定義,或者我有一個結構對齊問題。不幸的是,系統插件 的怪異文檔讓我瘋狂 對我沒有多大幫助。

這裏是我的測試腳本:

outfile "hello.exe" 

section 

System::Call /NOUNLOAD "*(*i11,t 'some',t 'thing',i22,i44)i .r0" 
Dumpstate::debug 
System::Call /NOUNLOAD "netapi32::NetWkstaGetInfo(i0, i100, i r0) i.r6" 
Dumpstate::debug 
System::Call /NOUNLOAD "*$0(*i.r1, t.r2, t.r3, i.r4, i.r5)" 
Dumpstate::debug 
messagebox MB_OK "Hello, to $2 $3 domain (win $1 - $4.$5) !" 
System::Free $0 

sectionEnd 

第一檢索到的值(500)是正確的。但其他成員保持其初始價值。我錯過了什麼?

(編輯)推論問題:

  • 似乎文檔和MSDN之後,該結構的第一個成員應該是i,而不是*i但我沒得到了一個正確的返回值沒有*(Dumpstate插件傾向於顯示它是作爲地址返回的)
  • 是插件的/NOUNLOAD參數是必需的嗎?我發現了幾個例子,但沒有找到確切的原因。我擔心分配的結構可能在沒有參數的情況下被提前釋放。你能確認/體弱嗎?

回答

0

bufptr超出只有這麼傳遞R0爲輸入NetWkstaGetInfo是沒有意義的,該功能不需要輸入數據。 你不應該使用*i與NetApiBufferFree,單獨i足夠($ 0已經有地址,你不希望系統插件與指針玩,只是把它傳遞直接到API)

!include LogicLib.nsh 

System::Call "netapi32::NetWkstaGetInfo(i0, i100, *i 0 r0) i.r1" 
${If} 0 = $1 
    System::Call "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)" 
    DetailPrint "Hello, to $2 $3 domain (win $1 - $4.$5) !" 
${EndIf} 
System::Call "netapi32::NetApiBufferFree(ir0)" 

在前面的示例中,我使用*i 0 r0作爲bufptr參數,因此在函數啓動之前$ 0爲NULL(如果您不想使用此技巧,則可以在系統調用之前執行StrCpy $0 0)。如果你不這樣做,那麼不清楚如果函數失敗會發生什麼。該文檔沒有指定當函數失敗時,bufptr會發生什麼情況,希望它被設置爲NULL,但是您無法確定。如果函數失敗,我們最終會將NULL傳遞給NetApiBufferFree,通常這是一個安全的事情,可以傳遞給一個免費函數,但文檔不會將其視爲OK。要在超級安全起見,你應該只釋放非NULL指針:

System::Call "netapi32::NetWkstaGetInfo(i0, i100, *i 0 r0) i.r1" 
${If} 0 = $1 
    System::Call "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)" 
    DetailPrint "Hello, to $2 $3 domain (win $1 - $4.$5) !" 
${EndIf} 
${IfThen} $0 <> 0 ${|} System::Call "netapi32::NetApiBufferFree(ir0)" ${|} 
SectionEnd 

/NOUNLOAD不再需要使用該系統的插件(自v2.42)時。/NOUNLOAD阻止NSIS卸載插件。如果插件具有內部狀態,這很重要,但在您的情況下,唯一的狀態是由Windows分配的內存塊。

+0

感謝您的詳細解釋! – Seki

+0

稍後注意:從結構中獲取寬度字符串的正確表示法是'&w $ {NSIS_MAX_STRLEN} .r3'而不是'w .r3'(導致訪問衝突)請參閱http://stackoverflow.com/questions/12402628 /意外性的logiclib - 行爲 - 當測試字符串,返回按系統插件#comment16669797_12403086 – Seki

0

似乎文檔和MSDN之後,該結構的第一個成員應該是i,而不是*i但我沒得到了一個正確的返回值沒有*(在Dumpstate插件趨於顯示它會返回一個地址)

這就是線索的解決方案:我看錯了MSDN頁面,起初並沒有注意到,這是不是結構傳遞給NetWkstaGetInfo但地址一個NetWkstaGetInfo*由api調用修改(並且必須在NetApiBufferFree之後釋放。因此,正確的腳本是:

outfile "hello.exe" 

section 

System::Call "netapi32::NetWkstaGetInfo(i0, i100, *i r0 r0) i.r6" 
System::Call "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)" 
messagebox MB_OK "Hello, to $2 $3 domain (win $1 - $4.$5) !" 
System::Call "netapi32::NetApiBufferFree(*i r0) i.r6" 

sectionEnd