742 lines
18 KiB
C++
742 lines
18 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) Microsoft Corporation. All rights reserved
|
|
|
|
Module Name:
|
|
|
|
WdsTransportManager.cpp
|
|
|
|
Abstract:
|
|
|
|
Sample application to demonstrate usage of the WDS Transport
|
|
Management API.
|
|
|
|
Note:
|
|
|
|
This sample is primarily intended to illustrate usage of the WDS Transport
|
|
Management API, sometimes referred to as WdsTptMgmt.
|
|
For the sake of clarity and brevity, the sample does not adhere to all the
|
|
coding guidelines expected of a modern, well-designed application. Some of
|
|
the coding aspects that are omitted from this program are:
|
|
1. Globalization. The code uses hardcoded English strings rather than
|
|
placing strings in a resource file.
|
|
2. Error Handling:
|
|
a. The sample provided here simply prints some of its own error messages
|
|
and shows raw HRESULTS in case of most failures. A developer working
|
|
with this sample can manually look up WdsTptMgmt HRESULTs in
|
|
WdsTptMgmtMsg.h and WdsMcErr.h.
|
|
b. In general, an application is expected to use functions like
|
|
FormatMessage to get a user-friendly message that corresponds to
|
|
each error code. In the case of the WdsTptMgmt API, all error codes
|
|
have user-friendly messages that can be looked up in WdsTptMgmt.dll
|
|
and WdsMcErr.dll using FormatMessage.
|
|
c. If the application needs to support Windows versions prior to
|
|
Windows Vista, the function LoadMUILibrary should be used to get
|
|
a handle to the WDS Transport modules above for the purpose of error
|
|
lookup.
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "WdsTransportManager.h"
|
|
|
|
|
|
|
|
int __cdecl
|
|
wmain(
|
|
_In_ int argc,
|
|
_In_reads_(argc) wchar_t* argv[ ]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the main application entry point.
|
|
|
|
Arguments:
|
|
|
|
argc - Number of arguments passed to the application.
|
|
argv - Array of null-terminated arguments passed to the application.
|
|
|
|
Return Value:
|
|
|
|
0 - Success
|
|
Others - Failure HRESULT.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WDSTPT_ARGS Arguments = { 0 };
|
|
DWORD dwInstalledFeatures = 0;
|
|
|
|
IWdsTransportManager* pWdsTransportManager = NULL;
|
|
IWdsTransportServer* pServer = NULL;
|
|
IWdsTransportSetupManager* pSetupMgr = NULL;
|
|
CLSID clsid;
|
|
|
|
|
|
//
|
|
// Parse arguments.
|
|
//
|
|
hr = ParseArguments( argc,
|
|
argv,
|
|
&Arguments );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
|
|
//
|
|
// Initialize COM.
|
|
//
|
|
hr = CoInitializeEx( NULL,
|
|
COINIT_APARTMENTTHREADED );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Instantiate the top-level WdsTransportManager object.
|
|
//
|
|
hr = CLSIDFromProgID( L"WdsTptMgmt.WdsTransportManager",
|
|
&clsid );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
hr = CoCreateInstance( clsid,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
__uuidof( IWdsTransportManager ),
|
|
(PVOID*) &pWdsTransportManager );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
|
|
//
|
|
// Get an object for the target server
|
|
//
|
|
hr = pWdsTransportManager->GetWdsTransportServer( Arguments.bszServer,
|
|
&pServer );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Confirm that the server is a WDS Transport Server.
|
|
// This is accomplished by querying the server's SetupManager.
|
|
//
|
|
hr = pServer->get_SetupManager( &pSetupMgr );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Check if the server is actually a WDS Transport server by seeing if
|
|
// the Transport Server feature is installed on the server.
|
|
//
|
|
hr = pSetupMgr->get_InstalledFeatures( &dwInstalledFeatures );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
|
|
if ( !( dwInstalledFeatures & WdsTptFeatureTransportServer ) )
|
|
{
|
|
//
|
|
// Print a message indicating the server isn't a WDS transport server.
|
|
// Set return value to the special WdsTptMgmt value that would have
|
|
// been returned had we attempted other operations on the server.
|
|
//
|
|
wprintf( WDSTPTMGR_SERVER_NOT_CONFIGURED );
|
|
hr = WDSTPTMGMT_E_TRANSPORT_SERVER_ROLE_NOT_CONFIGURED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Dispatch to appropriate handler function based on parsed action type.
|
|
//
|
|
switch ( Arguments.Action )
|
|
{
|
|
case WdsTptEnableServer :
|
|
|
|
hr = EnableServer( pServer );
|
|
break;
|
|
|
|
case WdsTptDisableServer :
|
|
|
|
hr = DisableServer( pServer );
|
|
break;
|
|
|
|
case WdsTptAddNamespace :
|
|
|
|
hr = AddNamespace( pServer,
|
|
&Arguments );
|
|
break;
|
|
|
|
case WdsTptRemoveNamespace :
|
|
|
|
hr = RemoveNamespace( pServer,
|
|
&Arguments );
|
|
break;
|
|
|
|
default :
|
|
|
|
//
|
|
// This branch should never be reached unless the parser was updated
|
|
// to recognize more actions than this dispatcher supports.
|
|
//
|
|
hr = E_NOTIMPL;
|
|
wprintf( WDSTPTMGR_UNKNOWN_ACTION,
|
|
argv[ 0 ],
|
|
Arguments.pwszAction,
|
|
(ULONG)Arguments.Action );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
|
|
//
|
|
// Print an overall result message.
|
|
//
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
wprintf( WDSTPTMGR_SUCCESS );
|
|
}
|
|
else
|
|
{
|
|
wprintf( WDSTPTMGR_FAILURE, hr );
|
|
}
|
|
|
|
|
|
//
|
|
// Release/Free resources
|
|
//
|
|
RELEASE( pWdsTransportManager );
|
|
RELEASE( pServer );
|
|
RELEASE( pSetupMgr );
|
|
BSTR_FREE( Arguments.bszServer );
|
|
BSTR_FREE( Arguments.bszNamespace );
|
|
BSTR_FREE( Arguments.bszWdsContentProvider );
|
|
BSTR_FREE( Arguments.bszFolderPath );
|
|
|
|
|
|
//
|
|
// Uninitialize COM.
|
|
//
|
|
CoUninitialize( );
|
|
|
|
//
|
|
// Return the current HRESULT as the program return
|
|
//
|
|
return (int) hr;
|
|
}
|
|
|
|
|
|
//
|
|
// Utility Functions
|
|
//
|
|
|
|
HRESULT
|
|
AllocBstr(
|
|
_In_opt_ PWSTR pwszString,
|
|
_COM_Outptr_ BSTR* pbszString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
HRESULT-based version of SysAllocString that returns an HR status
|
|
rather than the string.
|
|
|
|
Note that if pwszString is NULL, this function returns an empty
|
|
BSTR.
|
|
|
|
Arguments:
|
|
|
|
pwszString - PWSTR string to be converted to a BSTR
|
|
pbszString - Receives a BSTR version of the input string.
|
|
Use SysFreeString( *pbszString ) when done.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Success
|
|
E_OUTOFMEMORY - Not enough memory to perform the allocation.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Validate parameters.
|
|
//
|
|
assert( pbszString );
|
|
|
|
//
|
|
// Allocate a BSTR using the specified PWSTR as input.
|
|
// If the input string is NULL, use an empty string.
|
|
//
|
|
*pbszString = SysAllocString( ( NULL == pwszString ) ? L"" : pwszString );
|
|
|
|
if ( NULL == *pbszString )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
_At_(pArguments->bszServer, _Post_notnull_)
|
|
HRESULT
|
|
ParseArguments(
|
|
_In_ int argc,
|
|
_In_reads_(argc) wchar_t *argv[ ],
|
|
_Out_ PWDSTPT_ARGS pArguments
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses the arguments passed on from the application main function.
|
|
The results are returned in the output variable, pArguments.
|
|
|
|
Arguments:
|
|
|
|
argc - Number of arguments passed to the application.
|
|
argv - Array of null-terminated arguments passed to the application.
|
|
pArguments - Receives parsed and constructed arguments.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Success
|
|
Others - Failure
|
|
|
|
Note:
|
|
|
|
If the function succeeds, the caller should remember to free
|
|
the various BSTR fields inside the pArguments structure.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Validate parameters
|
|
//
|
|
assert( argc > 0 );
|
|
assert( argv );
|
|
assert( pArguments );
|
|
|
|
ZeroMemory( pArguments, sizeof( WDSTPT_ARGS ) );
|
|
_Analysis_assume_nullterminated_(pArguments->bszServer);
|
|
|
|
//
|
|
// Verify that the correct number of arguments was passed
|
|
// At this point we'll ensure we have at least 3 arguments
|
|
// (application, server name, and action).
|
|
//
|
|
if ( argc < 3 )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Read server name and convert it to a BSTR.
|
|
//
|
|
hr = AllocBstr( argv[ 1 ],
|
|
&pArguments->bszServer );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Read action.
|
|
//
|
|
pArguments->pwszAction = argv[ 2 ];
|
|
|
|
//
|
|
// Map the action to one of the supported types and parse the remaining
|
|
// arguments accordingly
|
|
//
|
|
if ( 0 == _wcsicmp( pArguments->pwszAction, L"EnableServer" ) )
|
|
{
|
|
pArguments->Action = WdsTptEnableServer;
|
|
}
|
|
else if ( 0 == _wcsicmp( pArguments->pwszAction, L"DisableServer" ) )
|
|
{
|
|
pArguments->Action = WdsTptDisableServer;
|
|
}
|
|
else if ( 0 == _wcsicmp( pArguments->pwszAction, L"AddNamespace" ) )
|
|
{
|
|
pArguments->Action = WdsTptAddNamespace;
|
|
|
|
//
|
|
// This action requires a total of 6 arguments.
|
|
// Check for and read the remaining 3.
|
|
//
|
|
if ( argc < 6 )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Read namespace name and convert it to a BSTR.
|
|
//
|
|
hr = AllocBstr( argv[ 3 ],
|
|
&pArguments->bszNamespace );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Construct a BSTR for the WDS content provider.
|
|
// This provider is hardcoded here because it is guaranteed to be
|
|
// installed by default on a WDS transport server.
|
|
//
|
|
hr = AllocBstr( WDSTPTMGR_WDS_CONTENT_PROVIDER,
|
|
&pArguments->bszWdsContentProvider );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Read folder path and convert it to a BSTR.
|
|
//
|
|
#pragma warning( push )
|
|
#pragma warning( disable :6385 )
|
|
|
|
hr = AllocBstr( argv[ 4 ],
|
|
&pArguments->bszFolderPath );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Read minimum clients as a ULONG.
|
|
//
|
|
// NOTE: Validation should be done here but is omitted for brevity.
|
|
//
|
|
pArguments->ulMinClients = (ULONG) _wtol( argv[ 5 ] );
|
|
#pragma warning( pop )
|
|
}
|
|
else if ( 0 == _wcsicmp( pArguments->pwszAction, L"RemoveNamespace" ) )
|
|
{
|
|
pArguments->Action = WdsTptRemoveNamespace;
|
|
|
|
//
|
|
// This action requires a total of 4 arguments.
|
|
// Check for and read the remaining one.
|
|
//
|
|
if ( argc < 4 )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Read namespace name and convert it to a BSTR.
|
|
//
|
|
hr = AllocBstr( argv[ 3 ],
|
|
&pArguments->bszNamespace );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Invalid action specified
|
|
//
|
|
hr = E_INVALIDARG;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// If parsing failed, free any allocated resources and print
|
|
// a usage message.
|
|
//
|
|
if ( FAILED( hr ) )
|
|
{
|
|
BSTR_FREE( pArguments->bszServer );
|
|
BSTR_FREE( pArguments->bszNamespace );
|
|
BSTR_FREE( pArguments->bszWdsContentProvider );
|
|
BSTR_FREE( pArguments->bszFolderPath );
|
|
wprintf( WDSTPTMGR_USAGE, argv[0] );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
EnableServer(
|
|
_In_ IWdsTransportServer* pServer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enables the WDS Transport Server for operation.
|
|
This is done by enabling and starting the WDS transport services.
|
|
Note that if the services are already enabled/running, the
|
|
WdsTptMgmt API methods succeed and so this function does as well.
|
|
|
|
Arguments:
|
|
|
|
pServer - Pointer to the server to be enabled.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Success
|
|
Others - Failure
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWdsTransportConfigurationManager* pConfigMgr = NULL;
|
|
|
|
assert( pServer );
|
|
|
|
//
|
|
// Get a reference to the server's Configuration Manager.
|
|
//
|
|
hr = pServer->get_ConfigurationManager( &pConfigMgr );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Enable WDS Tranport Services.
|
|
//
|
|
hr = pConfigMgr->EnableWdsTransportServices( );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Start WDS Tranport Services.
|
|
//
|
|
hr = pConfigMgr->StartWdsTransportServices( );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
|
|
Cleanup:
|
|
|
|
RELEASE( pConfigMgr );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DisableServer(
|
|
_In_ IWdsTransportServer* pServer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disables the WDS Transport Server.
|
|
This is done by stopping and disabling the WDS transport services.
|
|
Note that if the services are already stopped/disabled, the
|
|
WdsTptMgmt API methods succeed and so this function does as well.
|
|
|
|
Arguments:
|
|
|
|
pServer - Pointer to the server to be disabled.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Success
|
|
Others - Failure
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWdsTransportConfigurationManager* pConfigMgr = NULL;
|
|
|
|
assert( pServer );
|
|
|
|
//
|
|
// Get a reference to the server's Configuration Manager.
|
|
//
|
|
hr = pServer->get_ConfigurationManager( &pConfigMgr );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Stop WDS Tranport Services.
|
|
//
|
|
hr = pConfigMgr->StopWdsTransportServices( );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Disable WDS Tranport Services.
|
|
//
|
|
hr = pConfigMgr->DisableWdsTransportServices( );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
|
|
Cleanup:
|
|
|
|
RELEASE( pConfigMgr );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AddNamespace(
|
|
_In_ IWdsTransportServer* pServer,
|
|
_In_ PWDSTPT_ARGS pArguments
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds the specified namespace to the specified WDS Transport Server.
|
|
Note that there are various WDS transport namespace types but this
|
|
function only demonstrates the creation of a namespace of type
|
|
WdsTransportNamespaceScheduledCastAutoStart. Other types can be
|
|
created in a very similar manner.
|
|
|
|
Arguments:
|
|
|
|
pServer - Pointer to the server to be modified.
|
|
pArguments - Pointer to a structure with parsed arguments.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Success
|
|
Others - Failure
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWdsTransportNamespaceManager* pNamespaceMgr = NULL;
|
|
IWdsTransportNamespace* pNamespace = NULL;
|
|
IWdsTransportNamespaceScheduledCastAutoStart* pNamespaceAutoStart = NULL;
|
|
|
|
assert( pServer );
|
|
assert( pArguments );
|
|
|
|
//
|
|
// Get a reference to the server's Namespace Manager.
|
|
//
|
|
hr = pServer->get_NamespaceManager( &pNamespaceMgr );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Create an auto-start namespace object using specified arguments.
|
|
//
|
|
hr = pNamespaceMgr->CreateNamespace( WdsTptNamespaceTypeScheduledCastAutoStart,
|
|
pArguments->bszNamespace,
|
|
pArguments->bszWdsContentProvider,
|
|
pArguments->bszFolderPath,
|
|
&pNamespace );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Get a type-specific reference so we can set properties unique to
|
|
// auto-start namespaces.
|
|
//
|
|
hr = pNamespace->QueryInterface( __uuidof(IWdsTransportNamespaceScheduledCastAutoStart),
|
|
(PVOID*) &pNamespaceAutoStart );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Set the MinimumClients property to the user-specified value.
|
|
//
|
|
hr = pNamespaceAutoStart->put_MinimumClients( pArguments->ulMinClients );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Register the namespace on the server.
|
|
//
|
|
// NOTE: This may fail with an appropriate HRESULT for various reasons.
|
|
// E.g. If the namespace name is already in use by another
|
|
// regtistered namespace on the server, this method may return a
|
|
// "duplicate namespace" error code from WdsTptMgmt.h or WdsMcErr.h.
|
|
// This sample simply bubbles up the error code, but a real-world
|
|
// application may want to handle such an error, e.g. by looking up
|
|
// and displaying its associated user-friendly message and/or
|
|
// prompting the user to try a different namespace name.
|
|
//
|
|
hr = pNamespaceAutoStart->Register( );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Release all references
|
|
//
|
|
RELEASE( pNamespaceMgr );
|
|
RELEASE( pNamespace );
|
|
RELEASE( pNamespaceAutoStart );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
RemoveNamespace(
|
|
_In_ IWdsTransportServer* pServer,
|
|
_In_ PWDSTPT_ARGS pArguments
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes the specified namespace from the specified WDS Transport Server.
|
|
|
|
Arguments:
|
|
|
|
pServer - Pointer to the server to be modified.
|
|
pArguments - Pointer to a structure with parsed arguments.
|
|
|
|
Return Value:
|
|
|
|
S_OK - Success
|
|
Others - Failure
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWdsTransportNamespaceManager* pNamespaceMgr = NULL;
|
|
IWdsTransportNamespace* pNamespace = NULL;
|
|
|
|
assert( pServer );
|
|
assert( pArguments );
|
|
|
|
//
|
|
// Get a reference to the server's Namespace Manager.
|
|
//
|
|
hr = pServer->get_NamespaceManager( &pNamespaceMgr );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Retrieve the namespace object corresponding to the specified namespace.
|
|
//
|
|
// NOTE: If this fails indicating no such namespace is registered on
|
|
// the server, this sample simply bubbles up the error code.
|
|
// In a real-world scenario, the application may look up the error
|
|
// message in the WDS transport modules, display its own
|
|
// user-friendly message, prompt the user to re-enter the name,
|
|
// and so on.
|
|
//
|
|
hr = pNamespaceMgr->RetrieveNamespace( pArguments->bszNamespace,
|
|
&pNamespace );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
//
|
|
// Deregister the namespace on the server.
|
|
//
|
|
// NOTE: This sample utilizes the deregistration option that immediately
|
|
// terminates any active transport sessions under the namespace.
|
|
// In a real-world scenario, the application may give the user
|
|
// the option to deregister the namespace but allow existing
|
|
// sessions to run to completion.
|
|
//
|
|
hr = pNamespace->Deregister( VARIANT_TRUE );
|
|
CLEANUP_HR( hr, Cleanup );
|
|
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Release all references
|
|
//
|
|
RELEASE( pNamespaceMgr );
|
|
RELEASE( pNamespace );
|
|
|
|
return hr;
|
|
}
|