2010-07-06 64 views
6

諸如CreateProcess之類的函數具有指向結構的指針。在C中,我只是通過NULL作爲可選參數的指針,而不是在堆棧上創建一個啞元結構對象,並將指針傳遞給啞元。P /調用函數將指針指向結構

在C#中,我已經聲明它(的P/Invoke)

[DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
     public static extern bool CreateProcess(
      string lpApplicationName, 
      string lpCommandLine, 
      ref SECURITY_ATTRIBUTES lpProcessAttributes, 
      ref SECURITY_ATTRIBUTES lpThreadAttributes, 
      bool bInheritHandles, 
      CreateProcessFlags dwProcessCreationFlags, 
      IntPtr lpEnvironment, 
      string lpCurrentDirectory, 
      ref STARTUPINFO lpStartupInfo, 
      ref PROCESS_INFORMATION lpProcessInformation); 

但是,如果我嘗試通過nulllpProcessAttributes參數或lpThreadAttributes的說法,我得到一個編譯錯誤:

Error 2 Argument 3: cannot convert from '<null>' to 'ref Debugging.Wrappers.SECURITY_ATTRIBUTES'

如何修改上述函數簽名,以便我可以通過null作爲SECURITY_ATTRIBUTES參數,而不會出現此編譯器錯誤? (如果我願意,還能夠傳遞一個真實的結構?)

+0

看起來我的問題和這個一樣,儘管我不會從標題中猜出它。 http://stackoverflow.com/questions/1049623/how-to-pass-a-nullable-type-to-a-p-invoked-function – 2010-07-06 04:45:59

回答

3

null僅對.Net中的引用類型有效。您的SECURITY_ATTRIBUTES是struct,這是一個ValueType。而不是傳遞null,你需要傳遞一個空的SECURITY_ATTRIBUTES結構。 (只需說new SECURITY_ATTRIBUTES())。

一個清潔的方法是靜態空屬性添加到您的結構,只是通過SECURITY_ATTRIBUTES.Empty

[StructLayout(LayoutKind.Sequential)] 
public struct SECURITY_ATTRIBUTES { 
    public int nLength; 
    public IntPtr lpSecurityDescriptor; 
    public int bInheritHandle; 

    public static SECURITY_ATTRIBUTES Empty { 
     get { 
      return new SECURITY_ATTRIBUTES { 
       nLength = sizeof(int)*2 + IntPtr.Size, 
       lpSecurityDescriptor = IntPtr.Zero, 
       bInheritHandle = 0, 
      }; 
     } 
    } 
} 

或者更好的,而不是使用P/Invoke來創建一個進程,檢查出System.Diagnostics.Process類,這應該可以做你需要的。 (!)

+0

謝謝,我喜歡這SECURITY_ATTRIBUTES.Empty模式。 – 2010-07-06 04:45:24

+0

順便說一下,我使用p/invoke來創建一個進程,因爲我想用託管API不支持的進程權限來執行操作。但是否則,我會使用System.Diagnostics.Process類。 – 2012-09-13 18:35:00

+0

但是,Empty屬性的問題是您無法將其作爲ref參數傳遞。鑑於許多處理結構的Win32 API需要一個地址,因此需要ref。 – Adarsha 2013-10-19 18:40:06

6

OK,我終於找到了這樣做的更好的方法:

聲明SECURITY_ATTRIBUTES爲類,而不是結構不被裁判傳遞。 :-)

[DllImport("kernel32.dll", SetLastError = true)] 
    public static extern bool CreateProcess(
     string lpApplicationName, 
     StringBuilder lpCommandLine, 
     SECURITY_ATTRIBUTES lpProcessAttributes, 
     SECURITY_ATTRIBUTES lpThreadAttributes, 
     bool bInheritHandles, 
     CreateProcessFlags dwCreationFlags, 
     IntPtr lpEnvironment, 
     string lpCurrentDirectory, 
     STARTUPINFO lpStartupInfo, /// Required 
     PROCESS_INFORMATION lpProcessInformation //Returns information about the created process 
     ); 

/// <summary> 
/// See http://msdn.microsoft.com/en-us/library/aa379560(v=VS.85).aspx 
/// </summary> 
[StructLayout(LayoutKind.Sequential)] 
public class SECURITY_ATTRIBUTES 
{ 
    public uint nLength; 
    public IntPtr lpSecurityDescriptor; 
    [MarshalAs(UnmanagedType.Bool)] public bool bInheritHandle; 
} 

獎勵:這也可以讓你在聲明SECURITY_ATTRIBUTES一個體面的構造函數用於初始化nLength。

+0

無論您將類重命名爲什麼,它都能正常工作。很好的答案! – 2015-08-04 21:22:11

+1

我不知道這是否安全。 'StructLayout'屬性可能只會影響結構,而不會影響類。所以也許.NET的JIT可能會按照它想要的方式佈置這個類的字段。例如,我想知道這是否會在x64或其他平臺上失敗。我可能不是一個安全的伎倆。 – 2015-10-27 17:49:05

+0

我剛剛從MSFT內部的CLR專家那裏聽說,這是一個安全的技巧。 :) – 2015-10-27 19:15:48