2025-11-28 00:35:46 +09:00

1292 lines
38 KiB
C

/********************************************************************++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1985-2007 Microsoft Corporation. All Rights Reserved.
Abstract:
This C file includes sample code for working with contacts using
the Microsoft Peer-to-Peer Collaboration APIs.
Note:
This peer to peer application requires global IPv6 connectivity.
--********************************************************************/
#pragma warning(disable:4201) // nameless struct/union
#include <p2p.h>
#include <stdio.h>
#include <strsafe.h>
#include <Tlhelp32.h>
#include "Shared.h"
GUID MESSAGE_GUID = { /* 191312ce-4466-4dc4-a8d6-cb2e9710157f */
0x191312ce,
0x4466,
0x4dc4,
{0xa8, 0xd6, 0xcb, 0x2e, 0x97, 0x10, 0x15, 0x7f}
};
#define ROUND_UP_COUNT(Count,Pow2) \
( ((Count)+(Pow2)-1) & (~(((LONG)(Pow2))-1)) )
// If Ptr is not already aligned, then round it up until it is.
#define ROUND_UP_POINTER(Ptr,Pow2) \
( (LPVOID) ( (((ULONG_PTR)(Ptr))+(Pow2)-1) & (~(((LONG)(Pow2))-1)) ) )
// Usage: myPtr = ROUND_UP_POINTER( unalignedPtr, ALIGN_LPVOID )
#define ALIGN_LPVOID sizeof(LPVOID)
//-----------------------------------------------------------------------------
// Function: ChangeType
// Purpose: Convert the enum PEER_CHANGE_TYPE to a string
// Parameters:
// eChangeType : [in] enum value to convert to a string
//
const WCHAR *ChangeType(__in const PEER_CHANGE_TYPE eChangeType)
{
const static PWSTR rgEventType[] =
{
L"Added",
L"Deleted",
L"Updated"
};
if (eChangeType >= celems(rgEventType))
{
return L"";
}
return rgEventType[eChangeType];
}
//-----------------------------------------------------------------------------
// Function: ChangeType
// Purpose: Convert the enum PEER_PUBLICATION_SCOPE to a string
// Parameters:
// ePublicationScope : [in] enum value to convert to a string
//
const WCHAR *PublicationScope(__in const PEER_PUBLICATION_SCOPE ePublicationScope)
{
const static PWSTR rgPublicationScope[] =
{
L"None",
L"Near Me",
L"Internet",
L"All"
};
if (ePublicationScope >= celems(rgPublicationScope))
{
return L"";
}
return rgPublicationScope[ePublicationScope];
}
//-----------------------------------------------------------------------------
// Function: ChangeType
// Purpose: Convert the enum PEER_PRESENCE_STATUS to a string
// Parameters:
// ePresenceStatus : [in] enum value to convert to a string
//
const WCHAR *PresenceStatus(__in const PEER_PRESENCE_STATUS ePresenceStatus)
{
const static PWSTR rgPresence[] =
{
L"Offline",
L"Out to lunch",
L"Away",
L"Be Right Back",
L"Idle",
L"Busy",
L"On the phone",
L"Online"
};
if (ePresenceStatus >= celems(rgPresence))
{
return L"";
}
return rgPresence[ePresenceStatus];
}
//-----------------------------------------------------------------------------
// Function: PrintError
// Purpose: Utility routine to print an error and the associated error string
// Parameters: hr error obtained
//
void PrintError(HRESULT hrError)
{
DWORD dwCch=0;
WCHAR wszBuffer[ERRBUFSIZE] = {0};
if (HRESULT_FACILITY(hrError) == FACILITY_P2P)
{
HMODULE hResDll = GetModuleHandle(L"p2p.dll");
if (NULL != hResDll)
{
dwCch = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE,
hResDll,
HRESULTTOWIN32(hrError),
0,
wszBuffer,
ERRBUFSIZE,
NULL);
FreeLibrary(hResDll);
if (dwCch > 0)
{
wprintf(L"Error Description: %s\n", wszBuffer);
}
}
}
else
{
dwCch = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
HRESULTTOWIN32(hrError),
0,
wszBuffer,
ERRBUFSIZE,
NULL);
if (dwCch > 0)
{
wprintf(L"Error Description: %s\n", wszBuffer);
}
}
}
//-----------------------------------------------------------------------------
// Function: PrintInvitation
// Purpose: Prints out a PEER_INVITATION structure to the console
// Parameters:
// pInvitation : [in] pointer to PEER_INVITATION structure
//
void PrintInvitation(PCPEER_INVITATION pInvitation)
{
PWSTR pwzApplicationId = NULL;
wprintf(L"\tApplication:\n");
if (UuidToString(&pInvitation->applicationId, &pwzApplicationId) == RPC_S_OK)
{
wprintf(L"\t Application Id: %s\n", pwzApplicationId);
RpcStringFree(&pwzApplicationId);
}
if (pInvitation->pwzMessage != NULL)
{
wprintf(L"\t Message: %s\n", pInvitation->pwzMessage );
}
wprintf(L"\tApplication Data\n");
wprintf(L"\t Application Data Size: %d\n", pInvitation->applicationData.cbData);
if (pInvitation->applicationData.cbData > 0)
{
wprintf(L"\t Application Data: %.*s\n", pInvitation->applicationData.cbData, (WCHAR *)pInvitation->applicationData.pbData );
}
}
//-----------------------------------------------------------------------------
// Function: PrintEndpoint
// Purpose: Prints out a PEER_ENDPOINT structure to the console
// Parameters:
// pEndpoint : [in] pointer to PEER_ENDPOINT structure
//
void PrintEndpoint(PCPEER_ENDPOINT pEndpoint)
{
PrintFullEndpoint(pEndpoint, FALSE);
}
void PrintFullEndpoint(PCPEER_ENDPOINT pEndpoint, BOOL fFull)
{
HRESULT hr = S_OK;
WCHAR wzAddr[256] = {0};
DWORD dwLen = (sizeof(wzAddr) / sizeof(wzAddr[0]));
PEER_PRESENCE_INFO* pPresInfo = NULL;
if (pEndpoint != NULL)
{
wprintf(L"\tEndpoint:\n");
// Print out address
if (WSAAddressToString(
(LPSOCKADDR) &(pEndpoint->address.sin6),
sizeof(SOCKADDR_IN6),
NULL,
wzAddr,
&dwLen) != SOCKET_ERROR)
{
wprintf(L"\t IPV6 Endpoint Address: %s\n", wzAddr);
}
else
{
wprintf(L"\t Error parsing address\n");
}
// Print out endpoint name
wprintf(L"\t Endpoint Name: %s\n", pEndpoint->pwzEndpointName);
}
else
{
wprintf(L"\tEndpoint\n");
wprintf(L"\t <Me>\n");
}
if (fFull != FALSE)
{
//Presence Info
hr = PeerCollabGetPresenceInfo(pEndpoint, &pPresInfo);
if (FAILED(hr))
{
wprintf(L"PeerCollabGetPresenceInfo failed, hr=0x%x\n", hr);
PrintError(hr);
goto exit;
}
// print out the presence information
PrintPresenceInformation(pPresInfo);
}
exit:
// free the presence info struct that was allocated by the PeerCollabGetPresenceInfo API
SAFE_PEER_FREE_DATA(pPresInfo);
}
//-----------------------------------------------------------------------------
// Function: PrintContact
// Purpose: Prints out a PEER_CONTACT structure to the console
// Parameters:
// pContact : [in] pointer to PEER_CONTACT structure
//
void PrintContact(PCPEER_CONTACT pContact)
{
if (pContact != NULL)
{
wprintf(L"\tContact\n");
wprintf(L"\t pwzPeerName : %s\n", pContact->pwzPeerName);
wprintf(L"\t pwzNickName : %s\n", pContact->pwzNickName);
wprintf(L"\t pwzDisplayName : %s\n", pContact->pwzDisplayName);
wprintf(L"\t pwzEmailAddress : %s\n", pContact->pwzEmailAddress);
wprintf(L"\t fWatch : %s\n", (int)pContact->fWatch==0?L"FALSE":L"TRUE");
wprintf(L"\t WatcherPermissions: %s\n", (int)pContact->WatcherPermissions==PEER_WATCH_BLOCKED?L"PEER_WATCH_BLOCKED":L"PEER_WATCH_ALLOWED");
wprintf(L"\t credentials : %d bytes\n", pContact->credentials.cbData);
}
else
{
wprintf(L"\tContact\n");
wprintf(L"\t <Me>\n");
}
}
//-----------------------------------------------------------------------------
// Function: PrintContacts
// Purpose: Prints out an array of PEER_CONTACT structures to the console
// Parameters:
// ppContacts: array of pointers to PEER_CONTACT structures
// cContacts : count of PEER_CONTACT structures in ppContacts array
//
void PrintContacts(__in_ecount(cContacts) PCPEER_CONTACT *ppContacts, __in const ULONG cContacts)
{
ULONG i;
wprintf(L"Contacts:\n");
for (i = 0; i < cContacts; i++)
{
wprintf(L"%d)\n", i+1);
PrintContact(ppContacts[i]);
}
}
//-----------------------------------------------------------------------------
// Function: PrintObject
// Purpose: Prints out a PEER_OBJECT structure to the console
// Parameters:
// pObject : [in] pointer to PEER_CONTACT structure
//
void PrintObject(__in PCPEER_OBJECT pObject)
{
PWSTR pwzObjectId = NULL;
wprintf(L"\tObject:\n");
if (UuidToString(&pObject->id, &pwzObjectId) == RPC_S_OK)
{
wprintf(L"\t Id: %s\n", pwzObjectId);
RpcStringFree(&pwzObjectId);
}
wprintf(L"\t Size: %d\n", pObject->data.cbData);
// Displays contents of message object when object's GUID equals MESSAGE_GUID
if (pObject->data.cbData != 0 &&
memcmp(&(pObject->id), &(MESSAGE_GUID), sizeof(pObject->id)) == 0)
{
wprintf(L"\t Data: %s\n", (PWSTR) pObject->data.pbData);
}
wprintf(L"\t Publication Scope: %s\n", PublicationScope(pObject->dwPublicationScope));
}
//-----------------------------------------------------------------------------
// Function: PrintApplication
// Purpose: Prints out a PEER_APPLICATION structure to the console
// Parameters:
// pApplication : [in] pointer to PEER_APPLICATION structure
//
void PrintApplication(__in PCPEER_APPLICATION pApplication)
{
PWSTR pwzApplicationId = NULL;
wprintf(L"\tApplication:\n");
if (UuidToString(&pApplication->id, &pwzApplicationId) == RPC_S_OK)
{
wprintf(L"\t Id: %s\n", pwzApplicationId);
RpcStringFree(&pwzApplicationId);
}
if (pApplication->pwzDescription != NULL)
{
wprintf(L"\t Description: %s\n", pApplication->pwzDescription);
}
wprintf(L"\t Data Size: %d\n\n", pApplication->data.cbData);
}
//-----------------------------------------------------------------------------
// Function: PrintPeopleNearMeInfo
// Purpose: Prints out an array of PEER_PEOPLE_NEAR_ME structures to the console
// Parameters:
// ppPeopleNearMe: array of pointers to PEER_PEOPLE_NEAR_ME structures
// cContacts : count of PEER_PEOPLE_NEAR_ME structures in ppPeopleNearMe array
//
void PrintPeopleNearMeInfo(__in_ecount(cContacts) PCPEER_PEOPLE_NEAR_ME *ppPeopleNearMe, __in const ULONG cPeopleNearMe)
{
ULONG i = 0;
wprintf(L"\nPeople Near Me: \n");
for (i = 0; i < cPeopleNearMe; i++)
{
// Print out nickname
wprintf(L"%d) %s, ", i+1, ppPeopleNearMe[i]->pwzNickName);
PrintEndpoint(&ppPeopleNearMe[i]->endpoint);
}
}
//-----------------------------------------------------------------------------
// Function: PrintPresenceInformation
// Purpose: Prints out a PCPEER_PRESENCE_INFO structure to the console
// Parameters:
// pPresInfo : [in] pointer to PCPEER_PRESENCE_INFO structure
//
void PrintPresenceInformation(__in PCPEER_PRESENCE_INFO pPresInfo)
{
// first print the text equivalent of the status
wprintf(L"%s", PresenceStatus(pPresInfo->status));
// now print any descriptive text
// (for example, the user might set status to "Playing Halo")
wprintf(L" - %s\n", pPresInfo->pwzDescriptiveText == NULL ? L"" :
pPresInfo->pwzDescriptiveText);
}
//-----------------------------------------------------------------------------
// Function: PrintGUID
// Purpose: Prints out a GUID to the console
// Parameters:
// pguid : [in] pointer to GUID
//
void PrintGUID(__in const GUID *pguid)
{
PWSTR pwzApplicationId = NULL;
if (pguid != NULL)
{
if (UuidToString(pguid, &pwzApplicationId) == RPC_S_OK)
{
wprintf(L"%s\n", pwzApplicationId);
RpcStringFree(&pwzApplicationId);
}
}
}
//-----------------------------------------------------------------------------
// Function: DuplicateContact
//
// Purpose: Duplicates a PEER_CONTACT structure
// It allocates a copy, so the caller needs to free
//
// Returns: HRESULT
//
HRESULT DuplicateContact(PEER_CONTACT ** ppContactDestination, const PEER_CONTACT * pContactSource)
{
PEER_CONTACT * pTempDestination = NULL;
size_t cbPeerName = 0;
size_t cbNickName = 0;
size_t cbDisplayName = 0;
size_t cbEmailAddress = 0;
WCHAR *pPos = NULL;
if (ppContactDestination == NULL || pContactSource == NULL) return E_INVALIDARG;
//Get size of the strings pointed to by the PWSTR elements
//
if (pContactSource->pwzPeerName)
{
cbPeerName = ROUND_UP_COUNT((wcslen(pContactSource->pwzPeerName) * sizeof(WCHAR)) + sizeof(WCHAR), ALIGN_LPVOID);
}
if (pContactSource->pwzNickName)
{
cbNickName = ROUND_UP_COUNT((wcslen(pContactSource->pwzNickName) * sizeof(WCHAR)) + sizeof(WCHAR), ALIGN_LPVOID);
}
if (pContactSource->pwzDisplayName)
{
cbDisplayName = ROUND_UP_COUNT((wcslen(pContactSource->pwzDisplayName) * sizeof(WCHAR)) + sizeof(WCHAR), ALIGN_LPVOID);
}
if (pContactSource->pwzEmailAddress)
{
cbEmailAddress = ROUND_UP_COUNT((wcslen(pContactSource->pwzEmailAddress) * sizeof(WCHAR)) + sizeof(WCHAR), ALIGN_LPVOID);
}
//Allocate PEER_CONTACT structure
//
pTempDestination = (PEER_CONTACT *) malloc(ROUND_UP_COUNT(sizeof(PEER_CONTACT), ALIGN_LPVOID) + cbPeerName + cbNickName + cbDisplayName + cbEmailAddress + pContactSource->credentials.cbData);
if (NULL == pTempDestination)
return E_OUTOFMEMORY;
ZeroMemory(pTempDestination, sizeof(PEER_CONTACT));
//Copy the relevant fields into the PEER_PEOPLE_NEAR_ME structure
//
pTempDestination->fWatch = pContactSource->fWatch;
pTempDestination->WatcherPermissions = pContactSource->WatcherPermissions;
pTempDestination->credentials.cbData = pContactSource->credentials.cbData;
pPos = (WCHAR *)ROUND_UP_POINTER((pTempDestination + 1), ALIGN_LPVOID);
if (pContactSource->pwzPeerName)
{
pTempDestination->pwzPeerName = pPos;
//Copy the relevant fields into the PEER_PEOPLE_NEAR_ME structure
//
memcpy(pTempDestination->pwzPeerName, pContactSource->pwzPeerName, cbPeerName);
pPos+=ROUND_UP_COUNT(cbPeerName, ALIGN_LPVOID)/sizeof(WCHAR);
}
if (pContactSource->pwzNickName)
{
pTempDestination->pwzNickName = pPos;
//Copy the relevant fields into the PEER_PEOPLE_NEAR_ME structure
//
memcpy(pTempDestination->pwzNickName, pContactSource->pwzNickName, cbNickName);
pPos+=ROUND_UP_COUNT(cbNickName, ALIGN_LPVOID)/sizeof(WCHAR);
}
if (pContactSource->pwzDisplayName)
{
pTempDestination->pwzDisplayName = pPos;
//Copy the relevant fields into the Display_PEOPLE_NEAR_ME structure
//
memcpy(pTempDestination->pwzDisplayName, pContactSource->pwzDisplayName, cbDisplayName);
pPos+=ROUND_UP_COUNT(cbDisplayName, ALIGN_LPVOID)/sizeof(WCHAR);
}
if (pContactSource->pwzEmailAddress)
{
pTempDestination->pwzEmailAddress = pPos;
//Copy the relevant fields into the PEER_PEOPLE_NEAR_ME structure
//
memcpy(pTempDestination->pwzEmailAddress, pContactSource->pwzEmailAddress, cbEmailAddress);
pPos+=ROUND_UP_COUNT(cbEmailAddress, ALIGN_LPVOID)/sizeof(WCHAR);
}
if (pContactSource->credentials.pbData)
{
pTempDestination->credentials.pbData = (PBYTE)pPos;
memcpy(pTempDestination->credentials.pbData, pContactSource->credentials.pbData, pContactSource->credentials.cbData);
}
*ppContactDestination = pTempDestination;
return S_OK;
}
//-----------------------------------------------------------------------------
// Function: DuplicateEndpoint
//
// Purpose: Duplicates a PEER_ENDPOINT structure
// It allocates a copy, so the caller needs to free
//
// Returns: HRESULT
//
HRESULT DuplicateEndpoint(PEER_ENDPOINT ** ppEndpointDestination, const PEER_ENDPOINT * pEndpointSource)
{
size_t cbEndpointName = 0;
PEER_ENDPOINT * pTempDestination = NULL;
WCHAR *pPos = NULL;
if (pEndpointSource->pwzEndpointName)
{
cbEndpointName = ROUND_UP_COUNT((wcslen(pEndpointSource->pwzEndpointName) * sizeof(WCHAR)) + sizeof(WCHAR), ALIGN_LPVOID);
}
//Allocate PEER_PEOPLE_NEAR_ME structure
//
pTempDestination = (PEER_ENDPOINT *) malloc(ROUND_UP_COUNT(sizeof(PEER_ENDPOINT), ALIGN_LPVOID) + cbEndpointName);
if (NULL == pTempDestination)
return E_OUTOFMEMORY;
ZeroMemory(pTempDestination, sizeof(PEER_ENDPOINT));
//Copy the relevant fields into the PEER_PEOPLE_NEAR_ME structure
//
pTempDestination->address = pEndpointSource->address;
pPos = (WCHAR *)ROUND_UP_POINTER((pTempDestination + 1), ALIGN_LPVOID);
//Get size of pwzEndpointName
//
if (pEndpointSource->pwzEndpointName)
{
pTempDestination->pwzEndpointName = pPos;
//Copy the relevant fields into the PEER_PEOPLE_NEAR_ME structure
//
memcpy(pTempDestination->pwzEndpointName, pEndpointSource->pwzEndpointName, cbEndpointName);
pPos+=ROUND_UP_COUNT(cbEndpointName, ALIGN_LPVOID)/sizeof(WCHAR);
}
*ppEndpointDestination = pTempDestination;
return S_OK;
}
//-----------------------------------------------------------------------------
// Function: SelectContact
// Purpose: Retrieves and prints to the console all contacts for the currently
// logged in user. Unless fPrompt is FALSE the function also
// prompts the user to select a contact from the list.
// Parameters:
// pppContacts : [out] pointer to the selected contact.
// fPrompt : [out] If false skips prompting the user to select a contact (only prints the contacts)
//
HRESULT SelectContact(__out PPEER_CONTACT *pContact, __in BOOL fPrompt)
{
HPEERENUM hEnum;
HRESULT hr = S_OK;
ULONG Selection = 0;
WCHAR wzBuff[5];
PPEER_CONTACT *ppContacts = NULL;
ULONG cContacts = 0;
if (pContact == NULL) return E_INVALIDARG;
// Begin an enumeration of all contacts
//
hr = PeerCollabEnumContacts(&hEnum);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerCollabEnumContacts failed.");
// Retrieve the number of contacts
//
hr = PeerGetItemCount(hEnum, &cContacts);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerGetItemCount failed.");
if (cContacts == 0)
{
wprintf(L"No contacts exist.\n");
hr = E_FAIL;
goto exit;
}
// Retrieve all the contacts
//
hr = PeerGetNextItem(hEnum, &cContacts, (void***) &ppContacts);
if (FAILED(hr))
{
wprintf(L"Failed to retrieve contacts. hr=0x%x\n", hr);
PrintError(hr);
goto exit;
}
// Display the contacts
//
PrintContacts(ppContacts, cContacts);
if (fPrompt != FALSE)
{
// Prompt the user to select a contact
//
wprintf(L"Select contact: ");
GET_PROMPT_RESPONSE(hr, wzBuff);
Selection = _wtoi(wzBuff);
if (Selection < 1 || (ULONG)Selection > cContacts)
{
wprintf(L"Invalid selection.\n");
hr = E_FAIL;
goto exit;
}
Selection--; //make it 0 based rather than 1 based.
hr = DuplicateContact(pContact, ppContacts[Selection]);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"Failed to duplicate contacts.");
}
exit:
SAFE_PEER_END_ENUMERATION(hEnum);
SAFE_PEER_FREE_DATA(ppContacts);
return hr;
}
//-----------------------------------------------------------------------------
// Function: SelectEndpointFromContact
// Purpose: Given a contact allow the user to select an available endpoint of that contact
// Parameters:
// pContact : [in] contact to select endpoint for
// ppEndpoint : [out] pointer to an endpoint pointer of the endpoint that the user selected
//
HRESULT SelectEndpointFromContact(__in const PEER_CONTACT *pContact, __out PEER_ENDPOINT **ppEndpoint)
{
HRESULT hr;
PEER_ENDPOINT **ppEndpoints = NULL;
HPEERENUM hEnum = NULL;
ULONG ulEndpoint = 0;
int nSelection = 0;
ULONG cEndpoints = 0;
WCHAR wzInputBuffer[5] = {0};
if (pContact == NULL || ppEndpoint == NULL) return E_INVALIDARG;
*ppEndpoint = NULL;
// Enumerate all endpoints for this contact
//
hr = PeerCollabEnumEndpoints(pContact, &hEnum);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerCollabEnumEndpoints failed.");
// Get the count of endpoints for this contact
//
hr = PeerGetItemCount(hEnum, &cEndpoints);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerGetItemCount failed.");
if (cEndpoints == 0)
{
wprintf(L"Contact has no endpoints visible. Are we watching this contact? Has this contact granted us watch permissions?)\n");
hr = E_FAIL;
goto exit;
}
// If there are any endpoints, retrieve them all
//
hr = PeerGetNextItem(hEnum, &cEndpoints, (void***) &ppEndpoints);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerGetNextItem failed.");
// Prompt for which endpoint to send the invite to
//
for (ulEndpoint = 0; ulEndpoint < cEndpoints; ulEndpoint++)
{
wprintf(L"%d)\n", ulEndpoint+1);
PrintEndpoint(ppEndpoints[ulEndpoint]);
}
wprintf(L"\nSelect Endpoint [1-%d]: ", cEndpoints);
GET_PROMPT_RESPONSE(hr, wzInputBuffer);
nSelection = _wtoi(wzInputBuffer);
if (nSelection < 1 || (ULONG)nSelection > cEndpoints)
{
wprintf(L"\nInvalid Selection.\n");
hr = E_FAIL;
goto exit;
}
nSelection--; //make it 0 based rather than 1 based.
hr = DuplicateEndpoint(ppEndpoint, ppEndpoints[nSelection]);
if (FAILED(hr))
{
wprintf(L"Failed to duplicate endpoint structure.\n");
goto exit;
}
//Ensure we have the latest information from this endpoint
//
hr = RefreshEndpoint(*ppEndpoint);
if (FAILED(hr))
{
wprintf(L"Failed to refresh endpoint.\n");
goto exit;
}
exit:
if (FAILED(hr))
{
//If we are returning an error but have already allocated memory for the out
//paramter it is our responsibillity to clean up
SAFE_FREE(*ppEndpoint);
}
SAFE_PEER_FREE_DATA(ppEndpoints);
SAFE_PEER_END_ENUMERATION(hEnum);
return hr;
}
//-----------------------------------------------------------------------------
// Function: SelectContactEndpoint
// Purpose: Select a contact and an endpoint of that contact
// Parameters:
// pContact : [out] pointer to a pointer of the selected contact
// ppEndpoint : [out] pointer to a pointer of the selected endpoint
//
HRESULT SelectContactEndpoint(__out PPEER_CONTACT *ppContact, PPEER_ENDPOINT *ppEndpoint)
{
HRESULT hr = S_OK;
if (ppContact == NULL || ppEndpoint == NULL) return E_INVALIDARG;
*ppContact = NULL;
*ppEndpoint = NULL;
// Retrieve the list of contacts
//
hr = SelectContact(ppContact, TRUE);
if (FAILED(hr))
{
goto exit;
}
hr = SelectEndpointFromContact(*ppContact, ppEndpoint);
if (FAILED(hr))
{
goto exit;
}
exit:
if (FAILED(hr))
{
SAFE_FREE(*ppContact);
SAFE_FREE(*ppEndpoint);
}
return hr;
}
//-----------------------------------------------------------------------------
// Function: SelectPNMEndpoint
// Purpose: Returns a PNM endpoint selected by the user from a menu of all
// available PNM endpoints
// Parameters:
// ppEndpoint : [out] pointer to a pointer of the selected endpoint
//
HRESULT SelectPNMEndpoint(__out PPEER_ENDPOINT *ppEndpoint)
{
PEER_PEOPLE_NEAR_ME** ppPeopleNearMe = NULL;
HRESULT hr = S_OK;
HPEERENUM hEnum = NULL;
ULONG count = 0;
ULONG ulEndpoint = 0;
WCHAR wzInputBuffer[5] = {0};
if (ppEndpoint == NULL) return E_INVALIDARG;
*ppEndpoint = NULL;
hr = PeerCollabEnumPeopleNearMe(&hEnum);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerCollabEnumPeopleNearMe failed.");
hr = PeerGetItemCount(hEnum, &count);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerGetItemCount failed.");
if (count == 0)
{
wprintf(L"No people near me found\n");
hr = E_FAIL;
return hr;
}
hr = PeerGetNextItem(hEnum, &count, (PVOID **) &ppPeopleNearMe);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerGetNextItem failed.");
PrintPeopleNearMeInfo(ppPeopleNearMe, count);
wprintf(L"\nSelect Endpoint [1-%d]: ", count);
GET_PROMPT_RESPONSE(hr, wzInputBuffer);
ulEndpoint = _wtoi(wzInputBuffer);
if (ulEndpoint < 1 || ulEndpoint > count)
{
wprintf(L"\nInvalid Selection\n");
hr = E_FAIL;
goto exit;
}
ulEndpoint--; //make it 0 based
hr = DuplicateEndpoint(ppEndpoint, &ppPeopleNearMe[ulEndpoint]->endpoint);
//Ensure we have the latest information from this endpoint
//
hr = RefreshEndpoint(*ppEndpoint);
if (FAILED(hr))
{
wprintf(L"Failed to refresh endpoint.\n");
goto exit;
}
exit:
if (FAILED(hr))
{
//If we are returning an error but have already allocated memory for the out
//paramter it is our responsibillity to clean up
SAFE_FREE(*ppEndpoint);
}
SAFE_PEER_FREE_DATA(ppPeopleNearMe);
SAFE_PEER_END_ENUMERATION(hEnum);
return hr;
}
//-----------------------------------------------------------------------------
// Function: SelectMultipleEndpoints
// Purpose: Select multiple sets of
// - a PNM endpoint; and
// - a contact and endpoint
// Parameters:
// ulNumEndpoints: [in] The number of endpoints to allocate and populate.
// pppContact : [out] Pointer to an array of pointers to PPEER_CONTACT structures.
// The function will allocate an array of size ulNumEndpoints.
// In the case where a PNM endpoint was selected that arrary element will be set to NULL.
// pppEndpoint : [out] Pointer to an array or pointers to PPEER_ENDPOINT structures.
// The function will allocate an array of size ulNumEndpoints
//
// Remarks:
// If this function returns a successes HRESULT the called is responsible for freeing *pppContacts and *pppEndpoint.
// The caller must seperatly free each non-null pointer within each array and then free the pointers to the arrays.
//
HRESULT SelectMultipleEndpoints(__in unsigned int uNumEndpoints, __out PPEER_CONTACT **pppContacts, __out PPEER_ENDPOINT **pppEndpoint)
{
HRESULT hr = S_OK;
unsigned int uCurrentEndpoint = 0;
if (pppContacts== NULL || pppEndpoint == NULL || uNumEndpoints == 0) return E_INVALIDARG;
*pppContacts = (PPEER_CONTACT *) malloc(sizeof (PPEER_CONTACT) * uNumEndpoints);
if (pppContacts == NULL)
{
printf("Failed to allocate memory in SelectMultipleEndpoints\n");
hr = E_ABORT;
goto exit;
}
*pppEndpoint = (PPEER_ENDPOINT *) malloc(sizeof (PPEER_ENDPOINT) * uNumEndpoints);
if (pppEndpoint == NULL)
{
printf("Failed to allocate memory in SelectMultipleEndpoints\n");
hr = E_ABORT;
goto exit;
}
ZeroMemory(*pppContacts, sizeof (PPEER_CONTACT) * uNumEndpoints);
ZeroMemory(*pppEndpoint, sizeof (PPEER_ENDPOINT) * uNumEndpoints);
uCurrentEndpoint = 0;
while (uCurrentEndpoint < uNumEndpoints)
{
wprintf(L"\nSelecting endpoint %d of %d:\n", uCurrentEndpoint+1, uNumEndpoints);
hr = SelectEndpoint(&((*pppContacts)[uCurrentEndpoint]), &((*pppEndpoint)[uCurrentEndpoint]));
if(FAILED(hr) && hr != E_FAIL)
{
//for E_FAIL we will retry, otherwise abort the loop
goto exit;
}
if (SUCCEEDED(hr))
{
uCurrentEndpoint++;
}
}
exit:
if (FAILED(hr))
{
if (*pppContacts)
{
for (uCurrentEndpoint = 0; uCurrentEndpoint < uNumEndpoints; uCurrentEndpoint++)
{
if ((*pppContacts)[uCurrentEndpoint] != NULL)
{
SAFE_FREE((*pppContacts)[uCurrentEndpoint]);
}
}
SAFE_FREE(*pppContacts);
}
if (*pppEndpoint)
{
for (uCurrentEndpoint = 0; uCurrentEndpoint < uNumEndpoints; uCurrentEndpoint++)
{
if ((*pppEndpoint)[uCurrentEndpoint] != NULL)
{
DeleteEndpointData((*pppEndpoint)[uCurrentEndpoint]);
SAFE_FREE((*pppEndpoint)[uCurrentEndpoint]);
}
}
SAFE_FREE(*pppEndpoint);
}
}
return hr;
}
//-----------------------------------------------------------------------------
// Function: SelectEndpoint
// Purpose: Select either
// - a PNM endpoint; or
// - a contact and endpoint
// Parameters:
// [pContact : [out] pointer to a pointer of the selected contact. *pContact will be
// set to NULL if a PNM endpoint is selected
// ppEndpoint : [out] pointer to a pointer of the selected endpoint
//
HRESULT SelectEndpoint(__out PPEER_CONTACT *ppContact, __out PPEER_ENDPOINT *ppEndpoint)
{
HRESULT hr = S_OK;
BOOL fIsContactEndpoint = FALSE;
WCHAR wzBuff[5] = {0};
int nSelection = 0;
if (ppContact == NULL || ppEndpoint == NULL) return E_INVALIDARG;
*ppContact = NULL;
*ppEndpoint = NULL;
wprintf(L"What type of endpoint (1) Contact, (2) People Near Me [1-2]: ");
GET_PROMPT_RESPONSE(hr, wzBuff);
nSelection = _wtoi(wzBuff);
if (nSelection < 1 || nSelection > 2)
{
wprintf(L"Invalid selection.\n");
hr = E_ABORT; //let the user exit out without needing to complete the process
goto exit;
}
fIsContactEndpoint = nSelection==1?TRUE:FALSE;
if (fIsContactEndpoint != FALSE)
{
hr = SelectContactEndpoint(ppContact, ppEndpoint);
}
else
{
hr = SelectPNMEndpoint(ppEndpoint);
}
exit:
if (FAILED(hr))
{
SAFE_FREE(*ppContact);
SAFE_FREE(*ppEndpoint);
}
return hr;
}
//-----------------------------------------------------------------------------
// Function: RefreshEndpoint
// Purpose: Requests a refresh of a specific endpoint's data.
// Note that if a subscription to the endpoint exists via
// PeerCollabSubscribeEndpoint, this is not necessary.
// Parameters:
// pcEndpoint : [in] endpoint to refresh
//
HRESULT RefreshEndpoint(__in PCPEER_ENDPOINT pcEndpoint)
{
HPEEREVENT hPeerEvent = NULL;
HRESULT hr = S_OK;
HANDLE hEvent = NULL;
PEER_COLLAB_EVENT_DATA *pEventData = NULL;
PEER_COLLAB_EVENT_REGISTRATION eventReg = {0};
DWORD dwWait = 0;
if (pcEndpoint == NULL) return E_INVALIDARG;
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent == NULL)
{
goto exit;
}
eventReg.eventType = PEER_EVENT_REQUEST_STATUS_CHANGED;
eventReg.pInstance = NULL;
// Register to be notified when the request finishes
hr = PeerCollabRegisterEvent(hEvent, 1, &eventReg, &hPeerEvent);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerCollabRegisterEvent failed.");
hr = PeerCollabRefreshEndpointData(pcEndpoint);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerCollabRefreshEndpointData failed.");
// Block until an event is set indicating that endpoint data has
// successfully been refreshed
dwWait = WaitForSingleObject(hEvent, SHORT_TIMEOUT);
switch (dwWait)
{
case WAIT_OBJECT_0:
// Find out if the refresh request succeeded
hr = PeerCollabGetEventData(hPeerEvent, &pEventData);
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerCollabGetEventData failed.");
if (FAILED(pEventData->requestStatusChangedData.hrChange))
{
wprintf(L"The data returned by PeerCollabGetEventData indicates failure. HRESULT=0x%x\n", hr);
PrintError(hr);
goto exit;
}
break;
case WAIT_TIMEOUT:
wprintf(L"Endpoint was not refreshed after waiting %d seconds. Giving up.\n", SHORT_TIMEOUT/1000);
hr = E_FAIL;
goto exit;
break;
default:
wprintf(L"WaitForSingleObject returned unexpected valud. Giving up.\n");
hr = E_FAIL;
goto exit;
break;
}
exit:
SAFE_PEER_FREE_DATA(pEventData);
if (hPeerEvent)
{
(void)PeerCollabUnregisterEvent(hPeerEvent);
hPeerEvent = NULL;
}
if (hEvent)
{
CloseHandle(hEvent);
hEvent = NULL;
}
return hr;
}
//-----------------------------------------------------------------------------
// Function: DeleteEndpointData
// Purpose: Delete cached endpoint data when it is no longer required
// Parameters:
// pcEndpoint : [in] endpoint for which to delete cached data
//
HRESULT DeleteEndpointData(__in PCPEER_ENDPOINT pcEndpoint)
{
HRESULT hr = S_OK;
//Ignore failures - best effort to delete cached data
(void)PeerCollabDeleteEndpointData(pcEndpoint);
return hr;
}
//-----------------------------------------------------------------------------
// Function: GetParentProcessHandle
// Purpose: Returns a handle to the parent process of the calling process
// Parameters:
// pHandle : [out] Pointer to a handle to the parent process of the calling process
//
HRESULT GetParentProcessHandle(HANDLE *pHandle)
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
HRESULT hr = S_OK;
DWORD dwCurrentProcessId = 0;
dwCurrentProcessId = GetCurrentProcessId();
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
printf( "CreateToolhelp32Snapshot (of processes) failed" );
hr = E_ABORT;
goto exit;
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first process.
// We can use this to get hte process Id of our parent processs
if( !Process32First( hProcessSnap, &pe32 ) )
{
printf("Process32First failed" ); // Show cause of failure
hr = E_ABORT;
goto exit;
}
do
{
// Retrieve a handle to the process
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
if( hProcess != NULL )
{
if (dwCurrentProcessId == pe32.th32ProcessID)
{
CloseHandle( hProcess );
// Retrieve a handle to the process
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ParentProcessID );
*pHandle = hProcess;
break;
}
CloseHandle( hProcess );
}
} while( Process32Next( hProcessSnap, &pe32 ) );
hr = S_OK;
exit:
CloseHandle( hProcessSnap );
return( TRUE );
}
//-----------------------------------------------------------------------------
// Function: PrintError
// Purpose: Utility routine to print the status of a set of invitations. Will
// optionally cancel outstanding invitations if fCancelInvitations == TRUE
//
// Return:
// HRESULT - TRUE if there outstanding invitations were found. FALSE otherwise.
//
BOOL PrintInvitationStatus(__in HANDLE *phInvite, __in unsigned int uNumEndpoints, __in BOOL fCancelInvitations)
{
BOOL fInvitationsOutstanding = FALSE;
PPEER_INVITATION_RESPONSE pResponse = NULL;
unsigned int uCurrentEndpoint = 0;
HRESULT hr = S_OK;
if (phInvite == NULL || uNumEndpoints == 0) return FALSE;
wprintf(L"------------------------------\n");
wprintf(L" Invitation Status\n");
for (uCurrentEndpoint=0; uCurrentEndpoint < uNumEndpoints; uCurrentEndpoint++)
{
wprintf(L"Invitation #%d: ", uCurrentEndpoint+1);
hr = PeerCollabGetInvitationResponse(phInvite[uCurrentEndpoint], &pResponse);
if (hr == PEER_E_INVITE_RESPONSE_NOT_AVAILABLE)
{
fInvitationsOutstanding = TRUE;
if (fCancelInvitations != FALSE)
{
wprintf(L"Cancelling invitation. ");
hr = PeerCollabCancelInvitation(phInvite[uCurrentEndpoint]);
if (SUCCEEDED(hr))
{
wprintf(L"Successfully cancelled Invitation.\n");
}
else
{
wprintf(L"Failed cancel invitation. hr=0x%x\n", hr);
PrintError(hr);
}
}
else
{
wprintf(L"Invitation response pending.\n");
}
}
else
{
IF_FAILED_PRINT_ERROR_AND_EXIT(hr, L"PeerCollabGetInvitationResponse failed.");
if (pResponse->action == PEER_INVITATION_RESPONSE_ACCEPTED)
{
wprintf(L"Invitation accepted.\n");
}
else
{
wprintf(L"Invitation not accepted.\n");
}
}
SAFE_PEER_FREE_DATA(pResponse);
}
wprintf(L"------------------------------\n\n", uCurrentEndpoint+1);
exit:
SAFE_PEER_FREE_DATA(pResponse);
return fInvitationsOutstanding;
}