2013-04-19 34 views
5

tôi đang cố gắng để có được thư mục làm việc hiện tại của quá trình lựa chọn. Tôi chắc chắn rằng nó là có thể, bởi vì các công cụ như Process Explorer có thể hiển thị thông tin này. Tôi phát hiện ra rằng thông tin này được lưu trữ trong PEB.đọc khác quá trình hiện tại thư mục trong C#

Hơn nữa tôi thấy Oleksiy bài viết trên blog: http://eazfuscator.blogspot.com/2011/06/reading-environment-variables-from.html, nhưng tất cả những thay đổi của tôi là hoàn toàn trừ.

Vì vậy, câu hỏi của tôi là làm thế nào tôi có thể đọc thông tin này trong C#? Nếu mã Oleksiy là một cách hay, tôi nên sửa đổi mã của mình như thế nào để có được thông tin này?

+3

Đây không phải là ứng dụng nên làm với nhau. Việc sử dụng hợp lệ duy nhất sẽ là một số công cụ chẩn đoán sắp xếp. –

+0

Bạn nói đúng, tôi cần điều này cho Bộ phận An ninh –

+0

Bạn có nghĩa là bộ phận Không an toàn? –

Trả lời

7

Như khác đã chỉ ra, điều này là hoàn toàn không có giấy tờ, nhưng đây là một đoạn mã nào đó (như của ngày hôm nay, có vẻ như để làm việc). Tất nhiên, nó cần phải chạy như admin. Lưu ý nó có thể làm việc cho bất kỳ bit bit quá trình, 32-bit hoặc 64-bit (một số processess có thể báo cáo một truy cập bị từ chối, thậm chí chạy như admin), với bất kỳ mục tiêu biên dịch (x86 hoặc x64). Nó cũng có khả năng đọc dòng lệnh. Sử dụng có nguy cơ của riêng bạn!

// All offset values below have been tested on Windows 7 & 8 only 
// but you can use WinDbg "dt ntdll!_PEB" command and search for ProcessParameters offset to find the truth, depending on the OS version 
public static class ProcessUtilities 
{ 
    public static string GetCurrentDirectory(int processId) 
    { 
     return GetProcessParametersString(processId, Environment.Is64BitOperatingSystem ? 0x38 : 0x24); 
    } 

    public static string GetCurrentDirectory(this Process process) 
    { 
     if (process == null) 
      throw new ArgumentNullException("process"); 

     return GetCurrentDirectory(process.Id); 
    } 

    public static string GetCommandLine(int processId) 
    { 
     return GetProcessParametersString(processId, Environment.Is64BitOperatingSystem ? 0x70 : 0x40); 
    } 

    public static string GetCommandLine(this Process process) 
    { 
     if (process == null) 
      throw new ArgumentNullException("process"); 

     return GetCommandLine(process.Id); 
    } 

    private static string GetProcessParametersString(int processId, int offset) 
    { 
     IntPtr handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, processId); 
     if (handle == IntPtr.Zero) 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 

