匿名管道重定向命令行输出

首先是MFC,注意事项:
1、管道读写是FIFO
2、读写指针,要记得关闭
3、编译时用了UNICODE,但CMD读取回来时ANSI,所以要转换一下字符集

	SECURITY_ATTRIBUTES sa;
	ZeroMemory(&sa, sizeof(sa));
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;

	HANDLE hRead, hWrite;
	if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
		MessageBox(L"Error On CreatePipe()");
		return;
	}

	STARTUPINFO si;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(STARTUPINFO);
	GetStartupInfo(&si);
	si.hStdError = hWrite;
	si.hStdOutput = hWrite;
	si.wShowWindow = SW_HIDE;
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	PROCESS_INFORMATION pi;
	ZeroMemory(&pi, sizeof(pi));
	if (!::CreateProcess(L"C:\\Windows\\System32\\cmd.exe", L"/c dir /b D:\\Downloads"
		, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi)) {
		showMeErrorInfo();	
		return;
	}
	CloseHandle(hWrite);

	char buffer[4096] = { 0 };
	DWORD bytesRead;
	while (true) {
		if (ReadFile(hRead, buffer, 4095, &bytesRead, NULL) == NULL)
		{
			break;
		}
		
		UINT CodePage = 0;
		DWORD dwNum;
		dwNum = MultiByteToWideChar(CodePage, 0, buffer, -1, NULL, 0);
		if (dwNum)
		{
			wchar_t *pwText;
			pwText = new TCHAR[dwNum];
			if (pwText)
			{
				MultiByteToWideChar(CodePage, 0, buffer, -1, pwText, dwNum);
			}
			//m_Edit.SetWindowText(pwText);
			delete[]pwText;
			pwText = NULL;
		}
		UpdateData(false);
		Sleep(200);
	}
	CloseHandle(hRead);

C#的话,就简单多了:

            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = "C:\\Windows\\System32\\cmd.exe";
            startInfo.Arguments = "/c dir /b D:\\Downloads";
            startInfo.RedirectStandardOutput = true;
            //startInfo.RedirectStandardError = true;
            startInfo.UseShellExecute = false;
            startInfo.CreateNoWindow = false;
           
            Process p=Process.Start(startInfo);

            String cmdOut = "";
            while(!p.HasExited)
            { 
                cmdOut = p.StandardOutput.ReadLine();
                textBox1.Text += cmdOut + "\r\n";
                p.WaitForExit(10);
            }
            cmdOut = p.StandardOutput.ReadToEnd() + "\r\n";
            textBox1.Text += cmdOut ;

使用WM_COPYDATA实现跨进程通讯(下)

请注意:
A、SendMessage在接收方处理完毕前不会返回,会产生严重阻塞
B、由于使用了非托管内存,要注意进行清理

1、发送方WinForm

        public const int WM_COPYDATA = 0x004A;
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            public IntPtr lpData;
        }

        public void sendData(String msg, Boolean isUnicode)
        {
            COPYDATASTRUCT cds = new COPYDATASTRUCT();
            cds.cbData = (msg.Length + 1) * (isUnicode ? 2:1);
            cds.lpData = (isUnicode ? Marshal.StringToCoTaskMemUni(msg) : Marshal.StringToCoTaskMemAnsi(msg));

            IntPtr cdsPtr = Marshal.AllocHGlobal(Marshal.SizeOf(cds));
            Marshal.StructureToPtr(cds, cdsPtr, false);

            IntPtr clientWnd = Win32Helper.GetCurrentWindowHandle();
            SendMessage(clientWnd, WM_COPYDATA, IntPtr.Zero, cdsPtr);

            Marshal.FreeHGlobal(cdsPtr);
            Marshal.FreeCoTaskMem(cds.lpData);
        }

