Moore's Mind

Thursday, October 27, 2005

Peer Name Resolution (PNRP) - The Code Project - C# Programming

My article about PNRP was just posted here on the Code Project web site.

Tuesday, October 18, 2005

New PNRP Functions

Windows Vista October CTP contains some new PNRP functions that remove the previous complexity of having to use the underlying WSAxxx functions. Since the Windows SDK won't be updated until Beta 2, here's a guess at what these functions probably do.

PeerPnrpGetCloudInfo - probably returns a PNRPCLOUDINFO structure. Not sure how to Enum clouds though. Equivalent to this.

PeerPnrpGetEndpoint - probably converts a peer name to an endpoint

PeerPnrpRegister, PeerPnrpUnregister - probably registers and unregisters a peer name in the serverless DNS. Equivalent to this and this.

PeerPnrpUpdateRegistration - probably allows info such as address and comment to be updated for a previously registered peer name

PeerPnrpResolve - probably determines if a peer name exists. Equivalent to this.

PeerPnrpStartResolve, PeerPnrpEndResolve - asynchronous version

Monday, October 17, 2005

Windows Vista October CTP (Ultimate Edition)

Install was very easy, and finally provided drivers for all my hardware.

The Windows Collaboration is still busted due to a missing file (RPCSHIM.DLL) referenced by RPCHTTP.DLL. If anyone knows of a quick fix, drop me a comment.

A quick check using dependency walker shows that this build has all the good stuff; new PeerCollab API's and some new Pnrp helper API's. Can't wait for an updated SDK header file to get these exposed to managed code.

Overall, Explorer is a little buggier, but the UI is looking much better.

Keep up the good work Microsoft.

Saturday, October 15, 2005

PeerPnrpToDnsName and PeerDnsToPnrpName

In case anyone is interested, the C# DllImports are below...

[DllImport("pnrpnsp.dll", CharSet=CharSet.Unicode)]internal static extern int PeerPnrpToDnsName(string pwszPnrpNameStr, System.Text.StringBuilder pwszDnsNameStr, ref int pcchDnsName);

[DllImport("pnrpnsp.dll", CharSet=CharSet.Unicode)]
internal static extern int PeerDnsToPnrpName(string pwszDnsNameStr, System.Text.StringBuilder pwszPnrpNameStr, ref int pcchPnrpName);

Use the following code to call the first function...

int length = 255;
System.Text.StringBuilder DnsName = new System.Text.StringBuilder(length);
int err = PnrpNative.PeerPnrpToDnsName(PnrpName, DnsName, ref length);

In the first case, take any Peer Name, for example, 0.test (zero.test) previously registered to get the equivalent serverless DNS name. In this case, is returned. Passing this into the second function returnes the original 0.test peer name. Use

netsh p2p pnrp cloud>show names

to see other peer name examples that may be registered on your computer. I'm still not sure what the benefit of getting the DNS name gives me.

What I'd like to know though is what parameters do you need to pass to PNRP lookup to get the equivalent of netsh p2p pnrp cloud> show names list of registered names? If anyone knows, please leave a comment.

Software Development Manager

You'd think that being a software development manager, I'd have my sleeves rolled up every day churning out code. Actually, its the opposite. Once you become a "manager", you do very little coding. Instead, my job is to plan and think ahead to eliminate as many obstacles and risks to the people who do the real coding. My job is to make sure the development "process" is followed to increase the odds that we deliver what the customer wants with a minimum number of deficiencies as possible (oh! and on schedule and on budget). Its an interesting balancing act.

I've been on vacation this week. With two young children in daycare/pre-school/kindergarten, the bills are high so we don't have much money left to go anywhere. Besides, it was a chance to get a break from work and kids. It has been a excellent opportunity to do some coding...

Wednesday, October 12, 2005

Thread was being stopped.

While debugging a test application that is using my managed wrapper for Microsoft's Peer-to-Peer API's, I kept getting the following error: "Thread was being stopped."

A quick search via Google shows that others have had the same problem. I found the answer at the end of this link. Turns out I was watching a listbox control. I removed this from the Watch Window and suddenly the problem went away.

Hope this helps someone.

Wednesday, October 05, 2005

Tripp Parks's WebLog : Most Annoying API

Tripp Park posted this message about the most annoying Windows API to use.

All I can say is: " I feel your pain ".

I've been working on implementing the Peer Name Resolution functions from C# via Interop and this one is definitely giving me some trouble. PNRP is the foundation for finding peers via the PeerGraph and PeerGroup API sets.

The following code *does not* appear to work.