     int processParametersOffset = Environment.Is64BitOperatingSystem ? 0x20 : 0x10; 
     try 
     { 
      if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess) // are we running in WOW? 
      { 
       PROCESS_BASIC_INFORMATION_WOW64 pbi = new PROCESS_BASIC_INFORMATION_WOW64(); 
       int hr = NtWow64QueryInformationProcess64(handle, 0, ref pbi, Marshal.SizeOf(pbi), IntPtr.Zero); 
       if (hr != 0) 
        throw new Win32Exception(hr); 

       long pp = 0; 
       hr = NtWow64ReadVirtualMemory64(handle, pbi.PebBaseAddress + processParametersOffset, ref pp, Marshal.SizeOf(pp), IntPtr.Zero); 
       if (hr != 0) 
        throw new Win32Exception(hr); 

       UNICODE_STRING_WOW64 us = new UNICODE_STRING_WOW64(); 
       hr = NtWow64ReadVirtualMemory64(handle, pp + offset, ref us, Marshal.SizeOf(us), IntPtr.Zero); 
       if (hr != 0) 
        throw new Win32Exception(hr); 

       if ((us.Buffer == 0) || (us.Length == 0)) 
        return null; 

       string s = new string('\0', us.Length/2); 
       hr = NtWow64ReadVirtualMemory64(handle, us.Buffer, s, us.Length, IntPtr.Zero); 
       if (hr != 0) 
        throw new Win32Exception(hr); 

       return s; 
      } 
      else // we are running with the same bitness as the OS, 32 or 64 
      { 
       PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION(); 
       int hr = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), IntPtr.Zero); 
       if (hr != 0) 
        throw new Win32Exception(hr); 

       IntPtr pp = new IntPtr(); 
       if (!ReadProcessMemory(handle, pbi.PebBaseAddress + processParametersOffset, ref pp, new IntPtr(Marshal.SizeOf(pp)), IntPtr.Zero)) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       UNICODE_STRING us = new UNICODE_STRING(); 
       if (!ReadProcessMemory(handle, pp + offset, ref us, new IntPtr(Marshal.SizeOf(us)), IntPtr.Zero)) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       if ((us.Buffer == IntPtr.Zero) || (us.Length == 0)) 
        return null; 

       string s = new string('\0', us.Length/2); 
       if (!ReadProcessMemory(handle, us.Buffer, s, new IntPtr(us.Length), IntPtr.Zero)) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       return s; 
      } 
     } 
     finally 
     { 
      CloseHandle(handle); 
     } 
    } 

    private const int PROCESS_QUERY_INFORMATION = 0x400; 
    private const int PROCESS_VM_READ = 0x10; 

    [StructLayout(LayoutKind.Sequential)] 
    private struct PROCESS_BASIC_INFORMATION 
    { 
     public IntPtr Reserved1; 
     public IntPtr PebBaseAddress; 
     public IntPtr Reserved2_0; 
     public IntPtr Reserved2_1; 
     public IntPtr UniqueProcessId; 
     public IntPtr Reserved3; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct UNICODE_STRING 
    { 
     public short Length; 
     public short MaximumLength; 
     public IntPtr Buffer; 
    } 

    // for 32-bit process in a 64-bit OS only 
    [StructLayout(LayoutKind.Sequential)] 
    private struct PROCESS_BASIC_INFORMATION_WOW64 
    { 
     public long Reserved1; 
     public long PebBaseAddress; 
     public long Reserved2_0; 
     public long Reserved2_1; 
     public long UniqueProcessId; 
     public long Reserved3; 
    } 

    // for 32-bit process in a 64-bit OS only 
    [StructLayout(LayoutKind.Sequential)] 
    private struct UNICODE_STRING_WOW64 
    { 
     public short Length; 
     public short MaximumLength; 
     public long Buffer; 
    } 

    [DllImport("ntdll.dll")] 
    private static extern int NtQueryInformationProcess(IntPtr ProcessHandle, int ProcessInformationClass, ref PROCESS_BASIC_INFORMATION ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref IntPtr lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref UNICODE_STRING lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [MarshalAs(UnmanagedType.LPWStr)] string lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); 

    [DllImport("kernel32.dll")] 
    private static extern bool CloseHandle(IntPtr hObject); 

    // for 32-bit process in a 64-bit OS only 
    [DllImport("ntdll.dll")] 
    private static extern int NtWow64QueryInformationProcess64(IntPtr ProcessHandle, int ProcessInformationClass, ref PROCESS_BASIC_INFORMATION_WOW64 ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength); 

    [DllImport("ntdll.dll")] 
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, ref long lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("ntdll.dll")] 
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, ref UNICODE_STRING_WOW64 lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("ntdll.dll")] 
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, [MarshalAs(UnmanagedType.LPWStr)] string lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead); 
} 
+1

Tôi nghĩ rằng có 4 kết hợp có thể có của 32 so với quy trình 64 bit. Bạn cũng cần IsWow64Process() để kiểm tra nếu quá trình đích là 32-bit. Oh niềm vui;) –

