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

660 lines
15 KiB
C

/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
main.cpp
Abstract:
Sample code demonstrating an implementation of the wds content provider.
Author:
Blaine Young (blyoung)
Environment:
User Mode
--*/
//
// Includes
//
#include <windows.h>
#include <stdlib.h>
#include <wdstpdi.h>
//
// Handy macros.
//
#define TO_UNICODE2(x) L ## x
#define TO_UNICODE(x) TO_UNICODE2(x)
#define __WFILE__ TO_UNICODE(__FILE__)
#define __WFUNCTION__ TO_UNICODE(__FUNCTION__)
#define __WFUNCSIG__ TO_UNICODE(__FUNCSIG__)
#define EXIT_ON_HR_ERROR(x) do{if(FAILED(x)){hr = x; WdsTransportServerTrace(g_hProvider, WDS_MC_TRACE_ERROR, L"%s: failing with error 0x%08x\n", __WFUNCTION__, hr); goto exit;}}while(0)
#define EXIT_ON_MALLOC_ERROR(x) do{if(NULL == x){hr = E_OUTOFMEMORY; WdsTransportServerTrace(g_hProvider, WDS_MC_TRACE_ERROR, L"%s: failing with error 0x%08x\n", __WFUNCTION__, hr);goto exit;}}while(0)
#define EXIT_ON_WIN_ERROR(x) do{if(ERROR_SUCCESS != x){hr = HRESULT_FROM_WIN32(x); WdsTransportServerTrace(g_hProvider, WDS_MC_TRACE_ERROR, L"%s: failing with error 0x%08x\n", __WFUNCTION__, hr);goto exit;}}while(0)
#define CHECK_ARG(x) do{if(NULL == x){hr = E_INVALIDARG; WdsTransportServerTrace(g_hProvider, WDS_MC_TRACE_ERROR, L"%s: failing with error 0x%08x\n", __WFUNCTION__, hr);goto exit;}}while(0)
//
// Global Instance Handle
//
HINSTANCE g_hInstance = NULL;
static HANDLE g_hProvider = NULL;
typedef struct _CALLBACK_ENTRY
{
TRANSPORTPROVIDER_CALLBACK_ID CallbackId;
PVOID pfnCallback;
} CALLBACK_ENTRY, *PCALLBACK_ENTRY;
//
// This provider does not implement every possible callback. See wdstpdi.h or
// the reference documentation for a full list of valid callbacks.
//
CALLBACK_ENTRY Callbacks[] = {{WDS_TRANSPORTPROVIDER_CREATE_INSTANCE, WdsTransportProviderCreateInstance},
{WDS_TRANSPORTPROVIDER_COMPARE_CONTENT, WdsTransportProviderCompareContent},
{WDS_TRANSPORTPROVIDER_OPEN_CONTENT, WdsTransportProviderOpenContent},
{WDS_TRANSPORTPROVIDER_USER_ACCESS_CHECK, WdsTransportProviderUserAccessCheck},
{WDS_TRANSPORTPROVIDER_GET_CONTENT_SIZE, WdsTransportProviderGetContentSize},
{WDS_TRANSPORTPROVIDER_READ_CONTENT, WdsTransportProviderReadContent},
{WDS_TRANSPORTPROVIDER_CLOSE_CONTENT, WdsTransportProviderCloseContent},
{WDS_TRANSPORTPROVIDER_CLOSE_INSTANCE, WdsTransportProviderCloseInstance},
{WDS_TRANSPORTPROVIDER_SHUTDOWN, WdsTransportProviderShutdown}};
typedef struct _CALLBACK_DATA
{
OVERLAPPED lpOverlapped;
PVOID pvCallerData;
DWORD dwReadCount;
} CALLBACK_DATA, *PCALLBACK_DATA;
BOOL
WINAPI
DllMain(
__in HINSTANCE hInstance,
IN DWORD dwReason,
__in PVOID pReserved
)
/*++
Routine Description:
DLL main function.
Arguments:
hInstance - Module Handle.
dwReason - Reason for calling.
pReserved - Reserved.
Returns:
TRUE on success, FALSE on failure.
--*/
{
HRESULT hr = S_OK;
UNREFERENCED_PARAMETER( pReserved );
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
g_hInstance = hInstance;
break;
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return !FAILED(hr);
}
VOID
CompleteRead(
__in DWORD dwErrorCode,
__in DWORD dwBytesCount,
__in PCALLBACK_DATA pData
)
/**
Routine Description:
Read completion routine.
Arguments:
dwErrorCode - The overall result of the read.
dwBytesCount - The number of bytes read.
pData - The length of the buffer pSettings, in bytes.
**/
{
HRESULT hr = S_OK;
//
// Translate any caller errors.
//
if (ERROR_SUCCESS != dwErrorCode)
{
hr = HRESULT_FROM_WIN32(dwErrorCode);
}
//
// Inform the server that the read is complete.
//
WdsTransportServerCompleteRead(g_hProvider,
dwBytesCount,
pData->pvCallerData,
hr);
//
// Free our callback data since it is no longer needed.
//
free(pData);
}
HRESULT
WdsTransportProviderInit(
__in PWDS_TRANSPORTPROVIDER_INIT_PARAMS pInParameters,
__out_bcount(ulLength) PWDS_TRANSPORTPROVIDER_SETTINGS pSettings,
__in ULONG ulLength
)
/*++
Routine Description:
Initializes the content provider globally.
Arguments:
pInParameters - Pointer to a a PWDS_TRANSPORTPROVIDER_INIT_PARAMS structure
that will contain information about the multicast server and
the environment that the provider is running in. Content
providers should check themselves against these setting to
ensure that this is an environment that they can run in.
pSettings - Pointer to a PWDS_TRANSPORT_PROVIDER_SETTINGS structure that the
content provider uses to inform the server about itself.
ulLength - The length of the buffer pSettings, in bytes.
Returns:
S_OK on success, an appropriate error code on failure.
--*/
{
HRESULT hr = S_OK;
ULONG i = 0;
CHECK_ARG(pInParameters);
CHECK_ARG(pSettings);
//
// Validate structures.
//
if (ulLength < sizeof(WDS_TRANSPORTPROVIDER_SETTINGS))
{
EXIT_ON_HR_ERROR(E_INVALIDARG);
}
if (pInParameters->ulLength < sizeof(WDS_TRANSPORTPROVIDER_INIT_PARAMS))
{
EXIT_ON_HR_ERROR(E_INVALIDARG);
}
if (pInParameters->ulMcServerVersion < MC_SERVER_CURRENT_VERSION)
{
EXIT_ON_HR_ERROR(E_INVALIDARG);
}
//
// Initialize our submodules.
//
g_hProvider = pInParameters->hProvider;
//
// Register our callbacks with the server.
//
for (i = 0; i < ARRAYSIZE(Callbacks); i++)
{
hr = WdsTransportServerRegisterCallback(g_hProvider,
Callbacks[i].CallbackId,
Callbacks[i].pfnCallback);
EXIT_ON_HR_ERROR(hr);
}
//
// Inform the server of the version of the api we use.
//
pSettings->ulProviderVersion = TRANSPORTPROVIDER_CURRENT_VERSION;
pSettings->ulLength = sizeof(WDS_TRANSPORTPROVIDER_SETTINGS);
exit:
return hr;
}
HRESULT
WDSTRANSPORTPROVIDERAPI
WdsTransportProviderCreateInstance(
__in PCWSTR pwszConfigString,
__out PHANDLE phInstance
)
/*++
Routine Description:
Initializes a new provider instance. For more information about instances,
please see the Instances section in the api reference.
Arguments:
pwszConfigString - Configuration information for this instance.
Configuration information may change on an instance by
instance basis. The format of this string is determined
by the provider.
phInstance - Pointer to a handle that will be used to identify this
instance to the provider in future calls. This handle must be
closed with a call to WdsTransportProviderCloseInstance.
Returns:
S_OK on success, an appropriate error code on failure.
--*/
{
//
// This provider merely opens a handle to any file that is given to it,
// thus it does not need to accept configuration information.
//
return S_OK;
}
HRESULT
WDSTRANSPORTPROVIDERAPI
WdsTransportProviderCompareContent(
__in HANDLE hInstance,
__in PCWSTR pwszContentName,
__in HANDLE hContent,
__out PBOOL pbContentMatches
)
/*++
Routine Description:
Compares a content name/configuration string pair to an already opened
content handle to determine if they are the exact same.
Arguments:
hInstance - Handle to the instance against which this stream will be opened.
For more information, see the Instances section in the api
documentation.
pwszStreamName - The name of the Stream to compare.
hStream - An already opened Stream to compare to.
pbStreamsMatch - If the data streams pointed to by
hInstance/pwszContentName and hStream are the exact same,
this variable will be set to true. It will be set to
false otherwise.
Returns:
S_OK on success, an appropriate error code on failure.
--*/
{
HRESULT hr = S_OK;
//
// The multicast server performs basic file name matching, so if the request
// gets this far, then we can assume that the file has not changed due to
// the share access we asked for.
//
if (NULL == pbContentMatches)
{
EXIT_ON_HR_ERROR(E_INVALIDARG);
}
*pbContentMatches = TRUE;
exit:
return hr;
}
HRESULT
WDSTRANSPORTPROVIDERAPI
WdsTransportProviderUserAccessCheck(
__in HANDLE hContent,
__in HANDLE hUserToken,
__out PBOOL pbAccessAllowed
)
/*++
Routine Description:
Allows the content provider to grant or deny access to a user based on that
user's token.
Arguments:
hContent - Handle to the content to check access to.
hUserToken - Windows token of the user requesting access.
pbAccessAllowed - Pointer that will receive whether or not the provider
grants access to this file.
Returns:
S_OK on success, an appropriate error code on failure.
--*/
{
//
// Grant access to the entire world.
//
*pbAccessAllowed = TRUE;
return ERROR_SUCCESS;
}
HRESULT
WDSTRANSPORTPROVIDERAPI
WdsTransportProviderOpenContent(
__in HANDLE hInstance,
__in PCWSTR pwszContentName,
__out PHANDLE phContent
)
/*++
Routine Description:
The WdsTransportProviderOpenStream opens a new static view to contents.
Arguments:
hInstance - Handle to the instance against which this stream will be opened.
For more information, see the Instances section in the api
documentation.
pwszContentName - The name of the data stream that the user wants
multicasted. The interpretation of this Stream name is
provider specific.
phContent - Pointer to a handle that will be used to identify this data
stream to the provider.
Returns:
S_OK on success, an appropriate error code on failure.
--*/
{
HANDLE hFile = INVALID_HANDLE_VALUE;
BOOL bResult = FALSE;
HRESULT hr = S_OK;
//
// Create a file for exclusive access. For most users, this will not be
// sufficient since it's entirely possible for successive one-off sessions
// to tie up a file indefinately, preventing any sort of maintanence on that
// file.
//
hFile = CreateFile(pwszContentName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
EXIT_ON_WIN_ERROR(GetLastError());
}
bResult = BindIoCompletionCallback(hFile,
(LPOVERLAPPED_COMPLETION_ROUTINE)CompleteRead,
0);
if (FALSE == bResult)
{
EXIT_ON_WIN_ERROR(GetLastError());
}
//
// Inform the caller of the handle we opened.
//
*phContent = hFile;
exit:
if (FAILED(hr))
{
if (INVALID_HANDLE_VALUE != hFile)
{
CloseHandle(hFile);
}
}
return hr;
}
HRESULT
WDSTRANSPORTPROVIDERAPI
WdsTransportProviderGetContentSize(
__in HANDLE hContent,
__out PULARGE_INTEGER pContentSize
)
/*++
Routine Description:
Retrieves the static size of a previously opened content handle
Arguments:
hContent - Content handle previously opened by a call to
WdsTransportProviderOpenStream.
pContentSize - Pointer to a large integer that will receive the size of the
contents.
Returns:
S_OK on success, an appropriate error code on failure.
--*/
{
HRESULT hr = S_OK;
BOOL bResult = FALSE;
LARGE_INTEGER llFileSize = {0};
bResult = GetFileSizeEx(hContent, &llFileSize);
if (FALSE == bResult)
{
EXIT_ON_WIN_ERROR(GetLastError());
}
pContentSize->QuadPart = llFileSize.QuadPart;
exit:
return hr;
}
HRESULT
WDSTRANSPORTPROVIDERAPI
WdsTransportProviderReadContent(
__in HANDLE hContent,
__in_bcount(ulBytesToRead) PVOID pBuffer,
__in ULONG ulBytesToRead,
__in PULARGE_INTEGER pContentOffset,
__in PVOID pvUserData
)
/*++
Routine Description:
Retrieves the static size of a previously opened content handle
Arguments:
hContent - Content handle previously opened by a call to
WdsTransportProviderOpenStream.
pContentSize - Pointer to a large integer that will receive the size of the
contents.
Returns:
S_OK on success, an appropriate error code on failure.
--*/
{
HRESULT hr = S_OK;
BOOL bResult = FALSE;
DWORD dwError = 0;
DWORD dwBytesRead = 0;
PCALLBACK_DATA pData = NULL;
pData = (PCALLBACK_DATA)malloc(sizeof(CALLBACK_DATA));
EXIT_ON_MALLOC_ERROR(pData);
ZeroMemory(pData, sizeof(CALLBACK_DATA));
pData->lpOverlapped.Offset = pContentOffset->LowPart;
pData->lpOverlapped.OffsetHigh = pContentOffset->HighPart;
pData->pvCallerData = pvUserData;
//
// Read the file from the specified offset.
//
bResult = ReadFile(hContent,
pBuffer,
ulBytesToRead,
&pData->dwReadCount,
&pData->lpOverlapped);
if (FALSE == bResult)
{
dwError = GetLastError();
if (ERROR_IO_PENDING != dwError)
{
EXIT_ON_WIN_ERROR(dwError);
}
}
//
// Clear the callback data pointer, since it will now be freed in the read
// complete function.
//
pData = NULL;
exit:
if (NULL != pData)
{
free(pData);
}
return hr;
}
HRESULT
WDSTRANSPORTPROVIDERAPI
WdsTransportProviderCloseContent(
__in HANDLE hContent
)
/*++
Routine Description:
Closes the data stream associated with a handle.
Arguments:
hContent - Handle to the data stream to close.
--*/
{
//
// The handle belongs to the file system, so let the file system deal with
// it.
//
CloseHandle(hContent);
return S_OK;
}
HRESULT
WDSTRANSPORTPROVIDERAPI
WdsTransportProviderCloseInstance(
__in HANDLE hInstance
)
/*++
Routine Description:
Closes the instance associated with a handle.
Arguments:
hInstance - Handle to the instance to close.
--*/
{
//
// We don't keep track of instances, so noop this.
//
return S_OK;
}
HRESULT
WDSTRANSPORTPROVIDERAPI
WdsTransportProviderShutdown(
)
/*++
Routine Description:
Globally deallocates the content provider.
--*/
{
//
// We have nothing to clean up.
//
return S_OK;
}