SMBSMP.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:42k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*++
  2. Copyright (c) 1997 <company name>
  3. Module Name:
  4.     SmbSmp.c
  5. Abstract:
  6.     Resource DLL for SMB Sample (SmbSmp).
  7. Author:
  8.     <user> (<email-name>) Mmmm DD, 1997
  9. Revision History:
  10. --*/
  11. #pragma comment(lib, "clusapi.lib")
  12. #pragma comment(lib, "resutils.lib")
  13. #pragma comment(lib, "advapi32.lib")
  14. #pragma comment(lib, "netapi32.lib")
  15. #define UNICODE 1
  16. #pragma warning( disable : 4115 )  // named type definition in parentheses
  17. #pragma warning( disable : 4201 )  // nonstandard extension used : nameless struct/union
  18. #pragma warning( disable : 4214 )  // nonstandard extension used : bit field types other than int
  19. #include <windows.h>
  20. #pragma warning( default : 4214 )  // nonstandard extension used : bit field types other than int
  21. #pragma warning( default : 4201 )  // nonstandard extension used : nameless struct/union
  22. #pragma warning( default : 4115 )  // named type definition in parentheses
  23. #include <clusapi.h>
  24. #include <resapi.h>
  25. #include <stdio.h>
  26. #include <lm.h>
  27. #include <lmerr.h>
  28. //
  29. // Type and constant definitions.
  30. //
  31. #define SMBSMP_RESNAME  L"SMB Sample"
  32. #define SMBSMP_SVCNAME  TEXT("LanmanServer")
  33. #define DBG_PRINT printf
  34. // ADDPARAM: Add new parameters here.
  35. #define PARAM_NAME__SHARENAME L"ShareName"
  36. #define PARAM_NAME__PATH L"Path"
  37. #define PARAM_NAME__REMARK L"Remark"
  38. // ADDPARAM: Add new parameters here.
  39. typedef struct _SMBSMP_PARAMS {
  40.     PWSTR           ShareName;
  41.     PWSTR           Path;
  42.     PWSTR           Remark;
  43. } SMBSMP_PARAMS, *PSMBSMP_PARAMS;
  44. typedef struct _SMBSMP_RESOURCE {
  45.     RESID                   ResId; // for validation
  46.     SMBSMP_PARAMS         Params;
  47.     HKEY                    ParametersKey;
  48.     RESOURCE_HANDLE         ResourceHandle;
  49.     LPWSTR                  ResourceName;
  50.     CLUS_WORKER             OnlineThread;
  51.     CLUSTER_RESOURCE_STATE  State;
  52. } SMBSMP_RESOURCE, *PSMBSMP_RESOURCE;
  53. //
  54. // Global data.
  55. //
  56. // Event Logging routine.
  57. PLOG_EVENT_ROUTINE g_LogEvent = NULL;
  58. // Resource Status routine for pending Online and Offline calls.
  59. PSET_RESOURCE_STATUS_ROUTINE g_SetResourceStatus = NULL;
  60. // Forward reference to our RESAPI function table.
  61. extern CLRES_FUNCTION_TABLE g_SmbSmpFunctionTable;
  62. //
  63. // SMB Sample resource read-write private properties.
  64. //
  65. RESUTIL_PROPERTY_ITEM
  66. SmbSmpResourcePrivateProperties[] = {
  67.     { PARAM_NAME__SHARENAME, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(SMBSMP_PARAMS,ShareName) },
  68.     { PARAM_NAME__PATH, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(SMBSMP_PARAMS,Path) },
  69.     { PARAM_NAME__REMARK, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, 0, FIELD_OFFSET(SMBSMP_PARAMS,Remark) },
  70.     { 0 }
  71. };
  72. //
  73. // Function prototypes.
  74. //
  75. DWORD
  76. WINAPI
  77. Startup(
  78.     IN LPCWSTR ResourceType,
  79.     IN DWORD MinVersionSupported,
  80.     IN DWORD MaxVersionSupported,
  81.     IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  82.     IN PLOG_EVENT_ROUTINE LogEvent,
  83.     OUT PCLRES_FUNCTION_TABLE *FunctionTable
  84.     );
  85. RESID
  86. WINAPI
  87. SmbSmpOpen(
  88.     IN LPCWSTR ResourceName,
  89.     IN HKEY ResourceKey,
  90.     IN RESOURCE_HANDLE ResourceHandle
  91.     );
  92. VOID
  93. WINAPI
  94. SmbSmpClose(
  95.     IN RESID ResourceId
  96.     );
  97. DWORD
  98. WINAPI
  99. SmbSmpOnline(
  100.     IN RESID ResourceId,
  101.     IN OUT PHANDLE EventHandle
  102.     );
  103. DWORD
  104. WINAPI
  105. SmbSmpOnlineThread(
  106.     PCLUS_WORKER WorkerPtr,
  107.     IN PSMBSMP_RESOURCE ResourceEntry
  108.     );
  109. DWORD
  110. WINAPI
  111. SmbSmpOffline(
  112.     IN RESID ResourceId
  113.     );
  114. VOID
  115. WINAPI
  116. SmbSmpTerminate(
  117.     IN RESID ResourceId
  118.     );
  119. DWORD
  120. SmbSmpDoTerminate(
  121.     IN PSMBSMP_RESOURCE ResourceEntry
  122.     );
  123. BOOL
  124. WINAPI
  125. SmbSmpLooksAlive(
  126.     IN RESID ResourceId
  127.     );
  128. BOOL
  129. WINAPI
  130. SmbSmpIsAlive(
  131.     IN RESID ResourceId
  132.     );
  133. BOOL
  134. SmbSmpCheckIsAlive(
  135.     IN PSMBSMP_RESOURCE ResourceEntry
  136.     );
  137. DWORD
  138. WINAPI
  139. SmbSmpResourceControl(
  140.     IN RESID ResourceId,
  141.     IN DWORD ControlCode,
  142.     IN PVOID InBuffer,
  143.     IN DWORD InBufferSize,
  144.     OUT PVOID OutBuffer,
  145.     IN DWORD OutBufferSize,
  146.     OUT LPDWORD BytesReturned
  147.     );
  148. DWORD
  149. SmbSmpGetPrivateResProperties(
  150.     IN OUT PSMBSMP_RESOURCE ResourceEntry,
  151.     OUT PVOID OutBuffer,
  152.     IN DWORD OutBufferSize,
  153.     OUT LPDWORD BytesReturned
  154.     );
  155. DWORD
  156. SmbSmpValidatePrivateResProperties(
  157.     IN OUT PSMBSMP_RESOURCE ResourceEntry,
  158.     IN const PVOID InBuffer,
  159.     IN DWORD InBufferSize,
  160.     OUT PSMBSMP_PARAMS Params
  161.     );
  162. DWORD
  163. SmbSmpSetPrivateResProperties(
  164.     IN OUT PSMBSMP_RESOURCE ResourceEntry,
  165.     IN const PVOID InBuffer,
  166.     IN DWORD InBufferSize
  167.     );
  168. BOOLEAN
  169. WINAPI
  170. DllMain(
  171.     IN HINSTANCE    DllHandle,
  172.     IN DWORD        Reason,
  173.     IN LPVOID       Reserved
  174.     )
  175. /*++
  176. Routine Description:
  177.     Main DLL entry point.
  178. Arguments:
  179.     DllHandle - DLL instance handle.
  180.     Reason - Reason for being called.
  181.     Reserved - Reserved argument.
  182. Return Value:
  183.     TRUE - Success.
  184.     FALSE - Failure.
  185. --*/
  186. {
  187.     switch( Reason ) {
  188.     case DLL_PROCESS_ATTACH:
  189.         DisableThreadLibraryCalls( DllHandle );
  190.         break;
  191.     case DLL_PROCESS_DETACH:
  192.         break;
  193.     }
  194.     return(TRUE);
  195. } // DllMain
  196. DWORD
  197. WINAPI
  198. Startup(
  199.     IN LPCWSTR ResourceType,
  200.     IN DWORD MinVersionSupported,
  201.     IN DWORD MaxVersionSupported,
  202.     IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  203.     IN PLOG_EVENT_ROUTINE LogEvent,
  204.     OUT PCLRES_FUNCTION_TABLE *FunctionTable
  205.     )
  206. /*++
  207. Routine Description:
  208.     Startup the resource DLL. This routine verifies that at least one
  209.     currently supported version of the resource DLL is between
  210.     MinVersionSupported and MaxVersionSupported. If not, then the resource
  211.     DLL should return ERROR_REVISION_MISMATCH.
  212.     If more than one version of the resource DLL interface is supported by
  213.     the resource DLL, then the highest version (up to MaxVersionSupported)
  214.     should be returned as the resource DLL's interface. If the returned
  215.     version is not within range, then startup fails.
  216.     The ResourceType is passed in so that if the resource DLL supports more
  217.     than one ResourceType, it can pass back the correct function table
  218.     associated with the ResourceType.
  219. Arguments:
  220.     ResourceType - The type of resource requesting a function table.
  221.     MinVersionSupported - The minimum resource DLL interface version 
  222.         supported by the cluster software.
  223.     MaxVersionSupported - The maximum resource DLL interface version
  224.         supported by the cluster software.
  225.     SetResourceStatus - Pointer to a routine that the resource DLL should 
  226.         call to update the state of a resource after the Online or Offline 
  227.         routine returns a status of ERROR_IO_PENDING.
  228.     LogEvent - Pointer to a routine that handles the reporting of events 
  229.         from the resource DLL. 
  230.     FunctionTable - Returns a pointer to the function table defined for the
  231.         version of the resource DLL interface returned by the resource DLL.
  232. Return Value:
  233.     ERROR_SUCCESS - The operation was successful.
  234.     ERROR_MOD_NOT_FOUND - The resource type is unknown by this DLL.
  235.     ERROR_REVISION_MISMATCH - The version of the cluster service doesn't
  236.         match the versrion of the DLL.
  237.     Win32 error code - The operation failed.
  238. --*/
  239. {
  240.     if ( (MinVersionSupported > CLRES_VERSION_V1_00) ||
  241.          (MaxVersionSupported < CLRES_VERSION_V1_00) ) {
  242.         return(ERROR_REVISION_MISMATCH);
  243.     }
  244.     if ( lstrcmpiW( ResourceType, SMBSMP_RESNAME ) != 0 ) {
  245.         return(ERROR_MOD_NOT_FOUND);
  246.     }
  247.     if ( !g_LogEvent ) {
  248.         g_LogEvent = LogEvent;
  249.         g_SetResourceStatus = SetResourceStatus;
  250.     }
  251.     *FunctionTable = &g_SmbSmpFunctionTable;
  252.     return(ERROR_SUCCESS);
  253. } // Startup
  254. RESID
  255. WINAPI
  256. SmbSmpOpen(
  257.     IN LPCWSTR ResourceName,
  258.     IN HKEY ResourceKey,
  259.     IN RESOURCE_HANDLE ResourceHandle
  260.     )
  261. /*++
  262. Routine Description:
  263.     Open routine for SMB Sample resources.
  264.     Open the specified resource (create an instance of the resource). 
  265.     Allocate all structures necessary to bring the specified resource 
  266.     online.
  267. Arguments:
  268.     ResourceName - Supplies the name of the resource to open.
  269.     ResourceKey - Supplies handle to the resource's cluster configuration 
  270.         database key.
  271.     ResourceHandle - A handle that is passed back to the resource monitor 
  272.         when the SetResourceStatus or LogEvent method is called. See the 
  273.         description of the SetResourceStatus and LogEvent methods on the
  274.         SmbSmpStatup routine. This handle should never be closed or used
  275.         for any purpose other than passing it as an argument back to the
  276.         Resource Monitor in the SetResourceStatus or LogEvent callback.
  277. Return Value:
  278.     RESID of created resource.
  279.     NULL on failure.
  280. --*/
  281. {
  282.     DWORD               status;
  283.     DWORD               disposition;
  284.     RESID               resid = 0;
  285.     HKEY                parametersKey = NULL;
  286.     PSMBSMP_RESOURCE resourceEntry = NULL;
  287.     //
  288.     // Open the Parameters registry key for this resource.
  289.     //
  290.     status = ClusterRegCreateKey( ResourceKey,
  291.                                   L"Parameters",
  292.                                   0,
  293.                                   KEY_ALL_ACCESS,
  294.                                   NULL,
  295.                                   &parametersKey,
  296.                                   &disposition );
  297.     if ( status != ERROR_SUCCESS ) {
  298.         (g_LogEvent)(
  299.             ResourceHandle,
  300.             LOG_ERROR,
  301.             L"Unable to open Parameters key. Error: %1!u!.n",
  302.             status );
  303.         goto exit;
  304.     }
  305.     //
  306.     // Allocate a resource entry.
  307.     //
  308.     resourceEntry = (PSMBSMP_RESOURCE) LocalAlloc( LMEM_FIXED, sizeof(SMBSMP_RESOURCE) );
  309.     if ( resourceEntry == NULL ) {
  310.         status = GetLastError();
  311.         (g_LogEvent)(
  312.             ResourceHandle,
  313.             LOG_ERROR,
  314.             L"Unable to allocate resource entry structure. Error: %1!u!.n",
  315.             status );
  316.         goto exit;
  317.     }
  318.     //
  319.     // Initialize the resource entry..
  320.     //
  321.     ZeroMemory( resourceEntry, sizeof(SMBSMP_RESOURCE) );
  322.     resourceEntry->ResId = (RESID)resourceEntry; // for validation
  323.     resourceEntry->ResourceHandle = ResourceHandle;
  324.     resourceEntry->ParametersKey = parametersKey;
  325.     resourceEntry->State = ClusterResourceOffline;
  326.     //
  327.     // Save the name of the resource.
  328.     //
  329.     resourceEntry->ResourceName = LocalAlloc( LMEM_FIXED, (lstrlenW( ResourceName ) + 1) * sizeof(WCHAR) );
  330.     if ( resourceEntry->ResourceName == NULL ) {
  331.         goto exit;
  332.     }
  333.     lstrcpyW( resourceEntry->ResourceName, ResourceName );
  334.     //
  335.     // Startup for the resource.
  336.     //
  337.     // TODO: Add your resource startup code here.
  338.     resid = (RESID)resourceEntry;
  339. exit:
  340.     if ( resid == 0 ) {
  341.         if ( parametersKey != NULL ) {
  342.             ClusterRegCloseKey( parametersKey );
  343.         }
  344.         if ( resourceEntry != NULL ) {
  345.             LocalFree( resourceEntry->ResourceName );
  346.             LocalFree( resourceEntry );
  347.         }
  348.     }
  349.     if ( status != ERROR_SUCCESS ) {
  350.         SetLastError( status );
  351.     }
  352.     return(resid);
  353. } // SmbSmpOpen
  354. VOID
  355. WINAPI
  356. SmbSmpClose(
  357.     IN RESID ResourceId
  358.     )
  359. /*++
  360. Routine Description:
  361.     Close routine for SMB Sample resources.
  362.     Close the specified resource and deallocate all structures, etc.,
  363.     allocated in the Open call. If the resource is not in the offline state,
  364.     then the resource should be taken offline (by calling Terminate) before
  365.     the close operation is performed.
  366. Arguments:
  367.     ResourceId - Supplies the RESID of the resource to close.
  368. Return Value:
  369.     None.
  370. --*/
  371. {
  372.     PSMBSMP_RESOURCE resourceEntry;
  373.     resourceEntry = (PSMBSMP_RESOURCE)ResourceId;
  374.     if ( resourceEntry == NULL ) {
  375.         DBG_PRINT( "SmbSmp: Close request for a nonexistent resource id %un",
  376.                    ResourceId );
  377.         return;
  378.     }
  379.     if ( resourceEntry->ResId != ResourceId ) {
  380.         (g_LogEvent)(
  381.             resourceEntry->ResourceHandle,
  382.             LOG_ERROR,
  383.             L"Close resource sanity check failed! ResourceId = %1!u!.n",
  384.             ResourceId );
  385.         return;
  386.     }
  387. #ifdef LOG_VERBOSE
  388.     (g_LogEvent)(
  389.         resourceEntry->ResourceHandle,
  390.         LOG_INFORMATION,
  391.         L"Close request.n" );
  392. #endif
  393.     //
  394.     // Close the Parameters key.
  395.     //
  396.     if ( resourceEntry->ParametersKey ) {
  397.         ClusterRegCloseKey( resourceEntry->ParametersKey );
  398.     }
  399.     //
  400.     // Deallocate the resource entry.
  401.     //
  402.     // ADDPARAM: Add new parameters here.
  403.     LocalFree( resourceEntry->Params.ShareName );
  404.     LocalFree( resourceEntry->Params.Path );
  405.     LocalFree( resourceEntry->Params.Remark );
  406.     LocalFree( resourceEntry->ResourceName );
  407.     LocalFree( resourceEntry );
  408. } // SmbSmpClose
  409. DWORD
  410. WINAPI
  411. SmbSmpOnline(
  412.     IN RESID ResourceId,
  413.     IN OUT PHANDLE EventHandle
  414.     )
  415. /*++
  416. Routine Description:
  417.     Online routine for SMB Sample resources.
  418.     Bring the specified resource online (available for use). The resource
  419.     DLL should attempt to arbitrate for the resource if it is present on a
  420.     shared medium, like a shared SCSI bus.
  421. Arguments:
  422.     ResourceId - Supplies the resource id for the resource to be brought 
  423.         online (available for use).
  424.     EventHandle - Returns a signalable handle that is signaled when the 
  425.         resource DLL detects a failure on the resource. This argument is 
  426.         NULL on input, and the resource DLL returns NULL if asynchronous 
  427.         notification of failures is not supported, otherwise this must be 
  428.         the address of a handle that is signaled on resource failures.
  429. Return Value:
  430.     ERROR_SUCCESS - The operation was successful, and the resource is now 
  431.         online.
  432.     ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  433.     ERROR_RESOURCE_NOT_AVAILABLE - If the resource was arbitrated with some 
  434.         other systems and one of the other systems won the arbitration.
  435.     ERROR_IO_PENDING - The request is pending, a thread has been activated 
  436.         to process the online request. The thread that is processing the 
  437.         online request will periodically report status by calling the 
  438.         SetResourceStatus callback method, until the resource is placed into 
  439.         the ClusterResourceOnline state (or the resource monitor decides to 
  440.         timeout the online request and Terminate the resource. This pending 
  441.         timeout value is settable and has a default value of 3 minutes.).
  442.     Win32 error code - The operation failed.
  443. --*/
  444. {
  445.     PSMBSMP_RESOURCE resourceEntry = NULL;
  446.     DWORD               status;
  447.     resourceEntry = (PSMBSMP_RESOURCE)ResourceId;
  448.     if ( resourceEntry == NULL ) {
  449.         DBG_PRINT( "SmbSmp: Online request for a nonexistent resource id %u.n",
  450.                    ResourceId );
  451.         return(ERROR_RESOURCE_NOT_FOUND);
  452.     }
  453.     if ( resourceEntry->ResId != ResourceId ) {
  454.         (g_LogEvent)(
  455.             resourceEntry->ResourceHandle,
  456.             LOG_ERROR,
  457.             L"Online service sanity check failed! ResourceId = %1!u!.n",
  458.             ResourceId );
  459.         return(ERROR_RESOURCE_NOT_FOUND);
  460.     }
  461. #ifdef LOG_VERBOSE
  462.     (g_LogEvent)(
  463.         resourceEntry->ResourceHandle,
  464.         LOG_INFORMATION,
  465.         L"Online request.n" );
  466. #endif
  467.     resourceEntry->State = ClusterResourceOffline;
  468.     ClusWorkerTerminate( &resourceEntry->OnlineThread );
  469.     status = ClusWorkerCreate( &resourceEntry->OnlineThread,
  470.                                SmbSmpOnlineThread,
  471.                                resourceEntry );
  472.     if ( status != ERROR_SUCCESS ) {
  473.         resourceEntry->State = ClusterResourceFailed;
  474.         (g_LogEvent)(
  475.             resourceEntry->ResourceHandle,
  476.             LOG_ERROR,
  477.             L"Online: Unable to start thread, status %1!u!.n",
  478.             status
  479.             );
  480.     } else {
  481.         status = ERROR_IO_PENDING;
  482.     }
  483.     return(status);
  484. } // SmbSmpOnline
  485. DWORD
  486. WINAPI
  487. SmbSmpOnlineThread(
  488.     PCLUS_WORKER WorkerPtr,
  489.     IN PSMBSMP_RESOURCE ResourceEntry
  490.     )
  491. /*++
  492. Routine Description:
  493.     Worker function which brings a resource from the resource table online.
  494.     This function is executed in a separate thread.
  495. Arguments:
  496.     WorkerPtr - Supplies the worker structure
  497.     ResourceEntry - A pointer to the SMBSMP_RESOURCE block for this resource.
  498. Returns:
  499.     ERROR_SUCCESS - The operation completed successfully.
  500.     
  501.     Win32 error code - The operation failed.
  502. --*/
  503. {
  504.     RESOURCE_STATUS     resourceStatus;
  505.     DWORD               status;
  506.     LPWSTR              nameOfPropInError;
  507.     SHARE_INFO_2        shareInfo;
  508.     resourceStatus.ResourceState = ClusterResourceFailed;
  509.     resourceStatus.WaitHint = 0;
  510.     resourceStatus.CheckPoint = 1;
  511.     //
  512.     // Read parameters.
  513.     //
  514.     status = ResUtilGetPropertiesToParameterBlock( ResourceEntry->ParametersKey,
  515.                                                    SmbSmpResourcePrivateProperties,
  516.                                                    (LPBYTE) &ResourceEntry->Params,
  517.                                                    TRUE, // CheckForRequiredProperties
  518.                                                    &nameOfPropInError );
  519.     if ( status != ERROR_SUCCESS ) {
  520.         (g_LogEvent)(
  521.             ResourceEntry->ResourceHandle,
  522.             LOG_ERROR,
  523.             L"Unable to read the '%1' property. Error: %2!u!.n",
  524.             (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  525.             status );
  526.         goto exit;
  527.     }
  528.     //
  529.     // Start the SmbSmp service
  530.     //
  531.     status = ResUtilStartResourceService( SMBSMP_SVCNAME, NULL );
  532.     if ( status == ERROR_SERVICE_ALREADY_RUNNING ) {
  533.         status = ERROR_SUCCESS;
  534.     } else if ( status != ERROR_SUCCESS ) {
  535.         goto exit;
  536.     }
  537.     //
  538.     // Bring the resource online.
  539.     //
  540.     // TODO: Add code to bring your resource online.
  541.     if ( status == ERROR_SUCCESS ) {
  542.         shareInfo.shi2_netname =      ResourceEntry->Params.ShareName;
  543.         shareInfo.shi2_type =         STYPE_DISKTREE;
  544.         shareInfo.shi2_remark =       ResourceEntry->Params.Remark;
  545.         shareInfo.shi2_permissions =  ACCESS_ALL;
  546.         shareInfo.shi2_max_uses =     (DWORD)-1;
  547.         shareInfo.shi2_current_uses = 0;
  548.         shareInfo.shi2_path =         ResourceEntry->Params.Path;
  549.         shareInfo.shi2_passwd =       NULL;
  550.         status = NetShareAdd( NULL, 2, (PBYTE)&shareInfo, NULL );
  551.         if ( status != ERROR_SUCCESS ) {
  552.             (g_LogEvent)(
  553.                 ResourceEntry->ResourceHandle,
  554.                 LOG_ERROR,
  555.                 L"Error creating share '%1'. Error: %2!u!.n",
  556.                 ResourceEntry->Params.ShareName,
  557.                 status );
  558.             goto exit;
  559.         }
  560.     }
  561. exit:
  562.     if ( status != ERROR_SUCCESS ) {
  563.         (g_LogEvent)(
  564.             ResourceEntry->ResourceHandle,
  565.             LOG_ERROR,
  566.             L"Error %1!u! bringing resource online.n",
  567.             status );
  568.     } else {
  569.         resourceStatus.ResourceState = ClusterResourceOnline;
  570.     }
  571.     // _ASSERTE(g_SetResourceStatus != NULL);
  572.     g_SetResourceStatus( ResourceEntry->ResourceHandle, &resourceStatus );
  573.     ResourceEntry->State = resourceStatus.ResourceState;
  574.     return(status);
  575. } // SmbSmpOnlineThread
  576. DWORD
  577. WINAPI
  578. SmbSmpOffline(
  579.     IN RESID ResourceId
  580.     )
  581. /*++
  582. Routine Description:
  583.     Offline routine for SMB Sample resources.
  584.     Take the specified resource offline gracefully (unavailable for use).  
  585.     Wait for any cleanup operations to complete before returning.
  586. Arguments:
  587.     ResourceId - Supplies the resource id for the resource to be shutdown 
  588.         gracefully.
  589. Return Value:
  590.     ERROR_SUCCESS - The request completed successfully and the resource is 
  591.         offline.
  592.     ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  593.     ERROR_IO_PENDING - The request is still pending, a thread has been 
  594.         activated to process the offline request. The thread that is 
  595.         processing the offline will periodically report status by calling 
  596.         the SetResourceStatus callback method, until the resource is placed 
  597.         into the ClusterResourceOffline state (or the resource monitor decides 
  598.         to timeout the offline request and Terminate the resource).
  599.     
  600.     Win32 error code - Will cause the resource monitor to log an event and 
  601.         call the Terminate routine.
  602. --*/
  603. {
  604.     PSMBSMP_RESOURCE resourceEntry;
  605.     resourceEntry = (PSMBSMP_RESOURCE)ResourceId;
  606.     if ( resourceEntry == NULL ) {
  607.         DBG_PRINT( "SmbSmp: Offline request for a nonexistent resource id %un",
  608.             ResourceId );
  609.         return(ERROR_RESOURCE_NOT_FOUND);
  610.     }
  611.     if ( resourceEntry->ResId != ResourceId ) {
  612.         (g_LogEvent)(
  613.             resourceEntry->ResourceHandle,
  614.             LOG_ERROR,
  615.             L"Offline resource sanity check failed! ResourceId = %1!u!.n",
  616.             ResourceId );
  617.         return(ERROR_RESOURCE_NOT_FOUND);
  618.     }
  619. #ifdef LOG_VERBOSE
  620.     (g_LogEvent)(
  621.         resourceEntry->ResourceHandle,
  622.         LOG_INFORMATION,
  623.         L"Offline request.n" );
  624. #endif
  625.     // TODO: Offline code
  626.     // NOTE: Offline should try to shut the resource down gracefully, whereas
  627.     // Terminate must shut the resource down immediately. If there are no
  628.     // differences between a graceful shut down and an immediate shut down,
  629.     // Terminate can be called for Offline, as it is below.  However, if there
  630.     // are differences, replace the call to Terminate below with your graceful
  631.     // shutdown code.
  632.     //
  633.     // Terminate the resource.
  634.     //
  635.     return SmbSmpDoTerminate( resourceEntry );
  636. } // SmbSmpOffline
  637. VOID
  638. WINAPI
  639. SmbSmpTerminate(
  640.     IN RESID ResourceId
  641.     )
  642. /*++
  643. Routine Description:
  644.     Terminate routine for SMB Sample resources.
  645.     Take the specified resource offline immediately (the resource is
  646.     unavailable for use).
  647. Arguments:
  648.     ResourceId - Supplies the resource id for the resource to be brought 
  649.         offline.
  650. Return Value:
  651.     None.
  652. --*/
  653. {
  654.     PSMBSMP_RESOURCE resourceEntry;
  655.     resourceEntry = (PSMBSMP_RESOURCE)ResourceId;
  656.     if ( resourceEntry == NULL ) {
  657.         DBG_PRINT( "SmbSmp: Terminate request for a nonexistent resource id %un",
  658.             ResourceId );
  659.         return;
  660.     }
  661.     if ( resourceEntry->ResId != ResourceId ) {
  662.         (g_LogEvent)(
  663.             resourceEntry->ResourceHandle,
  664.             LOG_ERROR,
  665.             L"Terminate resource sanity check failed! ResourceId = %1!u!.n",
  666.             ResourceId );
  667.         return;
  668.     }
  669. #ifdef LOG_VERBOSE
  670.     (g_LogEvent)(
  671.         resourceEntry->ResourceHandle,
  672.         LOG_INFORMATION,
  673.         L"Terminate request.n" );
  674. #endif
  675.     //
  676.     // Terminate the resource.
  677.     //
  678.     SmbSmpDoTerminate( resourceEntry );
  679.     resourceEntry->State = ClusterResourceOffline;
  680. } // SmbSmpTerminate
  681. DWORD
  682. SmbSmpDoTerminate(
  683.     IN PSMBSMP_RESOURCE ResourceEntry
  684.     )
  685. /*++
  686. Routine Description:
  687.     Do the actual Terminate work for SMB Sample resources.
  688. Arguments:
  689.     ResourceEntry - Supplies resource entry for resource to be terminated
  690. Return Value:
  691.     ERROR_SUCCESS - The request completed successfully and the resource is 
  692.         offline.
  693.     Win32 error code - Will cause the resource monitor to log an event and 
  694.         call the Terminate routine.
  695. --*/
  696. {
  697.     DWORD       status = ERROR_SUCCESS;
  698.     //
  699.     // Kill off any pending threads.
  700.     //
  701.     ClusWorkerTerminate( &ResourceEntry->OnlineThread );
  702.     //
  703.     // Terminate the resource.
  704.     //
  705.     // TODO: Add code to terminate your resource.
  706.     status = NetShareDel( NULL, ResourceEntry->Params.ShareName, 0 );
  707.     if ( status != NO_ERROR ) {
  708.         (g_LogEvent)(
  709.             ResourceEntry->ResourceHandle,
  710.             LOG_ERROR,
  711.             L"Error removing share '%1'. Error %2!u!.n",
  712.             ResourceEntry->Params.ShareName,
  713.             status );
  714.     } else {
  715.         ResourceEntry->State = ClusterResourceOffline;
  716.     }
  717.     return(status);
  718. } // SmbSmpDoTerminate
  719. BOOL
  720. WINAPI
  721. SmbSmpLooksAlive(
  722.     IN RESID ResourceId
  723.     )
  724. /*++
  725. Routine Description:
  726.     LooksAlive routine for SMB Sample resources.
  727.     Perform a quick check to determine if the specified resource is probably
  728.     online (available for use).  This call should not block for more than
  729.     300 ms, preferably less than 50 ms.
  730. Arguments:
  731.     ResourceId - Supplies the resource id for the resource to polled.
  732. Return Value:
  733.     TRUE - The specified resource is probably online and available for use.
  734.     FALSE - The specified resource is not functioning normally.
  735. --*/
  736. {
  737.     PSMBSMP_RESOURCE  resourceEntry;
  738.     resourceEntry = (PSMBSMP_RESOURCE)ResourceId;
  739.     if ( resourceEntry == NULL ) {
  740.         DBG_PRINT("SmbSmp: LooksAlive request for a nonexistent resource id %un",
  741.             ResourceId );
  742.         return(FALSE);
  743.     }
  744.     if ( resourceEntry->ResId != ResourceId ) {
  745.         (g_LogEvent)(
  746.             resourceEntry->ResourceHandle,
  747.             LOG_ERROR,
  748.             L"LooksAlive sanity check failed! ResourceId = %1!u!.n",
  749.             ResourceId );
  750.         return(FALSE);
  751.     }
  752. #ifdef LOG_VERBOSE
  753.     (g_LogEvent)(
  754.         resourceEntry->ResourceHandle,
  755.         LOG_INFORMATION,
  756.         L"LooksAlive request.n" );
  757. #endif
  758.     // TODO: LooksAlive code
  759.     // NOTE: LooksAlive should be a quick check to see if the resource is
  760.     // available or not, whereas IsAlive should be a thorough check.  If
  761.     // there are no differences between a quick check and a thorough check,
  762.     // IsAlive can be called for LooksAlive, as it is below.  However, if there
  763.     // are differences, replace the call to IsAlive below with your quick
  764.     // check code.
  765.     //
  766.     // Check to see if the resource is alive.
  767.     //
  768.     return(SmbSmpCheckIsAlive( resourceEntry ));
  769. } // SmbSmpLooksAlive
  770. BOOL
  771. WINAPI
  772. SmbSmpIsAlive(
  773.     IN RESID ResourceId
  774.     )
  775. /*++
  776. Routine Description:
  777.     IsAlive routine for SMB Sample resources.
  778.     Perform a thorough check to determine if the specified resource is online
  779.     (available for use). This call should not block for more than 400 ms,
  780.     preferably less than 100 ms.
  781. Arguments:
  782.     ResourceId - Supplies the resource id for the resource to polled.
  783. Return Value:
  784.     TRUE - The specified resource is online and functioning normally.
  785.     FALSE - The specified resource is not functioning normally.
  786. --*/
  787. {
  788.     PSMBSMP_RESOURCE  resourceEntry;
  789.     resourceEntry = (PSMBSMP_RESOURCE)ResourceId;
  790.     if ( resourceEntry == NULL ) {
  791.         DBG_PRINT("SmbSmp: IsAlive request for a nonexistent resource id %un",
  792.             ResourceId );
  793.         return(FALSE);
  794.     }
  795.     if ( resourceEntry->ResId != ResourceId ) {
  796.         (g_LogEvent)(
  797.             resourceEntry->ResourceHandle,
  798.             LOG_ERROR,
  799.             L"IsAlive sanity check failed! ResourceId = %1!u!.n",
  800.             ResourceId );
  801.         return(FALSE);
  802.     }
  803. #ifdef LOG_VERBOSE
  804.     (g_LogEvent)(
  805.         resourceEntry->ResourceHandle,
  806.         LOG_INFORMATION,
  807.         L"IsAlive request.n" );
  808. #endif
  809.     //
  810.     // Check to see if the resource is alive.
  811.     //
  812.     return(SmbSmpCheckIsAlive( resourceEntry ));
  813. } // SmbSmpIsAlive
  814. BOOL
  815. SmbSmpCheckIsAlive(
  816.     IN PSMBSMP_RESOURCE ResourceEntry
  817.     )
  818. /*++
  819. Routine Description:
  820.     Check to see if the resource is alive for SMB Sample resources.
  821. Arguments:
  822.     ResourceEntry - Supplies the resource entry for the resource to polled.
  823. Return Value:
  824.     TRUE - The specified resource is online and functioning normally.
  825.     FALSE - The specified resource is not functioning normally.
  826. --*/
  827. {
  828.     SHARE_INFO_2        shareInfo;
  829.     DWORD               status;
  830.     //
  831.     // Check to see if the resource is alive.
  832.     //
  833.     // TODO: Add code to determine if your resource is alive.
  834.     status = NetShareGetInfo( NULL,
  835.                               ResourceEntry->Params.ShareName,
  836.                               2, // return a SHARE_INFO_2 structure
  837.                               (LPBYTE *) &shareInfo );
  838.     if ( status == NERR_NetNameNotFound ) {
  839.         (g_LogEvent)(
  840.             ResourceEntry->ResourceHandle,
  841.             LOG_ERROR,
  842.             L"Error, share '%1' went away.n",
  843.             ResourceEntry->Params.ShareName );
  844.         return(FALSE);
  845.     } else if ( status != ERROR_SUCCESS ) {
  846.         (g_LogEvent)(
  847.             ResourceEntry->ResourceHandle,
  848.             LOG_ERROR,
  849.             L"Error checking for share '%1'. Error %2!u!.n",
  850.             ResourceEntry->Params.ShareName,
  851.             status );
  852.     }
  853.     return(TRUE);
  854. } // SmbSmpCheckIsAlive
  855. DWORD
  856. WINAPI
  857. SmbSmpResourceControl(
  858.     IN RESID ResourceId,
  859.     IN DWORD ControlCode,
  860.     IN PVOID InBuffer,
  861.     IN DWORD InBufferSize,
  862.     OUT PVOID OutBuffer,
  863.     IN DWORD OutBufferSize,
  864.     OUT LPDWORD BytesReturned
  865.     )
  866. /*++
  867. Routine Description:
  868.     ResourceControl routine for SMB Sample resources.
  869.     Perform the control request specified by ControlCode on the specified
  870.     resource.
  871. Arguments:
  872.     ResourceId - Supplies the resource id for the specific resource.
  873.     ControlCode - Supplies the control code that defines the action
  874.         to be performed.
  875.     InBuffer - Supplies a pointer to a buffer containing input data.
  876.     InBufferSize - Supplies the size, in bytes, of the data pointed
  877.         to by InBuffer.
  878.     OutBuffer - Supplies a pointer to the output buffer to be filled in.
  879.     OutBufferSize - Supplies the size, in bytes, of the available space
  880.         pointed to by OutBuffer.
  881.     BytesReturned - Returns the number of bytes of OutBuffer actually
  882.         filled in by the resource. If OutBuffer is too small, BytesReturned
  883.         contains the total number of bytes for the operation to succeed.
  884. Return Value:
  885.     ERROR_SUCCESS - The function completed successfully.
  886.     ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  887.     ERROR_INVALID_FUNCTION - The requested control code is not supported.
  888.         In some cases, this allows the cluster software to perform the work.
  889.     Win32 error code - The function failed.
  890. --*/
  891. {
  892.     DWORD               status;
  893.     PSMBSMP_RESOURCE  resourceEntry;
  894.     DWORD               required;
  895.     resourceEntry = (PSMBSMP_RESOURCE)ResourceId;
  896.     if ( resourceEntry == NULL ) {
  897.         DBG_PRINT("SmbSmp: ResourceControl request for a nonexistent resource id %un",
  898.             ResourceId );
  899.         return(ERROR_RESOURCE_NOT_FOUND);
  900.     }
  901.     if ( resourceEntry->ResId != ResourceId ) {
  902.         (g_LogEvent)(
  903.             resourceEntry->ResourceHandle,
  904.             LOG_ERROR,
  905.             L"ResourceControl sanity check failed! ResourceId = %1!u!.n",
  906.             ResourceId );
  907.         return(ERROR_RESOURCE_NOT_FOUND);
  908.     }
  909.     switch ( ControlCode ) {
  910.         case CLUSCTL_RESOURCE_UNKNOWN:
  911.             *BytesReturned = 0;
  912.             status = ERROR_SUCCESS;
  913.             break;
  914.         case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  915.             status = ResUtilEnumProperties( SmbSmpResourcePrivateProperties,
  916.                                             OutBuffer,
  917.                                             OutBufferSize,
  918.                                             BytesReturned,
  919.                                             &required );
  920.             if ( status == ERROR_MORE_DATA ) {
  921.                 *BytesReturned = required;
  922.             }
  923.             break;
  924.         case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  925.             status = SmbSmpGetPrivateResProperties( resourceEntry,
  926.                                                       OutBuffer,
  927.                                                       OutBufferSize,
  928.                                                       BytesReturned );
  929.             break;
  930.         case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  931.             status = SmbSmpValidatePrivateResProperties( resourceEntry,
  932.                                                            InBuffer,
  933.                                                            InBufferSize,
  934.                                                            NULL );
  935.             break;
  936.         case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  937.             status = SmbSmpSetPrivateResProperties( resourceEntry,
  938.                                                       InBuffer,
  939.                                                       InBufferSize );
  940.             break;
  941.         default:
  942.             status = ERROR_INVALID_FUNCTION;
  943.             break;
  944.     }
  945.     return(status);
  946. } // SmbSmpResourceControl
  947. DWORD
  948. WINAPI
  949. SmbSmpResourceTypeControl(
  950.     IN LPCWSTR ResourceTypeName,
  951.     IN DWORD ControlCode,
  952.     IN PVOID InBuffer,
  953.     IN DWORD InBufferSize,
  954.     OUT PVOID OutBuffer,
  955.     IN DWORD OutBufferSize,
  956.     OUT LPDWORD BytesReturned
  957.     )
  958. /*++
  959. Routine Description:
  960.     ResourceTypeControl routine for SMB Sample resources.
  961.     Perform the control request specified by ControlCode.
  962. Arguments:
  963.     ResourceTypeName - Supplies the name of the resource type.
  964.     ControlCode - Supplies the control code that defines the action
  965.         to be performed.
  966.     InBuffer - Supplies a pointer to a buffer containing input data.
  967.     InBufferSize - Supplies the size, in bytes, of the data pointed
  968.         to by InBuffer.
  969.     OutBuffer - Supplies a pointer to the output buffer to be filled in.
  970.     OutBufferSize - Supplies the size, in bytes, of the available space
  971.         pointed to by OutBuffer.
  972.     BytesReturned - Returns the number of bytes of OutBuffer actually
  973.         filled in by the resource. If OutBuffer is too small, BytesReturned
  974.         contains the total number of bytes for the operation to succeed.
  975. Return Value:
  976.     ERROR_SUCCESS - The function completed successfully.
  977.     ERROR_INVALID_FUNCTION - The requested control code is not supported.
  978.         In some cases, this allows the cluster software to perform the work.
  979.     Win32 error code - The function failed.
  980. --*/
  981. {
  982.     DWORD               status;
  983.     DWORD               required;
  984.     switch ( ControlCode ) {
  985.         case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  986.             *BytesReturned = 0;
  987.             status = ERROR_SUCCESS;
  988.             break;
  989.         case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  990.             status = ResUtilEnumProperties( SmbSmpResourcePrivateProperties,
  991.                                             OutBuffer,
  992.                                             OutBufferSize,
  993.                                             BytesReturned,
  994.                                             &required );
  995.             if ( status == ERROR_MORE_DATA ) {
  996.                 *BytesReturned = required;
  997.             }
  998.             break;
  999.         default:
  1000.             status = ERROR_INVALID_FUNCTION;
  1001.             break;
  1002.     }
  1003.     return(status);
  1004. } // SmbSmpResourceTypeControl
  1005. DWORD
  1006. SmbSmpGetPrivateResProperties(
  1007.     IN OUT PSMBSMP_RESOURCE ResourceEntry,
  1008.     OUT PVOID OutBuffer,
  1009.     IN DWORD OutBufferSize,
  1010.     OUT LPDWORD BytesReturned
  1011.     )
  1012. /*++
  1013. Routine Description:
  1014.     Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
  1015.     for resources of type SMB Sample.
  1016. Arguments:
  1017.     ResourceEntry - Supplies the resource entry on which to operate.
  1018.     OutBuffer - Returns the output data.
  1019.     OutBufferSize - Supplies the size, in bytes, of the data pointed
  1020.         to by OutBuffer.
  1021.     BytesReturned - The number of bytes returned in OutBuffer.
  1022. Return Value:
  1023.     ERROR_SUCCESS - The function completed successfully.
  1024.     ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1025.     ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1026.     Win32 error code - The function failed.
  1027. --*/
  1028. {
  1029.     DWORD           status;
  1030.     DWORD           required;
  1031.     status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  1032.                                       SmbSmpResourcePrivateProperties,
  1033.                                       OutBuffer,
  1034.                                       OutBufferSize,
  1035.                                       BytesReturned,
  1036.                                       &required );
  1037.     if ( status == ERROR_MORE_DATA ) {
  1038.         *BytesReturned = required;
  1039.     }
  1040.     return(status);
  1041. } // SmbSmpGetPrivateResProperties
  1042. DWORD
  1043. SmbSmpValidatePrivateResProperties(
  1044.     IN OUT PSMBSMP_RESOURCE ResourceEntry,
  1045.     IN PVOID InBuffer,
  1046.     IN DWORD InBufferSize,
  1047.     OUT PSMBSMP_PARAMS Params
  1048.     )
  1049. /*++
  1050. Routine Description:
  1051.     Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  1052.     function for resources of type SMB Sample.
  1053. Arguments:
  1054.     ResourceEntry - Supplies the resource entry on which to operate.
  1055.     InBuffer - Supplies a pointer to a buffer containing input data.
  1056.     InBufferSize - Supplies the size, in bytes, of the data pointed
  1057.         to by InBuffer.
  1058.     Params - Supplies the parameter block to fill in.
  1059. Return Value:
  1060.     ERROR_SUCCESS - The function completed successfully.
  1061.     ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1062.     ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1063.     Win32 error code - The function failed.
  1064. --*/
  1065. {
  1066.     DWORD           status = ERROR_SUCCESS;
  1067.     SMBSMP_PARAMS   params;
  1068.     PSMBSMP_PARAMS  pParams;
  1069.     //
  1070.     // Check if there is input data.
  1071.     //
  1072.     if ( (InBuffer == NULL) ||
  1073.          (InBufferSize < sizeof(DWORD)) ) {
  1074.         return(ERROR_INVALID_DATA);
  1075.     }
  1076.     //
  1077.     // Duplicate the resource parameter block.
  1078.     //
  1079.     if ( Params == NULL ) {
  1080.         pParams = &params;
  1081.     } else {
  1082.         pParams = Params;
  1083.     }
  1084.     ZeroMemory( pParams, sizeof(SMBSMP_PARAMS) );
  1085.     status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1086.                                        (LPBYTE) &ResourceEntry->Params,
  1087.                                        SmbSmpResourcePrivateProperties );
  1088.     if ( status != ERROR_SUCCESS ) {
  1089.         return(status);
  1090.     }
  1091.     //
  1092.     // Parse and validate the properties.
  1093.     //
  1094.     status = ResUtilVerifyPropertyTable( SmbSmpResourcePrivateProperties,
  1095.                                          NULL,
  1096.                                          TRUE, // AllowUnknownProperties
  1097.                                          InBuffer,
  1098.                                          InBufferSize,
  1099.                                          (LPBYTE) pParams );
  1100.     if ( status == ERROR_SUCCESS ) {
  1101.         //
  1102.         // Validate the parameter values.
  1103.         //
  1104.         // TODO: Code to validate interactions between parameters goes here.
  1105.     }
  1106.     //
  1107.     // Cleanup our parameter block.
  1108.     //
  1109.     if ( pParams == &params ) {
  1110.         ResUtilFreeParameterBlock( (LPBYTE) &params,
  1111.                                    (LPBYTE) &ResourceEntry->Params,
  1112.                                    SmbSmpResourcePrivateProperties );
  1113.     }
  1114.     return status;
  1115. } // SmbSmpValidatePrivateResProperties
  1116. DWORD
  1117. SmbSmpSetPrivateResProperties(
  1118.     IN OUT PSMBSMP_RESOURCE ResourceEntry,
  1119.     IN PVOID InBuffer,
  1120.     IN DWORD InBufferSize
  1121.     )
  1122. /*++
  1123. Routine Description:
  1124.     Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  1125.     for resources of type SMB Sample.
  1126. Arguments:
  1127.     ResourceEntry - Supplies the resource entry on which to operate.
  1128.     InBuffer - Supplies a pointer to a buffer containing input data.
  1129.     InBufferSize - Supplies the size, in bytes, of the data pointed
  1130.         to by InBuffer.
  1131. Return Value:
  1132.     ERROR_SUCCESS - The function completed successfully.
  1133.     ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1134.     ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1135.     Win32 error code - The function failed.
  1136. --*/
  1137. {
  1138.     DWORD           status = ERROR_SUCCESS;
  1139.     SMBSMP_PARAMS   params;
  1140.     //
  1141.     // Parse the properties so they can be validated together.
  1142.     // This routine does individual property validation.
  1143.     //
  1144.     status = SmbSmpValidatePrivateResProperties( ResourceEntry, InBuffer, InBufferSize, &params );
  1145.     if ( status != ERROR_SUCCESS ) {
  1146.         ResUtilFreeParameterBlock( (LPBYTE) &params,
  1147.                                    (LPBYTE) &ResourceEntry->Params,
  1148.                                    SmbSmpResourcePrivateProperties );
  1149.         return(status);
  1150.     }
  1151.     //
  1152.     // Save the parameter values.
  1153.     //
  1154.     status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1155.                                                SmbSmpResourcePrivateProperties,
  1156.                                                NULL,
  1157.                                                (LPBYTE) &params,
  1158.                                                InBuffer,
  1159.                                                InBufferSize,
  1160.                                                (LPBYTE) &ResourceEntry->Params );
  1161.     ResUtilFreeParameterBlock( (LPBYTE) &params,
  1162.                                (LPBYTE) &ResourceEntry->Params,
  1163.                                SmbSmpResourcePrivateProperties );
  1164.     //
  1165.     // If the resource is online, return a non-success status.
  1166.     //
  1167.     // TODO: Modify the code below if your resource can handle
  1168.     // changes to properties while it is still online.
  1169.     if ( status == ERROR_SUCCESS ) {
  1170.         if ( ResourceEntry->State == ClusterResourceOnline ) {
  1171.             status = ERROR_RESOURCE_PROPERTIES_STORED;
  1172.         } else if ( ResourceEntry->State == ClusterResourceOnlinePending ) {
  1173.             status = ERROR_RESOURCE_PROPERTIES_STORED;
  1174.         } else {
  1175.             status = ERROR_SUCCESS;
  1176.         }
  1177.     }
  1178.     return status;
  1179. } // SmbSmpSetPrivateResProperties
  1180. //***********************************************************
  1181. //
  1182. // Define Function Table
  1183. //
  1184. //***********************************************************
  1185. CLRES_V1_FUNCTION_TABLE( g_SmbSmpFunctionTable,     // Name
  1186.                          CLRES_VERSION_V1_00,         // Version
  1187.                          SmbSmp,                    // Prefix
  1188.                          NULL,                        // Arbitrate
  1189.                          NULL,                        // Release
  1190.                          SmbSmpResourceControl,     // ResControl
  1191.                          SmbSmpResourceTypeControl); // ResTypeControl