Install Windows Service with Interacted with Desktop

本文介绍了一种在安装完成后修改Windows服务配置的方法,包括设置服务类型为交互式进程、更新服务描述、设置服务失败操作等。


	Private Sub ProjectInstaller_AfterInstall(ByVal sender As Object, ByVal e As System.Configuration.Install.InstallEventArgs) Handles MyBase.AfterInstall

		'Our code goes in this event because it is the only one that will do

		'a proper job of letting the user know that an error has occurred,

		'if one indeed occurs. Installation will be rolled back if an error occurs.



		Dim iSCManagerHandle As Integer

		Dim iSCManagerLockHandle As Integer

		Dim iServiceHandle As Integer

		Dim bChangeServiceConfig As Boolean

		Dim bChangeServiceConfig2 As Boolean

		Dim ServiceDescription As modAPI.SERVICE_DESCRIPTION

		Dim ServiceFailureActions As modAPI.SERVICE_FAILURE_ACTIONS

		Dim ScActions(2) As modAPI.SC_ACTION	 'There should be one element for each

		'action. The Services snap-in shows 3 possible actions.



		Dim bCloseService As Boolean

		Dim bUnlockSCManager As Boolean

		Dim bCloseSCManager As Boolean



		Dim iScActionsPointer As New IntPtr



		Try

			'Obtain a handle to the Service Control Manager, with appropriate rights.

			'This handle is used to open the relevant service.

			iSCManagerHandle = modAPI.OpenSCManager(vbNullString, vbNullString, _

			modAPI.ServiceControlManagerType.SC_MANAGER_ALL_ACCESS)



			'Check that it's open. If not throw an exception.

			If iSCManagerHandle < 1 Then

				Throw New Exception("Unable to open the Services Manager.")

			End If



			'Lock the Service Control Manager database.

			iSCManagerLockHandle = modAPI.LockServiceDatabase(iSCManagerHandle)



			'Check that it's locked. If not throw an exception.

			If iSCManagerLockHandle < 1 Then

				Throw New Exception("Unable to lock the Services Manager.")

			End If



			'Obtain a handle to the relevant service, with appropriate rights.

			'This handle is sent along to change the settings. The second parameter

			'should contain the name you assign to the service.

			iServiceHandle = modAPI.OpenService(iSCManagerHandle, "ServiceTest", _

			modAPI.ACCESS_TYPE.SERVICE_ALL_ACCESS)



			'Check that it's open. If not throw an exception.

			If iServiceHandle < 1 Then

				Throw New Exception("Unable to open the Service for modification.")

			End If



			'Call ChangeServiceConfig to update the ServiceType to SERVICE_INTERACTIVE_PROCESS.

			'Very important is that you do not leave out or change the other relevant

			'ServiceType settings. The call will return False if you do.

			'Also, only services that use the LocalSystem account can be set to

			'SERVICE_INTERACTIVE_PROCESS.

			bChangeServiceConfig = modAPI.ChangeServiceConfig(iServiceHandle, _

			modAPI.ServiceType.SERVICE_WIN32_OWN_PROCESS + modAPI.ServiceType.SERVICE_INTERACTIVE_PROCESS, _

			SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, vbNullString, vbNullString, _

			vbNullString, vbNullString, vbNullString, vbNullString, vbNullString)



			'If the call is unsuccessful, throw an exception.

			If Not bChangeServiceConfig Then

				Throw New Exception("Unable to change the Service settings.")

			End If



			'To change the description, create an instance of the SERVICE_DESCRIPTION

			'structure and set the lpDescription member to your desired description.

			ServiceDescription.lpDescription = "This is my custom description for my Windows Service Application!"



			'Call ChangeServiceConfig2 with SERVICE_CONFIG_DESCRIPTION in the second

			'parameter and the SERVICE_DESCRIPTION instance in the third parameter

			'to update the description.

			bChangeServiceConfig2 = modAPI.ChangeServiceConfig2(iServiceHandle, _

			modAPI.InfoLevel.SERVICE_CONFIG_DESCRIPTION, ServiceDescription)



			'If the update of the description is unsuccessful it is up to you to

			'throw an exception or not. The fact that the description did not update

			'should not impact the functionality of your service.

			If Not bChangeServiceConfig2 Then

				Throw New Exception("Unable to set the Service description.")

			End If



			'To change the Service Failure Actions, create an instance of the

			'SERVICE_FAILURE_ACTIONS structure and set the members to your

			'desired values. See MSDN for detailed descriptions.

			ServiceFailureActions.dwResetPeriod = 600

			ServiceFailureActions.lpRebootMsg = "Service failed to start! Rebooting..."

			ServiceFailureActions.lpCommand = "SomeCommand.exe Param1 Param2"

			ServiceFailureActions.cActions = ScActions.Length



			'The lpsaActions member of SERVICE_FAILURE_ACTIONS is a pointer to an

			'array of SC_ACTION structures. This complicates matters a little,

			'and although it took me a week to figure it out, the solution

			'is quite simple.



			'First order of business is to populate our array of SC_ACTION structures

			'with appropriate values.

			ScActions(0).Delay = 20000

			ScActions(0).SCActionType = modAPI.SC_ACTION_TYPE.SC_ACTION_RESTART

			ScActions(1).Delay = 20000

			ScActions(1).SCActionType = modAPI.SC_ACTION_TYPE.SC_ACTION_RUN_COMMAND

			ScActions(2).Delay = 20000

			ScActions(2).SCActionType = modAPI.SC_ACTION_TYPE.SC_ACTION_REBOOT



			'Once that's done, we need to obtain a pointer to a memory location

			'that we can assign to lpsaActions in SERVICE_FAILURE_ACTIONS.

			'We use 'Marshal.SizeOf(New modAPI.SC_ACTION) * 3' because we pass 

			'3 actions to our service. If you have less actions change the * 3 accordingly.

			iScActionsPointer = Marshal.AllocHGlobal(Marshal.SizeOf(New modAPI.SC_ACTION) * 3)



			'Once we have obtained the pointer for the memory location we need to

			'fill the memory with our structure. We use the CopyMemory API function

			'for this. Please have a look at it's declaration in modAPI.

			modAPI.CopyMemory(iScActionsPointer, ScActions, Marshal.SizeOf(New modAPI.SC_ACTION) * 3)



			'We set the lpsaActions member of SERVICE_FAILURE_ACTIONS to the integer

			'value of our pointer.

			ServiceFailureActions.lpsaActions = iScActionsPointer.ToInt32



			'We call bChangeServiceConfig2 with the relevant parameters.

			bChangeServiceConfig2 = modAPI.ChangeServiceConfig2(iServiceHandle, _

			modAPI.InfoLevel.SERVICE_CONFIG_FAILURE_ACTIONS, ServiceFailureActions)



			'If the update of the failure actions are unsuccessful it is up to you to

			'throw an exception or not. The fact that the failure actions did not update

			'should not impact the functionality of your service.

			If Not bChangeServiceConfig2 Then

				Throw New Exception("Unable to set the Service failure actions.")

			End If

		Catch ex As Exception

			Throw ex

		Finally

			'Once you are done you should close/release the handles to the service

			'and the Service Control Manager, as well as free the memory that held

			'the array of SC_ACTION structures.



			Marshal.FreeHGlobal(iScActionsPointer)

			If iServiceHandle > 0 Then

				bCloseService = modAPI.CloseServiceHandle(iServiceHandle)

			End If



			bUnlockSCManager = modAPI.UnlockServiceDatabase(iSCManagerLockHandle)



			If iSCManagerHandle > 0 Then

				bCloseSCManager = modAPI.CloseServiceHandle(iSCManagerHandle)

			End If

		End Try



		'When installation is done go check out your handy work using Computer Management!

	End Sub



 
