Files
KinginfoGateway/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/COM/Comn/ComInterop.cs
2023-09-30 23:05:53 +08:00

371 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
/// <summary>
/// The WIN32 system default locale.
/// </summary>
private const int LOCALE_SYSTEM_DEFAULT = 0x800;
/// <summary>
/// The WIN32 user default locale.
/// </summary>
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
/// <summary>
/// 创建一个COM服务器的实例。
/// </summary>
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;
}
/// <summary>
/// 指定错误消息文本检索系统。
/// </summary>
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);
}
/// <summary>
/// 初始化COM安全。
/// </summary>
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);
}
}
/// <summary>
/// 从枚举器读取guid。
/// </summary>
internal static Guid[] ReadClasses(IOPCEnumGUID enumerator)
{
List<Guid> guids = new List<Guid>();
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();
}
/// <summary>
/// 从枚举器读取guid。
/// </summary>
internal static Guid[] ReadClasses(IEnumGUID enumerator)
{
List<Guid> guids = new List<Guid>();
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();
}
/// <summary>
/// 释放 COM 对象
/// </summary>
/// <param name="m_server"></param>
internal static void RealseComServer(object m_server)
{
if (m_server != null && m_server.GetType().IsCOMObject)
{
Marshal.ReleaseComObject(m_server);
}
}
}