2010-07-06 33 views
6

Các chức năng như CreateProcess có chữ ký lấy con trỏ tới cấu trúc. Trong C tôi chỉ cần vượt qua NULL như một con trỏ cho các tham số tùy chọn, thay vì tạo một đối tượng struct dummy trên stack và đi qua một con trỏ đến giả.P/gọi hàm lấy con trỏ đến cấu trúc

Trong C#, tôi đã tuyên bố nó như là (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); 

Nhưng nếu tôi cố gắng vượt qua null cho lpProcessAttributes luận hoặc lpThreadAttributes lập luận, tôi nhận được một lỗi biên dịch:

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

Làm cách nào tôi có thể sửa đổi chữ ký hàm trên để tôi chỉ có thể vượt qua null đối với SECURITY_ATTRIBUTES đối số, không có lỗi trình biên dịch này? (Và cũng có thể vượt qua một cấu trúc thực nếu tôi muốn?)

+0

Có vẻ như câu hỏi của tôi giống như câu hỏi này, mặc dù tôi sẽ không đoán nó từ tựa đề. http://stackoverflow.com/questions/1049623/how-to-pass-a-nullable-type-to-a-p-invoked-function –

Trả lời

3

null chỉ hợp lệ cho các loại tham chiếu trong .Net. SECURITY_ATTRIBUTES của bạn là struct, là ValueType. Thay vì truyền null, bạn cần chuyển một cấu trúc SECURITY_ATTRIBUTES trống. (chỉ cần nói new SECURITY_ATTRIBUTES()) trong cuộc gọi của bạn.

Một phương pháp sạch hơn là thêm một tài sản Rỗng tĩnh để struct của bạn, và chỉ cần vượt qua 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, 
      }; 
     } 
    } 
} 

Hoặc tốt hơn, thay vì sử dụng P/Invoke để tạo ra một quá trình, hãy kiểm tra các lớp System.Diagnostics.Process, có lẽ nên làm những gì bạn cần. (!)

+0

Cảm ơn, tôi thích mẫu SECURITY_ATTRIBUTES.Empty này. –

+0

Nhân tiện, tôi đã sử dụng p/gọi để tạo một quy trình vì tôi muốn làm những việc với các đặc quyền quy trình sẽ không được các API được quản lý hỗ trợ. Nhưng nếu không, tôi đã sử dụng lớp System.Diagnostics.Process. –

+0

Nhưng vấn đề với thuộc tính trống là bạn không thể chuyển nó thành tham số ref. Do nhiều API Win32 giao dịch với cấu trúc mong đợi một địa chỉ, nên cần phải có ref. – Adarsha

6

OK, tôi cuối cùng đã tìm thấy một cách tốt hơn để làm điều này:

Khai SECURITY_ATTRIBUTES như lớp thay vì struct và không vượt qua nó bằng cách ref. :-)

[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; 
} 

Phần thưởng: điều này cũng cho phép bạn khai báo một hàm tạo phù hợp trên SECURITY_ATTRIBUTES khởi tạo nLength.

+0

Nó hoạt động không có vấn đề gì bạn đổi tên lớp. Câu trả lời chính xác! –

+1

Tôi tự hỏi liệu điều này có an toàn hay không. Thuộc tính 'StructLayout' chỉ có thể ảnh hưởng đến cấu trúc, không chỉ các lớp. Vì vậy, có lẽ JIT của NET có thể đặt ra các lĩnh vực trong lớp này bất kỳ cách nào nó muốn. Ví dụ, tôi tự hỏi nếu điều này có thể thất bại trên x64 hoặc các nền tảng khác. Tôi có thể không phải là một thủ thuật an toàn. –

+0

Tôi vừa nghe từ một chuyên gia CLR nội bộ của MSFT rằng đây là một thủ thuật an toàn. :) –

Các vấn đề liên quan