### 解决 `play()` 方法因用户未与文档交互而失败的问题 当调用 HTMLMediaElement 的 `play()` 方法时,如果浏览器的安全策略要求用户先与页面进行某种形式的互动(点击、触摸等),则可能会抛出 `NotAllowedError` 错误。这种安全措施旨在防止网页未经用户许可自动播放媒体文件。 为了处理这种情况并提供更好的用户体验,可以采用以下几种解决方案: #### 1. 使用 Autoplay 属性配合 Muted 参数 现代浏览器允许静音状态下自动播放视频,因此可以在 `<video>` 或者 `<audio>` 标签上设置 muted 和 autoplay 属性来实现无声启动[^1]。 ```html <video id="myVideo" controls muted autoplay> <source src="movie.mp4" type="video/mp4"> </video> ``` #### 2. 捕获异常并等待用户操作后再尝试播放 通过 try-catch 结构捕获 NotAllowedError 异常,在 catch 块内监听用户的首次交互事件(如 click 或 touchstart)。一旦检测到这些动作,则再次尝试执行 media.play() 来触发实际播放行为。 ```javascript const video = document.getElementById('myVideo'); try { await video.play(); } catch (error) { if (error.name === 'NotAllowedError') { // Wait for user interaction before playing. const promiseToPlayAfterInteraction = new Promise((resolve) => { ['click', 'touchstart'].forEach(eventType => window.addEventListener(eventType, resolve, { once: true })); }); await promiseToPlayAfterInteraction; // Try to play after user has interacted with page. await video.play().catch(console.error); } else { throw error; // Re-throw other errors not related to playback restrictions. } } ``` 以上两种方式都可以有效应对由于缺乏初始用户交互而导致无法正常播放的情况。具体选择哪种取决于应用场景以及期望达到的效果。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值