2012-10-10 59 views
1

我引用了另一個stackoverflow文章「如何將指針映射到JNA中的結構數組」以提出以下代碼來枚舉Windows服務依賴關係。如何使用JNA

結構和函數聲明:

static class SERVICE_STATUS extends Structure { 
    public int dwServiceType; 
    public int dwCurrentState; 
    public int dwControlsAccepted; 
    public int dwWin32ExitCode; 
    public int dwServiceSpecificExitCode; 
    public int dwCheckPoint; 
    public int dwWaitHint; 
    public SERVICE_STATUS(){} 
} 

static class ENUM_SERVICE_STATUS extends Structure { 
    public ENUM_SERVICE_STATUS(){ } 

    public WString lpServiceName; 
    public WString lpDisplayName; 
    SERVICE_STATUS serviceStatus; 
} 

boolean EnumDependentServicesW(Pointer hService, int serviceState, ENUM_SERVICE_STATUS serviceStatuses, int size, IntByReference bytesNeeded, IntByReference servicesReturned); 

如果只有一個服務的依賴,下面的代碼工作:

IntByReference bytesNeeded = new IntByReference(); 
IntByReference numberOfServices = new IntByReference(); 
Advapi32.ENUM_SERVICE_STATUS serviceStatus = new Advapi32.ENUM_SERVICE_STATUS(); 
Advapi32.ENUM_SERVICE_STATUS[] serviceStatuses = (Advapi32.ENUM_SERVICE_STATUS[]) serviceStatus.toArray(1); 

if (!advapi32.EnumDependentServicesW(serviceHandle, Advapi32.SERVICE_ACTIVE, null, 0, bytesNeeded, numberOfServices)) { 
    if (advapi32.EnumDependentServicesW (serviceHandle, Advapi32.SERVICE_ACTIVE, serviceStatuses[0], bytesNeeded.getValue(), bytesNeeded, numberOfServices)) { 
     for(int i = numberOfServices.getValue() - 1; i >= 0; i--){ 
      logger.debug("Service Name: " + serviceStatuses[i].lpServiceName.toString()); 
    } 
} 

如果有2個服務的依存關係,我得到一個NullPointerException異常的lpServiceName在logger.debug電話:

IntByReference bytesNeeded = new IntByReference(); 
IntByReference numberOfServices = new IntByReference(); 
Advapi32.ENUM_SERVICE_STATUS serviceStatus = new Advapi32.ENUM_SERVICE_STATUS(); 
Advapi32.ENUM_SERVICE_STATUS[] serviceStatuses = (Advapi32.ENUM_SERVICE_STATUS[]) serviceStatus.toArray(2); 

if (!advapi32.EnumDependentServicesW(serviceHandle, Advapi32.SERVICE_ACTIVE, null, 0, bytesNeeded, numberOfServices)) { 
    if (advapi32.EnumDependentServicesW (serviceHandle, Advapi32.SERVICE_ACTIVE, serviceStatuses[0], bytesNeeded.getValue(), bytesNeeded, numberOfServices)) { 
     for(int i = numberOfServices.getValue() - 1; i >= 0; i--){ 
      logger.debug("Service Name: " + serviceStatuses[i].lpServiceName.toString()); 
    } 
} 

NumberOfServices正如預期的那樣,上面的代碼值爲2。我試圖傳遞結構數組而不是指針,因爲我想讓JNA執行內存同步。我應該如何傳遞/使用結構數組?

回答

0

按照docsEnumDependentServices

lpServices [出,可選]

的指針,該接收名稱和服務 狀態信息 ENUM_SERVICE_STATUS結構陣列數據庫中的每個相關服務。 緩衝區必須足夠大以容納結構,加上其成員指向的字符串 。

你幾乎忽略了所需的緩衝區大小由bytesNeeded報道。您應該使用bytesNeeded值來創建所需大小的Memory實例,然後使用該Memory實例來創建一個新的ENUM_SERVICE_STATUS實例,而不是獨立所需的緩衝區大小的創建結構。

+0

謝謝@technomage,供您參考。我可以將內存分配給ENUM_SERVICE_STATUS實例,但我不太明白這是如何工作的。 BytesNeeded是數組中所有結構的總大小加上結構指向的字符串。因此,如果我手動將所有內存分配給一個ENUM_SERVICE_STATUS實例,那麼ENUM_SERVICE_STATUS結構數組將如何填充(以及從EnumDependentServices返回後如何訪問數組元素)? – user1735138

+0

一旦你知道了所需的內存,就創建一個這樣大小的內存實例,用它來初始化一個'ENUM_SERVICE_STATUS'實例,然後調用'toArray'。 'Structure'有一個構造函數,它具有'Pointer'值;用它來覆蓋你新分配的「內存」上的結構。一旦你在'Structure'基礎上調用'toArray',JNA就知道如何跟蹤它並通過本地方法調用同步所有數組成員。 – technomage

+0

我終於通過更新到JNA 3.3.0來返回所有依賴關係,創建一個Memory實例並使用它創建ENUM_SERVICE_STATUS。謝謝你@technomage!我仍然在想如何確定用於toArray的大小,因爲直到第二次調用EnumDependentServices之後,我們才知道有多少服務依賴關係,但是我們需要在第二次調用之前執行toArray ... – user1735138