+0

@ HansPassant - Tôi không nghĩ vậy. Các mã được thực hiện để xử lý 3 kết hợp - không 64 trên 32 tôi thừa nhận :-), bạn đã thử nghiệm nó hoặc nhìn nó một cách cẩn thận? –

+0

* NtWow64ReadVirtualMemory64 * trả về cả mã lỗi HRESULT lẫn mã lỗi Win32. Sử dụng * RtlNtStatusToDosError * để chuyển đổi tín hiệu kết quả thành mã lỗi có thể ném được. – IllidanS4

0

Nguồn "Simon Mourier" hoạt động tốt trong OS, Executor, Target là 32bit. Nhưng những người khác thì không. Vì vậy, tôi Thêm nguồn để xử lý tất cả các kết hợp của 32, 64bit. Có 5 kết hợp có thể có của quy trình 32, 64 bit. Đầu tiên, os, executor, target là 32bit. Thứ hai, os là 64bit, executor, target là sự kết hợp của quá trình 32,64bit. Mã này là tốt công việc trong máy tính xách tay của tôi Win7 64Bit OS, Process 32,64bit & mục tiêu Process 32,64bit, WinXP 32bit, exeutor, mục tiêu là 32bit. Nhưng, sử dụng có nguy cơ của riêng bạn!

// ref: http://www.microsoft.com/whdc/system/Sysinternals/MoreThan64proc.mspx 
public enum PROCESSINFOCLASS : int 
{ 
    ProcessBasicInformation = 0, // 0, q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION 
    ProcessWow64Information = 26, // q: ULONG_PTR 
} 
[Flags] 
public enum PEB_OFFSET 
{ 
    CurrentDirectory, 
    //DllPath, 
    //ImagePathName, 
    CommandLine, 
    //WindowTitle, 
    //DesktopInfo, 
    //ShellInfo, 
    //RuntimeData, 
    //TypeMask = 0xffff, 
    //Wow64 = 0x10000, 
}; 

public class Is64BitChecker 
{ 
    [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool IsWow64Process(
     [In] IntPtr hProcess, 
     [Out] out bool wow64Process 
    ); 

    public static bool GetProcessIsWow64(IntPtr hProcess) 
    { 
     if ((Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) || 
      Environment.OSVersion.Version.Major >= 6) 
     { 
      bool retVal; 
      if (!IsWow64Process(hProcess, out retVal)) 
      { 
       return false; 
      } 
      return retVal; 
     } 
     else 
     { 
      return false; 
     } 
    } 

    public static bool InternalCheckIsWow64() 
    { 
     if ((Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) || 
      Environment.OSVersion.Version.Major >= 6) 
     { 
      using (Process p = Process.GetCurrentProcess()) 
      { 
       bool retVal; 
       if (!IsWow64Process(p.Handle, out retVal)) 
       { 
        return false; 
       } 
       return retVal; 
      } 
     } 
     else 
     { 
      return false; 
     } 
    } 
} 

// All offset values below have been tested on Windows 7 & 8 only 
// but you can use WinDbg "dt ntdll!_PEB" command and search for ProcessParameters offset to find the truth, depending on the OS version 
public static class ProcessUtilities 
{ 
    public static readonly bool Is64BitProcess = IntPtr.Size > 4; 
    public static readonly bool Is64BitOperatingSystem = Is64BitProcess || Is64BitChecker.InternalCheckIsWow64(); 

    public static string GetCurrentDirectory(int processId) 
    { 
     return GetProcessParametersString(processId, PEB_OFFSET.CurrentDirectory); 
    } 

    public static string GetCurrentDirectory(this Process process) 
    { 
     if (process == null) 
      throw new ArgumentNullException("process"); 

     return GetCurrentDirectory(process.Id); 
    } 

    #region GetCommandLine 
    //public static string GetCommandLine(int processId) 
    //{ 
    // return null;// GetProcessParametersString(processId, Is64BitOperatingSystem ? 0x70 : 0x40); 
    //} 