PNRPINFO pnrpInfo = new PNRPINFO();
BLOB blPnrpData = new BLOB();
// fill a CSADDR_INFO structure from the address
csaAddr.iProtocol = 6; // IPPROTO_TCP
csaAddr.iSocketType = 1; // SOCK_STREAM;
csaAddr.LocalAddr.iSockaddrLength = Marshal.SizeOf(typeof(SOCKADDR_IN6));
SOCKADDR_IN6 address = new SOCKADDR_IN6();
address.sin6_addr = Registration.Address.GetAddressBytes();
csaAddr.LocalAddr.lpSockaddr = Marshal.AllocHGlobal(csaAddr.LocalAddr.iSockaddrLength);
Marshal.StructureToPtr(address, csaAddr.LocalAddr.lpSockaddr, false);
// build the WSAQUERYSET required to register
pnrpInfo.dwSize = Marshal.SizeOf(typeof(PNRPINFO));
pnrpInfo.dwLifetime = Lifetime;
pnrpInfo.lpwszIdentity = Registration.PeerId;
blPnrpData.cbSize = Marshal.SizeOf(typeof(PNRPINFO));
blPnrpData.pBlobData = Marshal.AllocHGlobal(blPnrpData.cbSize);
Marshal.StructureToPtr(pnrpInfo, blPnrpData.pBlobData, false);
querySet.dwSize = Marshal.SizeOf(typeof(WSAQUERYSET));
querySet.dwNameSpace = 38; // NS_PNRPNAME
querySet.dwNumberOfCsAddrs = 1; // one address

querySet.lpServiceClassId = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
Marshal.StructureToPtr(SVCID_PNRPNAMEV1, querySet.lpServiceClassId, false);

querySet.lpszServiceInstanceName = Registration.Name;
querySet.lpszContext = Registration.CloudName;
querySet.lpszComment = Registration.Comment;

querySet.lpcsaBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CSADDR_INFO)));
Marshal.StructureToPtr(csaAddr, querySet.lpcsaBuffer, false);

querySet.lpBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(BLOB)));
Marshal.StructureToPtr(blPnrpData, querySet.lpBlob, false);

IntPtr qryptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WSAQUERYSET)));
Marshal.StructureToPtr(querySet, qryptr, false);

uint hr = PnrpNative.WSASetService(qryptr, WSAESETSERVICEOP.Register, 0);
if (hr != 0) throw new System.Net.Sockets.SocketException((int)hr);

Here are the structure definitions:

internal struct SOCKET_ADDRESS
public IntPtr lpSockaddr; // LPSOCKADDR
public int iSockaddrLength;
internal struct CSADDR_INFO
public SOCKET_ADDRESS LocalAddr;
public SOCKET_ADDRESS RemoteAddr;
public int iSocketType;
public int iProtocol;
internal struct BLOB
public int cbSize;
public IntPtr pBlobData;
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct WSAQUERYSET
public int dwSize;
public string lpszServiceInstanceName;
public IntPtr lpServiceClassId; // LPGUID
public IntPtr lpVersion; // LPWSAVERSION
public string lpszComment;
public int dwNameSpace;
public IntPtr lpNSProviderId; // LPGUID
public string lpszContext;
public int dwNumberOfProtocols;
public IntPtr lpafpProtocols; // LPAFPROTOCOLS
public IntPtr lpszQueryString; // can be NULL
public int dwNumberOfCsAddrs;
public IntPtr lpcsaBuffer; // LPCSADDR_INFO
public int dwOutputFlags;
public IntPtr lpBlob; // LPBLOB

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct PNRPINFO
public int dwSize;
public string lpwszIdentity;
public int nMaxResolve;
public int dwTimeout;
public int dwLifetime;
public PNRP_RESOLVE_CRITERIA enResolveCriteria;
public int dwFlags;
public SOCKET_ADDRESS saHint;

If anyone get's this working, please share...

Saturday, October 01, 2005


Why does PeerCollabEnumCapabilities return "The parameter is incorrect" when I pass the PEER_ENDPOINT part of a PEER_ENDPOINT_NEAR_ME data structure. Does this function allow enumerating the capabilities of a endpoint near me that isn't in my list of contacts?

Below is the managed definition for this function:

[DllImport("p2p.dll", PreserveSig=true)]
internal static extern uint PeerCollabEnumCapabilities(IntPtr pcContact, IntPtr pcEndpoint, IntPtr pCapabilityId, ref IntPtr phPeerEnum);

Since some parameters can be NULL, I'm using IntPtr and having to Marshal each data structure. The structure definition for a PEER_ENDPOINT is:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct PEER_ENDPOINT
public PEER_ADDRESS address;
[MarshalAs(UnmanagedType.LPWStr)] public String pwzEndpointName;

internal struct PEER_ADDRESS
public uint dwSize;
public SOCKADDR_IN6 sin6;

[Serializable, StructLayout(LayoutKind.Sequential)]
internal struct SOCKADDR_IN6
public short sin6_family;
public ushort sin6_port;
public uint sin6_flowinfo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=0x10)]
public byte[] sin6_addr;
public uint sin6_scope_id;

I'm calling this function in the following way...

IntPtr conptr = IntPtr.Zero;
if (contact != null)
PEER_CONTACT ncon = contact.Convert();
conptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PEER_CONTACT)));
Marshal.StructureToPtr(ncon, conptr, true);
IntPtr epptr = IntPtr.Zero;
if (endpoint != null)
PEER_ENDPOINT nep = endpoint.Convert();
epptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PEER_ENDPOINT)));
Marshal.StructureToPtr(nep, epptr, true);
IntPtr capptr = IntPtr.Zero;
result = PeerCollabNative.PeerCollabEnumCapabilities(conptr, epptr, capptr, ref hPeerEnum);

Any help is appreciated.