LSPの実装は前節のコードよりも複雑になります。これにより実際にどちらの要求が送られたのかを判断する処理が必要となります。問題を分かりやすくするため、次のようなコードを実行するWinsockアプリケーションを例に挙げます。WSPSocketが呼ばれるWinsockアプリケーションは、最初にWSAStartupを呼び出すことになります。この関数の呼び出しによって、LSPの何らかの関数が呼ばれることはありません。これによりLSPが呼び出し側プロセスにロードされます。そのエントリのDLLがロードされます。WSPSocketが制御を返した場合にsocketも制御を返すことになります。2回目のsocketの呼び出しでは、WSPStartupが呼ばれるとは限りません。WSPSocketのみが呼ばれることになります。それでは、2回目のsocket呼び出しを1回目と異なる引数で実行した場合は、どうなるのでしょうか。答えは、WSPStartupとWSPSocketが呼ばれることになります。LSP内では現在呼び出されている関数がどのプロトコルによるものかを判断する仕組みが必要になります。理由は非常に単純で、あるプロトコルの処理を行う場合に、もう片方のプロトコルのデータを使用するわけにはいかないからです。プロトコル固有のデータは構造体などで管理しておくのがよいと思われます。今回のLSPは、複数のエントリの上にインストールされている場合でも正常に動作するように実装されています。defファイルについては、前節と同様です。NULL);CloseHandle(hFile);}LSPCONTEXT構造体は、1つのプロトコルを処理する場合に必要となるメンバが格納されています。言い換えれば、このメンバに格納される値は各プロトコルによって異なります。nextEntryInfoは次のエントリのプロトコル情報を格納します。lpNextを通じて全てのソケットにアクセスできるようになります。この結果、ソケットからLSPCONTEXT構造体を取得することが可能になります。WSPStartupでは最初に次の処理が行われています。これが0である場合はまだWSPStartupが呼ばれていないことを意味します。この場合、各プロトコル共通で使用するデータを初期化することになります。独自のヒープを作成するためにHeapCreateを呼び出します。これは、HeapDestroyによって、これまで確保したメモリをまとめて開放するようにしたいからです。CreateLspContextは、グローバルに定義されたg_lpLspContextとg_lpLspContextを初期化します。それを基にLSPCONTEXT構造体を初期化することです。2つのエントリが存在しているはずですからそれらを取得します。行うべきことはダミーエントリのIDを取得することです。このエントリのIDを保存します。次に、ダミーエントリのIDと一致するエントリの数をカウントし、この数だけLSPCONTEXT構造体を確保します。先と同じループを実行し、確保したLSPCONTEXT構造体のentryInfoにエントリの内容をコピーします。最後のループは、entryInfoの下に存在するエントリを発見し、それをnextEntryInfoにコピーする処理です。これと一致するエントリを探すようにしています。GetLspContextFromIdとGetLspContextFromSocketという関数が用意されています。後者の関数はソケットから関連するLSPCONTEXT構造体を取得します。どちらの関数を呼び出すかは、呼び出し側の関数の情報量によるでしょう。この構造体のdwCatalogEntryIdからGetLspContextFromIdを呼び出すことができます。現在要求されているプロトコルを特定するのは非常に重要といえます。これを使用すれば間違って他のプロトコルのデータを書き換えることもなくなります。そこに取得したソケットを格納するようにします。lpNextを通じて全てのソケットにアクセスできるような仕組みを作っています。GetLspContextFromSocketを呼び出すことになります。socServer;}lpWSPAcceptで取得したソケットもSOCKETCONTEXT構造体のリストに追加しておくことになります。GetLspContextFromSocketで関連するLSPCONTEXT構造体を取得できるようになります。この構造体をSOCKETCONTEXT構造体のメンバとして保存しておくのも面白いでしょう。WSPCleanupの実装は、次のようになっています。ここで少し問題が発生します。それは、この関数にプロトコルを特定するための引数が存在しないという点です。関数内ではどのLSPCONTEXT構造体を参照すればよいかが分かりません。これを下げ続けて0になった場合は、今回のWSPCleanupが最後の呼び出しということになります。g_lpLspContextの各要素にアクセスしています。