    //public static string GetCommandLine(this Process process) 
    //{ 
    // if (process == null) 
    //  throw new ArgumentNullException("process"); 

    // return GetCommandLine(process.Id); 
    //} 
    #endregion 

    private static string GetProcessParametersString(int processId, PEB_OFFSET Offset) 
    { 
     IntPtr handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, processId); 
     if (handle == IntPtr.Zero) 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 

     bool IsWow64Process = Is64BitChecker.InternalCheckIsWow64(); 
     bool IsTargetWow64Process = Is64BitChecker.GetProcessIsWow64(handle); 
     bool IsTarget64BitProcess = Is64BitOperatingSystem && !IsTargetWow64Process; 

     long offset = 0; 
     long processParametersOffset = IsTarget64BitProcess ? 0x20 : 0x10; 
     switch (Offset) 
     { 
      case PEB_OFFSET.CurrentDirectory: 
       offset = IsTarget64BitProcess ? 0x38 : 0x24; 
       break; 
      case PEB_OFFSET.CommandLine: 
      default: 
       return null; 
     } 

     try 
     { 
      long pebAddress = 0; 
      if (IsTargetWow64Process) // OS : 64Bit, Cur : 32 or 64, Tar: 32bit 
      { 
       IntPtr peb32 = new IntPtr(); 

       int hr = NtQueryInformationProcess(handle, (int)PROCESSINFOCLASS.ProcessWow64Information, ref peb32, IntPtr.Size, IntPtr.Zero); 
       if (hr != 0) throw new Win32Exception(hr); 
       pebAddress = peb32.ToInt64(); 

       IntPtr pp = new IntPtr(); 
       if (!ReadProcessMemory(handle, new IntPtr(pebAddress + processParametersOffset), ref pp, new IntPtr(Marshal.SizeOf(pp)), IntPtr.Zero)) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       UNICODE_STRING_32 us = new UNICODE_STRING_32(); 
       if (!ReadProcessMemory(handle, new IntPtr(pp.ToInt64() + offset), ref us, new IntPtr(Marshal.SizeOf(us)), IntPtr.Zero)) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       if ((us.Buffer == 0) || (us.Length == 0)) 
        return null; 

       string s = new string('\0', us.Length/2); 
       if (!ReadProcessMemory(handle, new IntPtr(us.Buffer), s, new IntPtr(us.Length), IntPtr.Zero)) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       return s; 
      } 
      else if (IsWow64Process)//Os : 64Bit, Cur 32, Tar 64 
      { 
       PROCESS_BASIC_INFORMATION_WOW64 pbi = new PROCESS_BASIC_INFORMATION_WOW64(); 
       int hr = NtWow64QueryInformationProcess64(handle, (int)PROCESSINFOCLASS.ProcessBasicInformation, ref pbi, Marshal.SizeOf(pbi), IntPtr.Zero); 
       if (hr != 0) throw new Win32Exception(hr); 
       pebAddress = pbi.PebBaseAddress; 

       long pp = 0; 
       hr = NtWow64ReadVirtualMemory64(handle, pebAddress + processParametersOffset, ref pp, Marshal.SizeOf(pp), IntPtr.Zero); 
       if (hr != 0) 
        throw new Win32Exception(hr); 

       UNICODE_STRING_WOW64 us = new UNICODE_STRING_WOW64(); 
       hr = NtWow64ReadVirtualMemory64(handle, pp + offset, ref us, Marshal.SizeOf(us), IntPtr.Zero); 
       if (hr != 0) 
        throw new Win32Exception(hr); 

       if ((us.Buffer == 0) || (us.Length == 0)) 
        return null; 

       string s = new string('\0', us.Length/2); 
       hr = NtWow64ReadVirtualMemory64(handle, us.Buffer, s, us.Length, IntPtr.Zero); 
       if (hr != 0) 
        throw new Win32Exception(hr); 

       return s; 
      } 
      else// Os,Cur,Tar : 64 or 32 
      { 
       PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION(); 
       int hr = NtQueryInformationProcess(handle, (int)PROCESSINFOCLASS.ProcessBasicInformation, ref pbi, Marshal.SizeOf(pbi), IntPtr.Zero); 
       if (hr != 0) throw new Win32Exception(hr); 
       pebAddress = pbi.PebBaseAddress.ToInt64(); 

       IntPtr pp = new IntPtr(); 
       if (!ReadProcessMemory(handle, new IntPtr(pebAddress + processParametersOffset), ref pp, new IntPtr(Marshal.SizeOf(pp)), IntPtr.Zero)) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       UNICODE_STRING us = new UNICODE_STRING(); 
       if (!ReadProcessMemory(handle, new IntPtr((long)pp + offset), ref us, new IntPtr(Marshal.SizeOf(us)), IntPtr.Zero)) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       if ((us.Buffer == IntPtr.Zero) || (us.Length == 0)) 
        return null; 

       string s = new string('\0', us.Length/2); 
       if (!ReadProcessMemory(handle, us.Buffer, s, new IntPtr(us.Length), IntPtr.Zero)) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       return s; 
      } 
     } 
     finally 
     { 
      CloseHandle(handle); 
     } 
    } 

