如何在Windows 10中使用C#的Winform启用和禁用蓝牙?

huangapple go评论82阅读模式
英文:

How to enable and disable bluetooth using winform in Windows 10 using C#?

问题

使用WinForm开发客户端,客户端需要在通信后关闭蓝牙,需要与蓝牙通信时打开蓝牙。

在Windows 10上,可以在设置 -> 设备 -> 蓝牙和其他设备中找到用于打开或关闭蓝牙的开关。是否可以使用一些Windows API来打开或关闭蓝牙?

英文:

using winform to develop client, the client need to turn off bluetooth after communication and when need to communication with bluetooth, turn on bluetooth.

On Windows 10, the settings -> devices -> bluetooth and other devices has the switch to turn on bluetooth or turn off. is possible to use some windows api to turn on or turn off the bluetooth?

答案1

得分: 1

BluetoothSetServiceState函数用于打开/关闭蓝牙设备的服务,从根本上启用/禁用整个设备。

然而,要打开/关闭蓝牙发射器(SDK中的“无线电”),Windows Runtime API具有Windows.Devices.Radios,其中RadioState可设置为OnOffDisabledUnknown

如果需要指导,这里有一些示例:

https://github.com/Microsoft/Windows-universal-samples/tree/main/Samples/RadioManager

英文:

The BluetoothSetServiceState function turns services on/off for a Bluetooth device, essentially enabling/disabling the device as a whole.

However, to turn on/off the Bluetooth transmitter ("radio" in SDK parlance), the Windows Runtime API has Windows.Devices.Radios with RadioState settable to On, Off, Disabled, or Unknown.

There are some samples here for guidance if you need them:

https://github.com/Microsoft/Windows-universal-samples/tree/main/Samples/RadioManager

答案2

得分: 0

BluetoothSetServiceState,如上所述,与蓝牙硬件本身无关。它只是添加/删除已配对的蓝牙启用设备的驱动程序。如果您已经与支持串行端口配置文件的设备配对,您可以使用此方法安装该服务的虚拟COM端口,或者移除它们。没有其他操作。

上面回答的第二部分是正确的。然而,它有一个非常重要的限制:应用程序必须与操作系统具有相同的“位数”。*如果您的应用程序在64位操作系统上运行,它(应用程序)必须也是64位的。64位操作系统上的32位应用程序将无法运行,因为RadioManager接口(内部使用基于COM的管理器来执行实际工作)只为64位注册(作为64位进程内COM服务器)。RadioState(当您设置它时)只是通过调用CoCreateInstance()检查RadioManager是否已注册,然后调用它的方法(请参阅下面的代码,该代码实际上与WinRT API执行的操作相同)。

因此,您可以直接调用RadioManager接口(和对象)而不是使用该API:

private static readonly Guid CLSID_BluetoothRadioManager = new Guid("{afd198ac-5f30-4e89-a789-5ddf60a69366}");
public const UInt32 CLSCTX_INPROC_SERVER = 1;