2、接收方WinForm

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            public string lpData;
        }

        public const int WM_COPYDATA = 0x004A;
        protected override void WndProc(ref System.Windows.Forms.Message msg)
        {
            string msgTxt = "";
            COPYDATASTRUCT cds = new COPYDATASTRUCT();
            switch (msg.Msg)
            {
                case WM_COPYDATA:
                    if(msg.LParam!=IntPtr.Zero)
                    {
                        cds = (COPYDATASTRUCT)msg.GetLParam(cds.GetType());
                        String msgstr = cds.lpData;
                        //MessageBox.Show(msgstr);
                    }
                    break;
                default:
                    base.WndProc(ref msg);
                    break;
            }
        }

C#获取dll自身路径

            //获取dll的绝对路径,请根据不同情况自己选用
            MessageBox.Show(System.Reflection.Assembly.GetExecutingAssembly().Location);
            MessageBox.Show(System.Reflection.Assembly.GetEntryAssembly().Location);   
            MessageBox.Show(System.Windows.Forms.Application.ExecutablePath);
            MessageBox.Show(System.Windows.Forms.Application.StartupPath);
            MessageBox.Show(System.Environment.CurrentDirectory);
            MessageBox.Show(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);

C#枚举窗口句柄

在CS程序中启动其他应用后,要获取进程的主窗体其实很简单:

        Process p = Process.Start(exePath);
        //p.WaitForInputIdle();
        p.Refresh(); 
        IntPtr mainWnd = p.MainWindowHandle;

但是,总有很多特殊的情况,上面的方法根本无法用,所以,要用Windows API来搞定了

1、如果窗口信息很固定而且没有重名的话,可以用Findwindow搞定

        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        IntPtr clientWnd = FindWindow(null,"FormClient");

2、根据标题枚举窗口句柄

        //枚举窗体
        [DllImport("User32.dll", EntryPoint = "EnumWindows", SetLastError = true)]
        public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam);
        //获取窗体标题
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int GetWindowText(IntPtr hWnd, StringBuilder lpText, int nCount);
        //设置错误状态
        [DllImport("kernel32.dll", EntryPoint = "SetLastError")]
        public static extern void SetLastError(uint dwErrCode);

        //线程主窗口句柄
        private static IntPtr processMainWnd = IntPtr.Zero;
        //要查找的窗口名称
        private static String winTitle = "__Web__Form__Main__";

        //声明委托函数
        public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam);

        //枚举进程句柄,非线程安全
        [SecuritySafeCritical]
        public static IntPtr GetCurrentWindowHandle()
        {
            IntPtr ptrWnd = IntPtr.Zero;

            bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), (uint)0);
            if (!bResult && Marshal.GetLastWin32Error() == 0)
            {
                ptrWnd = processMainWnd;
            }

            return ptrWnd;
        }

        //枚举函数,获取主窗口句柄然后退出
        [SecuritySafeCritical]
        private static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
        {
            //根据标题获取窗体
            var sb = new StringBuilder(50);
            GetWindowText(hwnd, sb, sb.Capacity);

            if (winTitle.Equals(sb.ToString()))
            {
                processMainWnd = hwnd;
                SetLastError(0);
                return false;
            }

            return true;
        }

3、跟进进程id枚举获取主窗体句柄

        //枚举窗体
        [DllImport("User32.dll", EntryPoint = "EnumWindows", SetLastError = true)]
        //获取父窗体
        [DllImport("user32.dll", EntryPoint = "GetParent", SetLastError = true)]
        //根据窗口获取线程句柄
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern int GetWindowThreadProcessId(IntPtr hwnd, out uint pid);
        //设置错误状态
        [DllImport("kernel32.dll", EntryPoint = "SetLastError")]
        public static extern void SetLastError(uint dwErrCode);

        //线程主窗口句柄
        private static IntPtr processMainWnd = IntPtr.Zero;

        //枚举进程句柄
        [SecuritySafeCritical]
        public static IntPtr GetCurrentWindowHandle(int processId)
        {
            IntPtr ptrWnd = IntPtr.Zero;

            bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), (uint)processId);
            if (!bResult && Marshal.GetLastWin32Error() == 0)
            {
                ptrWnd = processMainWnd;
            }

            return ptrWnd;
        }

        //枚举函数,获取主窗口句柄然后退出
        [SecuritySafeCritical]
        private static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
        {
            uint uiPid = 0;
            //根据启动方式不同,这里要有相应修改
            if (GetParent(hwnd) == IntPtr.Zero)
            {
                GetWindowThreadProcessId(hwnd, out uiPid);
                if (uiPid == lParam)
                {
                    processMainWnd = hwnd;
                    SetLastError(0);
                    return false;
                }
            }
        }