    private const int PROCESS_QUERY_INFORMATION = 0x400; 
    private const int PROCESS_VM_READ = 0x10; 

    [StructLayout(LayoutKind.Sequential)] 
    private struct PROCESS_BASIC_INFORMATION 
    { 
     public IntPtr Reserved1; 
     public IntPtr PebBaseAddress; 
     public IntPtr Reserved2_0; 
     public IntPtr Reserved2_1; 
     public IntPtr UniqueProcessId; 
     public IntPtr Reserved3; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct UNICODE_STRING 
    { 
     public short Length; 
     public short MaximumLength; 
     public IntPtr Buffer; 
    } 

    // for 32-bit process in a 64-bit OS only 
    [StructLayout(LayoutKind.Sequential)] 
    private struct PROCESS_BASIC_INFORMATION_WOW64 
    { 
     public long Reserved1; 
     public long PebBaseAddress; 
     public long Reserved2_0; 
     public long Reserved2_1; 
     public long UniqueProcessId; 
     public long Reserved3; 
    } 

    // for 32-bit process 
    [StructLayout(LayoutKind.Sequential)] 
    private struct UNICODE_STRING_WOW64 
    { 
     public short Length; 
     public short MaximumLength; 
     public long Buffer; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct UNICODE_STRING_32 
    { 
     public short Length; 
     public short MaximumLength; 
     public int Buffer; 
    } 

    [DllImport("ntdll.dll")] 
    private static extern int NtQueryInformationProcess(IntPtr ProcessHandle, int ProcessInformationClass, ref PROCESS_BASIC_INFORMATION ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength); 

    //ProcessWow64Information, // q: ULONG_PTR 
    [DllImport("ntdll.dll")] 
    private static extern int NtQueryInformationProcess(IntPtr ProcessHandle, int ProcessInformationClass, ref IntPtr ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref IntPtr lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref UNICODE_STRING lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref UNICODE_STRING_32 lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead); 

    //[DllImport("kernel32.dll", SetLastError = true)] 
    //private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref UNICODE_STRING_WOW64 lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [MarshalAs(UnmanagedType.LPWStr)] string lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); 

    [DllImport("kernel32.dll")] 
    private static extern bool CloseHandle(IntPtr hObject); 

    // for 32-bit process in a 64-bit OS only 
    [DllImport("ntdll.dll")] 
    private static extern int NtWow64QueryInformationProcess64(IntPtr ProcessHandle, int ProcessInformationClass, ref PROCESS_BASIC_INFORMATION_WOW64 ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength); 

    [DllImport("ntdll.dll")] 
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, ref long lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("ntdll.dll")] 
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, ref UNICODE_STRING_WOW64 lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead); 

    [DllImport("ntdll.dll")] 
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, [MarshalAs(UnmanagedType.LPWStr)] string lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead); 
} 
Các vấn đề liên quan