#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQ群:605534569
//------------------------------------------------------------------------------
#endregion
using System.Runtime.InteropServices;
using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
namespace ThingsGateway.Foundation.Adapter.OPCDA.Comn;
#pragma warning disable CA1416 // 验证平台兼容性
#pragma warning disable IDE0090
#pragma warning disable IDE0051
internal class ComInterop
{
private static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
#region const
private const uint EOAC_ACCESS_CONTROL = 0x04;
private const uint EOAC_APPID = 0x08;
private const uint EOAC_CLOAKING = 0x10;
private const uint EOAC_DYNAMIC_CLOAKING = 0x40;
private const uint EOAC_MUTUAL_AUTH = 0x01;
private const uint EOAC_NONE = 0x00;
private const uint EOAC_SECURE_REFS = 0x02;
private const uint EOAC_STATIC_CLOAKING = 0x20;
///
/// The WIN32 system default locale.
///
private const int LOCALE_SYSTEM_DEFAULT = 0x800;
///
/// The WIN32 user default locale.
///
private const int LOCALE_USER_DEFAULT = 0x400;
private const uint RPC_C_AUTHN_DCE_PRIVATE = 1;
private const uint RPC_C_AUTHN_DCE_PUBLIC = 2;
private const uint RPC_C_AUTHN_DEC_PUBLIC = 4;
private const uint RPC_C_AUTHN_DEFAULT = 0xFFFFFFFF;
private const uint RPC_C_AUTHN_DIGEST = 21;
private const uint RPC_C_AUTHN_DPA = 17;
private const uint RPC_C_AUTHN_GSS_KERBEROS = 16;
private const uint RPC_C_AUTHN_GSS_NEGOTIATE = 9;
private const uint RPC_C_AUTHN_GSS_SCHANNEL = 14;
private const uint RPC_C_AUTHN_LEVEL_CALL = 3;
private const uint RPC_C_AUTHN_LEVEL_CONNECT = 2;
private const uint RPC_C_AUTHN_LEVEL_DEFAULT = 0;
private const uint RPC_C_AUTHN_LEVEL_NONE = 1;
private const uint RPC_C_AUTHN_LEVEL_PKT = 4;
private const uint RPC_C_AUTHN_LEVEL_PKT_INTEGRITY = 5;
private const uint RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6;
private const uint RPC_C_AUTHN_MQ = 100;
private const uint RPC_C_AUTHN_MSN = 18;
private const uint RPC_C_AUTHN_NONE = 0;
private const uint RPC_C_AUTHN_WINNT = 10;
private const uint RPC_C_AUTHZ_DCE = 2;
private const uint RPC_C_AUTHZ_DEFAULT = 0xffffffff;
private const uint RPC_C_AUTHZ_NAME = 1;
private const uint RPC_C_AUTHZ_NONE = 0;
private const uint RPC_C_IMP_LEVEL_ANONYMOUS = 1;
private const uint RPC_C_IMP_LEVEL_DELEGATE = 4;
private const uint RPC_C_IMP_LEVEL_IDENTIFY = 2;
private const uint RPC_C_IMP_LEVEL_IMPERSONATE = 3;
#endregion const
#region struct
public struct COSERVERINFO
{
public uint dwReserved1;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwszName;
public IntPtr pAuthInfo;
public uint dwReserved2;
};
public struct MULTI_QI
{
public IntPtr iid;
[MarshalAs(UnmanagedType.IUnknown)]
public object pItf;
public uint hr;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SOLE_AUTHENTICATION_SERVICE
{
public uint dwAuthnSvc;
public uint dwAuthzSvc;
[MarshalAs(UnmanagedType.LPWStr)]
public string pPrincipalName;
public int hr;
}
#endregion struct
#region win32 api
[DllImport("ole32.dll")]
private static extern void CoCreateInstanceEx(ref Guid clsid,
[MarshalAs(UnmanagedType.IUnknown)] object punkOuter,
uint dwClsCtx,
[In] ref COSERVERINFO pServerInfo,
uint dwCount,
[In, Out] MULTI_QI[] pResults);
[DllImport("ole32.dll")]
private static extern int CoInitializeSecurity(
IntPtr pSecDesc,
int cAuthSvc,
SOLE_AUTHENTICATION_SERVICE[] asAuthSvc,
IntPtr pReserved1,
uint dwAuthnLevel,
uint dwImpLevel,
IntPtr pAuthList,
uint dwCapabilities,
IntPtr pReserved3);
[DllImport("Kernel32.dll")]
private static extern int FormatMessageW(
int dwFlags,
IntPtr lpSource,
int dwMessageId,
int dwLanguageId,
IntPtr lpBuffer,
int nSize,
IntPtr Arguments);
[DllImport("Kernel32.dll")]
private static extern int GetSystemDefaultLangID();
[DllImport("Kernel32.dll")]
private static extern int GetUserDefaultLangID();
#endregion win32 api
///
/// 创建一个COM服务器的实例。
///
public static object CreateInstance(Guid clsid, string hostName)
{
COSERVERINFO coserverInfo = new()
{
pwszName = hostName,
pAuthInfo = IntPtr.Zero,
dwReserved1 = 0,
dwReserved2 = 0
};
GCHandle hIID = GCHandle.Alloc(IID_IUnknown, GCHandleType.Pinned);
MULTI_QI[] results = new MULTI_QI[1];
results[0].iid = hIID.AddrOfPinnedObject();
results[0].pItf = null;
results[0].hr = 0;
try
{
// 检查是否在本地或远程连接。
uint clsctx = 0x01 | 0x04;
if (hostName != null && hostName.Length > 0 && hostName.ToLower() != "localhost" && hostName != "127.0.0.1")
{
clsctx = 0x04 | 0x10;
}
// create an instance.
CoCreateInstanceEx(
ref clsid,
null,
clsctx,
ref coserverInfo,
1,
results);
}
catch (Exception ex)
{
throw new ExternalException("CoCreateInstanceEx: " + ex.Message);
}
finally
{
if (hIID.IsAllocated) hIID.Free();
}
if (results[0].hr != 0)
{
throw new ExternalException("CoCreateInstanceEx: " + GetSystemMessage((int)results[0].hr));
}
return results[0].pItf;
}
///
/// 指定错误消息文本检索系统。
///
internal static string GetSystemMessage(int error)
{
const int MAX_MESSAGE_LENGTH = 1024;
const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
IntPtr buffer = Marshal.AllocCoTaskMem(MAX_MESSAGE_LENGTH);
_ = FormatMessageW(
(int)(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM),
IntPtr.Zero,
error,
0,
buffer,
MAX_MESSAGE_LENGTH - 1,
IntPtr.Zero);
string msg = Marshal.PtrToStringUni(buffer);
Marshal.FreeCoTaskMem(buffer);
if (!string.IsNullOrEmpty(msg))
{
return msg;
}
return string.Format("0x{0,0:X}", error);
}
///
/// 初始化COM安全。
///
internal static void InitializeSecurity()
{
int error = CoInitializeSecurity(
IntPtr.Zero,
-1,
null,
IntPtr.Zero,
RPC_C_AUTHN_LEVEL_CONNECT,
RPC_C_IMP_LEVEL_IMPERSONATE,
IntPtr.Zero,
EOAC_NONE,
IntPtr.Zero);
if (error != 0)
{
throw new ExternalException("COM初始化安全: " + GetSystemMessage(error), error);
}
}
///
/// 从枚举器读取guid。
///
internal static Guid[] ReadClasses(IOPCEnumGUID enumerator)
{
List guids = new List();
int fetched = 0;
Guid[] buffer = new Guid[10];
do
{
try
{
IntPtr pGuids = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(Guid)) * buffer.Length);
try
{
enumerator.Next(buffer.Length, pGuids, out fetched);
if (fetched > 0)
{
IntPtr pos = pGuids;
for (int ii = 0; ii < fetched; ii++)
{
object o = Marshal.PtrToStructure(pos, typeof(Guid));
if (o != null)
{
buffer[ii] = (Guid)o;
}
pos = IntPtr.Add(pos, Marshal.SizeOf(typeof(Guid)));
guids.Add(buffer[ii]);
}
}
}
finally
{
Marshal.FreeCoTaskMem(pGuids);
}
}
catch (Exception)
{
break;
}
}
while (fetched > 0);
return guids.ToArray();
}
///
/// 从枚举器读取guid。
///
internal static Guid[] ReadClasses(IEnumGUID enumerator)
{
List guids = new List();
int fetched = 0;
Guid[] buffer = new Guid[10];
do
{
try
{
IntPtr pGuids = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(Guid)) * buffer.Length);
try
{
enumerator.Next(buffer.Length, pGuids, out fetched);
if (fetched > 0)
{
IntPtr pos = pGuids;
for (int ii = 0; ii < fetched; ii++)
{
object o = Marshal.PtrToStructure(pos, typeof(Guid));
if (o != null)
{
buffer[ii] = (Guid)o;
}
pos = IntPtr.Add(pos, Marshal.SizeOf(typeof(Guid)));
guids.Add(buffer[ii]);
}
}
}
finally
{
Marshal.FreeCoTaskMem(pGuids);
}
}
catch (Exception)
{
break;
}
}
while (fetched > 0);
return guids.ToArray();
}
///
/// 释放 COM 对象
///
///
internal static void RealseComServer(object m_server)
{
if (m_server != null && m_server.GetType().IsCOMObject)
{
Marshal.ReleaseComObject(m_server);
}
}
}