[DllImport("ole32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.I4)]
public static extern Int32 CoCreateInstance(
  [param: MarshalAs(UnmanagedType.LPStruct), In] Guid rclsid,
  [param: MarshalAs(UnmanagedType.SysInt), In] IntPtr pUnkOuter,
  [param: MarshalAs(UnmanagedType.U4), In] UInt32 dwClsContext,
  [param: MarshalAs(UnmanagedType.LPStruct), In] Guid riid,
  [param: MarshalAs(UnmanagedType.Interface), Out] out Object ppv);
// ...(接下来是其他接口和枚举的定义,以及ChangeRadioState方法的实现)

正如您所看到的,这种方式使您更加灵活,并且可以与WiFi适配器一起使用(通过查询WiFi Radio接口)。关于操作系统位数:对于.NET应用程序使用Any CPU配置是可以的,但对于本机应用程序(C++、VCL等),可能会有问题,因为它们可以编译为32位应用程序,但在64位操作系统上运行。此外,这可能不适用于Windows 8

我们曾在我们的蓝牙框架库中使用这种方式。但后来切换到另一种完全可行的、与操作系统位数无关的方法。不幸的是,我不能在这里分享那段代码。

英文:

BluetoothSetServiceState, as described above, does nothing with Bluetooth hardware itself. It simple adds/removes drivers for paired Bluetooth enabled device. If you have paired device with, let say, Serial Port Profile, you can use this method to install vCOMs for that service and/or removes them. Nothing more.

The second part of the answer above is correct. However it has one very important limitation: the application uses it must has the same "bits" as the OS. If your application runs on 64bit OS it (the app) must be 64bits as well. 32bits app on 64bits OS will not work because the RadioManager interface (internally it uses COM based Managers that actually does the job) registered only for 64bits (as 64bits inproc COM server). RadioState (when you set it) simple checks if the RadioManager is registered by calling CoCreateInstance() and then calls its methods (see code below that does exactly the same what WinRT API does).

So instead of using that API you can directly call to RadioManager interface (and object):

<pre><code>
private static readonly Guid CLSID_BluetoothRadioManager = new Guid("{afd198ac-5f30-4e89-a789-5ddf60a69366}");
public const UInt32 CLSCTX_INPROC_SERVER = 1;

[DllImport(&quot;ole32.dll&quot;, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.I4)]
public static extern Int32 CoCreateInstance(
  [param: MarshalAs(UnmanagedType.LPStruct), In] Guid rclsid,
  [param: MarshalAs(UnmanagedType.SysInt), In] IntPtr pUnkOuter,
  [param: MarshalAs(UnmanagedType.U4), In] UInt32 dwClsContext,
  [param: MarshalAs(UnmanagedType.LPStruct), In] Guid riid,
  [param: MarshalAs(UnmanagedType.Interface), Out] out Object ppv);

[ComImport]
[Guid(&quot;6CFDCAB5-FC47-42A5-9241-074B58830E73&quot;)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMediaRadioManager
{
  [PreserveSig]
  [return: MarshalAs(UnmanagedType.I4)]
  Int32 GetRadioInstances(
    [param: MarshalAs(UnmanagedType.Interface), Out] out IRadioInstanceCollection ppCollection);

  [PreserveSig]
  [return: MarshalAs(UnmanagedType.I4)]
  Int32 OnSystemRadioStateChange(
    [param: In] SYSTEM_RADIO_STATE sysRadioState,
    [param: MarshalAs(UnmanagedType.U4), In] UInt32 uTimeoutSec);
};

[ComImport]
[Guid(&quot;E5791FAE-5665-4E0C-95BE-5FDE31644185&quot;)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IRadioInstanceCollection
{
  [PreserveSig]
  [return: MarshalAs(UnmanagedType.I4)]
  Int32 GetCount(
    [param: MarshalAs(UnmanagedType.U4), Out] out UInt32 pcInstance);

  [PreserveSig]
  [return: MarshalAs(UnmanagedType.I4)]
  Int32 GetAt(
    [param: MarshalAs(UnmanagedType.U4), In] UInt32 uIndex,
    [param: MarshalAs(UnmanagedType.Interface), Out] out IRadioInstance ppRadioInstance);
};

[ComImport]
[Guid(&quot;70AA1C9E-F2B4-4C61-86D3-6B9FB75FD1A2&quot;)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IRadioInstance
{
  [PreserveSig]
  [return: MarshalAs(UnmanagedType.I4)]
  Int32 GetRadioManagerSignature(
    [param: Out] out Guid pguidSignature);

  [PreserveSig]
  [return: MarshalAs(UnmanagedType.I4)]
  Int32 GetInstanceSignature(
    [param: MarshalAs(UnmanagedType.BStr), Out] out String pbstrId);

  [PreserveSig]
  [return: MarshalAs(UnmanagedType.I4)]
  Int32 GetFriendlyName(
    [param: MarshalAs(UnmanagedType.U4), In] UInt32 lcid,
    [param: MarshalAs(UnmanagedType.BStr), Out] out String pbstrName);
  
  [PreserveSig]
  [return: MarshalAs(UnmanagedType.I4)]
  Int32 GetRadioState(
    [param: Out] out DEVICE_RADIO_STATE pRadioState);

  [PreserveSig]
  [return: MarshalAs(UnmanagedType.I4)]
  Int32 SetRadioState(
    [param: In] DEVICE_RADIO_STATE radioState,
    [param: MarshalAs(UnmanagedType.U4), In] UInt32 uTimeoutSec);

  [PreserveSig]
  [return: MarshalAs(UnmanagedType.Bool)]
  Boolean IsMultiComm();
  
  [PreserveSig]
  [return: MarshalAs(UnmanagedType.Bool)]
  Boolean IsAssociatingDevice();
};

private enum DEVICE_RADIO_STATE : int
{
  DRS_RADIO_ON = 0,
  DRS_SW_RADIO_OFF = 1,
  DRS_HW_RADIO_OFF = 2,
  DRS_SW_HW_RADIO_OFF = 3,
  DRS_HW_RADIO_ON_UNCONTROLLABLE = 4,
  DRS_RADIO_INVALID = 5,
  DRS_HW_RADIO_OFF_UNCONTROLLABLE = 6,
  DRS_RADIO_MAX = DRS_HW_RADIO_OFF_UNCONTROLLABLE
};

private Boolean ChangeRadioState(Boolean TurnOn)
{
  // Try to get Bluetooth Radio Manager interface.
  Object oRadioMan;
  Int32 Res = CoCreateInstance(CLSID_BluetoothRadioManager, IntPtr.Zero, CLSCTX_INPROC_SERVER,
    typeof(IMediaRadioManager).GUID, out oRadioMan);
  if (Res != 0x00000000)
    return false;
  
  IMediaRadioManager RadioMan = oRadioMan as IMediaRadioManager;
  IRadioInstanceCollection Radios;
  if (RadioMan.GetRadioInstances(out Radios) != 0x00000000)
    return false;
  
  UInt32 Cnt = 0;
  if (Radios.GetCount(out Cnt) != 0x00000000)
    return false;
  if (Cnt == 0)
    return false;
  
  IRadioInstance Radio;
  if (Radios.GetAt(0, out Radio) != 0x00000000)
    return false;
  
  DEVICE_RADIO_STATE State;
  if (TurnOn)
    State = DEVICE_RADIO_STATE.DRS_RADIO_ON;
  else
    State = DEVICE_RADIO_STATE.DRS_SW_RADIO_OFF;
  if (Radio.SetRadioState(State, 10) != 0x00000000)
    return false;
  
  return true;
}

</code></pre>

As you can see this way gives you more control and also can be used with WiFi adapter (with querying WiFi Radio interface). Back to OS bits: it is OK for .NET applications with Any CPU configuration but can be a big problem for native applications (C++, VCL, etc) that can be compiled as 32bits but run on 64bits OS. Also, this may not work on Windows 8.

We used that way in our Bluetooth Framework library early. But then switched to another, 100% working, OS bits independent way. Unfortunately I can not share that code here.

huangapple
  • 本文由 发表于 2023年2月24日 00:24:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/75547578.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定