InternetGetCookie
.NETはCookieContrainerクラスをHttpWebRequestとHttpWebResponseにバインドすることで、比較的簡単にWebサーバとやりとりするCookieの処理を実装できるのだが、それは自身で生成するか、サーバから受け取ったCookieだけが対象であり、Webブラウザにより生成、保存されたCookieを共有して利用することはできない。しかし、この処理は、過去にサイトにログインした際に生成、保存したCookieを初回のリクエスト時にWebサーバに送る等、アプリケーションではよくつかう手だ。
InternetExploler等で設定されたCookieを取得するためには、標題のAPIが用意されているのだが、残念ながらこのメソッドはwininetのAPIであり、.NET Framework 2.0のマネジドコードでは提供されていない。従って、マネジドコードから使うにはP/Invoke経由で使う必要がある。(私がメソッドの存在に気が付いていないだけかもしれない)
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool InternetGetCookie( string lpszUrlName, string lpszCookieName, StringBuilder lpszCookieData, [MarshalAs(UnmanagedType.U4)] ref int lpdwSize ); //P/Invoke.NETでは以下のようにマッピングされていた [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError=true)] public static extern bool InternetGetCookie( string lpszUrlName, string lpszCookieName, [Out] string lpszCookieData, [MarshalAs(UnmanagedType.U4)] out int lpdwSize );
同じ第3パラメタをStringBuilderと[Out] stringマップしているのは、実際にどちらで使っても書ける。stringでマップした場合は取得した文字列が"\0\0"でターミネートされるので、トリムする必要があるだけだ。(これって、今後のことを考えるとどちらを使うのが良いのだろう。)
P/Invokeの記述が出来たら、後はマネジドコードから使うだけ。(第3パラメタに[Out]stringを使う例は省略)
public static string RetrieveIECookies(string url) { StringBuilder cookieHeader = new StringBuilder(new String(' ', 256), 256); int datasize = cookieHeader.Length; if (!InternetGetCookie(url, null, cookieHeader, ref datasize)) { if (datasize < 0) return String.Empty; new StringBuilder(datasize); InternetGetCookie(url, null, cookieHeader, ref datasize); } return cookieHeader.ToString(); }
このメソッドで取得したCookieを今日の最初のエントリで紹介したSetCookiesメソッドでCookieContainerにセットして、HttpWebRequestにパインドしてやれば、既に存在しているCookieを初回のGETなりPOSTなりでWebサーバに送信できる。
Uri uri = new Uri("http://hoge.com/hogehoge"); HttpWebRequest httpRequest = (HttpWebRequest)HttpWebRequest.Create(uri); CookieContainer cookieContainer = new CookieContainer(); cookieContainer.SetCookies(uri, RetrieveIECookies(uri.AbsoluteUri)); httpRequest.CookieContainer = cookieContainer;