4、跟进窗口WindowsClassName举获取主窗体句柄

        //查找桌面
        [DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern IntPtr GetDesktopWindow();
        //获取窗体句柄
        [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        public static extern IntPtr GetWindow(IntPtr hwnd, int wFlag);
        //获取窗体类
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        public const int GW_CHILD = 5;
        public const int GW_HWNDNEXT = 2;

        //枚举桌面窗口,根据WindowsClassName获取句柄
        [SecuritySafeCritical]
        public static IntPtr GetWinHandleByClasName(String windowClassNmae)
        {   
            //取得桌面窗口,再获取第一个子窗口
            IntPtr hwnd = GetDesktopWindow();
            hwnd = GetWindow((IntPtr)hwnd, System.Convert.ToInt32(GW_CHILD));
            
            //通过循环来枚举所有的子窗口
            while ((long)hwnd != 0)
            {
                System.Text.StringBuilder ClassName = new System.Text.StringBuilder(256);
                GetClassName((IntPtr)hwnd, ClassName, ClassName.Capacity);
                String tmpClassName= ClassName.ToString().Trim();
                if (tmpClassName.Length > 0)
                {
                    if (tmpClassName.Equals(windowClassNmae))
                    {
                        break;
                    }
                }

                hwnd = GetWindow((IntPtr)hwnd, System.Convert.ToInt32(GW_HWNDNEXT));
            }

            return hwnd;
        }

C# Https Soap Client

1、Soap Https Soap Client

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace IISSoapClientTest
{
    class Program
    {
        public static void HelloHttp(string url)
        {
            Hello h = new Hello(url);
            string ans = h.HelloWorld("C# http client");
            Console.WriteLine(ans);
            Console.WriteLine();
        }

        //同样的证书,IIS可以过,Tomcat过不去
        public static void HelloHttps(string url,String certPath)
        {
            X509CertificateCollection certs = new X509CertificateCollection();
            X509Certificate cert = X509Certificate.CreateFromCertFile(certPath);

            Hello h = new Hello(url);
            h.ClientCertificates.Add(cert);
            string ans = h.HelloWorld("C# https client");
            Console.WriteLine(ans);
            Console.WriteLine();
        }

        //绕过证书检查
        public static void HelloHttpsWithRemoteCertificateValidationCallback(string url)
        {
            //ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(RemoteCertificateValidationCallback);

            Hello h = new Hello(url);
            string ans = h.HelloWorld("C# https client");
            Console.WriteLine(ans);
            Console.WriteLine();
        }

        private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, 
            X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }  

        static void Main(string[] args)
        {
            //HelloHttp("http://127.0.0.1:80/Hello.asmx");
            //HelloHttps("https://127.0.0.1:443/Hello.asmx");
            //HelloHttpsWithRemoteCertificateValidationCallback("https://127.0.0.1:443/Hello.asmx");

            //HelloHttp("http://127.0.0.1:8080/SoapTest/services/HelloService");
            HelloHttps("https://127.0.0.1:8443/SoapTest/services/HelloService", @"D:\DiskE\Projects\VS2010\TestProjects\SSLSocket\myKeyStore.cer");
            //HelloHttpsWithRemoteCertificateValidationCallback("https://127.0.0.1:8443/SoapTest/services/HelloService");
        }
    }
}

C# Https Soap Server(IIS7)

1、首先准备一个p12格式的服务端证书
无论是购买,还是用openssl或java keytool生成自签名证书都可以

2、在IIS7的根目录,选中“安全性->根目录证书”,选择“导入”即可

3、如果显示证书链有问题,则在IE中导入CA证书就好了

4、在需要HTTPS的网站上,选择“绑定”,绑定类型为https,选择需要的证书

5、在客户端的IE中,导入CA证书就好了

SSLSocket C# Part1

1、SSLSocket Server

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

namespace SSLSocket
{
    class SSLSocketServer
    {
        static X509Certificate serverCertificate = null;
        static String delimiter = "=========================================================";

        public static void RunServer(String ip,int port,String p12Path)
        {
            serverCertificate = new X509Certificate2(p12Path, "sslTestPwd");

            TcpListener listener = new TcpListener(IPAddress.Parse(ip), port);
            listener.Start();
            while (true)
            {
                try
                {
                    TcpClient client = listener.AcceptTcpClient();
                    ProcessClient(client);
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }

        static void ProcessClient(TcpClient client)
        {
            SslStream sslStream = new SslStream(client.GetStream(), false);
            try
            {
                //sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls | SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.None, true);
                sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Ssl2 | SslProtocols.Ssl3, true);
                DisplaySecurityLevel(sslStream);
                DisplayCertificateInformation(sslStream);

                sslStream.ReadTimeout = 5000;
                sslStream.WriteTimeout = 5000;
                string messageData = ReadMessage(sslStream);
                Console.WriteLine(delimiter);
                Console.WriteLine("收到信息: {0}", messageData);
                Console.WriteLine(delimiter);
                //byte[] message = Encoding.UTF8.GetBytes("Hello from the server.");
                //Console.WriteLine("Sending hello message.");
                //sslStream.Write(message);
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
                if (e.InnerException != null)
                {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                Console.WriteLine("Authentication failed - closing the connection.");
                sslStream.Close();
                client.Close();
                return;
            }
            finally
            {
                sslStream.Close();
                client.Close();
            }
        }

        static string ReadMessage(SslStream sslStream)
        {
            byte[] buffer = new byte[2048];
            StringBuilder messageData = new StringBuilder();
            int bytes = -1;
            do
            {
                bytes = sslStream.Read(buffer, 0, buffer.Length);
                Decoder decoder = Encoding.UTF8.GetDecoder();
                char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                decoder.GetChars(buffer, 0, bytes, chars, 0);
                messageData.Append(chars);
                if (messageData.ToString().IndexOf("") != -1)
                {
                    break;
                }
            }
            while (bytes != 0);

            return messageData.ToString();
        }

        static void DisplaySecurityLevel(SslStream stream)
        {
            Console.WriteLine(delimiter);
            Console.WriteLine("通讯协议: {0}", stream.SslProtocol);
            Console.WriteLine("加密算法: {0} strength {1}", stream.CipherAlgorithm, stream.CipherStrength);
            Console.WriteLine("哈希算法: {0} strength {1}", stream.HashAlgorithm, stream.HashStrength);
            Console.WriteLine("密钥交换算法: {0} strength {1}", stream.KeyExchangeAlgorithm, stream.KeyExchangeStrength);
            Console.WriteLine(delimiter);
        }

        static void DisplayCertificateInformation(SslStream stream)
        {
            Console.WriteLine(delimiter);
            Console.WriteLine("证书吊销列表检查: {0}", stream.CheckCertRevocationStatus);

            X509Certificate localCertificate = stream.LocalCertificate;
            if (stream.LocalCertificate != null)
            {
                Console.WriteLine("本地证书签发者: {0}", localCertificate.Subject);
                Console.WriteLine("本地证书有效期: {0}~{1}", localCertificate.GetEffectiveDateString(),
                    localCertificate.GetExpirationDateString());
            }
            else
            {
                Console.WriteLine("本地证书为空");
            }

            X509Certificate remoteCertificate = stream.RemoteCertificate;
            if (stream.RemoteCertificate != null)
            {
                Console.WriteLine("远程证书签发者: {0}", remoteCertificate.Subject);
                Console.WriteLine("远程证书有效期: {0}至{1}", remoteCertificate.GetEffectiveDateString(),
                    remoteCertificate.GetExpirationDateString());
            }
            else
            {
                Console.WriteLine("远程证书为空");
            }
            Console.WriteLine(delimiter);
        }

    }
}

2、SSLSocket Client

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

namespace SSLSocketClient
{
    class SSLSocketClient
    {
        //回调函数验证证书
        public static bool ValidateServerCertificate(
              object sender,
              X509Certificate certificate,
              X509Chain chain,
              SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
            {
                return true;
            }

            if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch || sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors)
            {
                return true;
            }

            return false;
        }

        public static void SendMessage(string ip, int port,String certPath, String msg)
        {
            TcpClient client = new TcpClient(ip, port);
            SslStream sslStream = new SslStream(client.GetStream(),
                false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);

            X509CertificateCollection certs = new X509CertificateCollection();
            X509Certificate cert = X509Certificate.CreateFromCertFile(certPath);
            certs.Add(cert);

            try
            {
                sslStream.AuthenticateAsClient("AtlasTiger", certs, SslProtocols.Tls, false);
                //sslStream.AuthenticateAsClient("AtlasTiger", certs, SslProtocols.Ssl3, false);

                //sslStream.AuthenticateAsClient("AtlasTiger", certs, SslProtocols.Ssl2, false);
                //sslStream.AuthenticateAsClient("AtlasTiger", certs, SslProtocols.None, false);
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine("Authentication failed : " + e);
                client.Close();
                return;
            }

            byte[] messsage = Encoding.UTF8.GetBytes(msg);
            sslStream.Write(messsage);
            sslStream.Flush();

            client.Close();
        }
    }
}

CS访问网络资源

using System.Runtime.InteropServices;
 
public class WNetHelper
{
	 [DllImport("mpr.dll", EntryPoint = "WNetAddConnection2")]
	 private static extern uint WNetAddConnection2(NetResource lpNetResource, string lpPassword, string lpUsername, uint dwFlags);
 
	 [DllImport("Mpr.dll", EntryPoint = "WNetCancelConnection2")]
	 private static extern uint WNetCancelConnection2(string lpName, uint dwFlags, bool fForce);
 
	 [StructLayout(LayoutKind.Sequential)]
	 public class NetResource
	 {
		  public int dwScope;
		  public int dwType;
		  public int dwDisplayType;
		  public int dwUsage;
		  public string lpLocalName;
		  public string lpRemoteName;
		  public string lpComment;
		  public string lpProvider;
	 }
 
	 public static uint WNetAddConnection(string username, string password, string remoteName, string localName)
	 {
		  NetResource netResource = new NetResource();
 
		  netResource.dwScope = 2;
		  netResource.dwType = 1;
		  netResource.dwDisplayType = 3;
		  netResource.dwUsage = 1;
		  netResource.lpLocalName = localName;
		  netResource.lpRemoteName = remoteName.TrimEnd('\\');
		  uint result = WNetAddConnection2(netResource, password, username, 0);
 
		  return result;
	 }
 
	 public static uint WNetCancelConnection(string name, uint flags, bool force)
	 {
		  uint nret = WNetCancelConnection2(name, flags, force);
		  return nret;
	 }
}

C#调用cdll指针参数处理

1、API声明(包括**参数)

int GetTheLastErrorA(char **pcError);
int GetTheLastErrorW(wchar_t **pwError);

2、C#代码

using System.Runtime.InteropServices;

[DllImport("StringAW.dll", CallingConvention = CallingConvention.Winapi, 
CharSet = CharSet.Ansi, EntryPoint = "GetTheLastErrorA")]
extern static int GetTheLastErrorA(ref IntPtr a);

[DllImport("StringAW.dll", CallingConvention = CallingConvention.Winapi, 
CharSet = CharSet.Auto, EntryPoint = "GetTheLastErrorW")]
extern static int GetTheLastErrorW(ref IntPtr w);

IntPtr a = IntPtr.Zero;
GetTheLastErrorA(ref a);
String sa = Marshal.PtrToStringAnsi(a);
MessageBox.Show(sa);

IntPtr w = IntPtr.Zero;
GetTheLastErrorW(ref w);
String sw = Marshal.PtrToStringUni(w);
MessageBox.Show(sw);