*(00)*

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
https://www.cnblogs.com/heqing/p/3562031.html
OPC客户端的进程安全初始化

  现场OPC客户端无法获取远程OPC Server列表,也无法连接OPC Server,经查调用CoCreateInstanceEx()创建IID_IOPCServerList接口正常,但调用IOPCServerList->EnumClassesOfCategories()时返回0x80070532错误,可是用PI的OPC-Tool测试OPC Server的各项操作正常,于是被迫周末加班一天,发现是未对OPC客户端的进程进行安全初始化造成的:

1
2
3
4
5
6
7
8
9
10
11
HRESULT hr = ::CoInitializeSecurity(
        NULL,                    // points to security descriptor
        -1,                     // count of entries in asAuthSvc
        NULL,                    // array of names to register
        NULL,                    // reserved for future use
        RPC_C_AUTHN_LEVEL_NONE, // the default authentication level for proxies
        RPC_C_IMP_LEVEL_IMPERSONATE,// the default impersonation level for proxies
        NULL,                    // used only on Windows 2000
        EOAC_NONE,              // additional client or server-side capabilities
        NULL                     // reserved for future use
        );

  该代码只需要加入到CxxxxApp::InitInstance()中即可。

   如果用Delphi开发的OPC客户端,则可以在主程序的OnCreate事件中调用以下的OPCInitSecurity()函数即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function OPCInitSecurity: HResult;
const
  RPC_C_AUTHN_LEVEL_NONE = 1;
  RPC_C_IMP_LEVEL_IMPERSONATE = 3;
  EOAC_NONE = 0;
begin
    Result := CoInitializeSecurity(
        nil,                    // points to security descriptor
        -1,                     // count of entries in asAuthSvc
        nil,                    // array of names to register
        nil,                    // reserved for future use
        RPC_C_AUTHN_LEVEL_NONE, // the default authentication level for proxies
        RPC_C_IMP_LEVEL_IMPERSONATE,// the default impersonation level for proxies
        nil,                    // used only on Windows 2000
        EOAC_NONE,              // additional client or server-side capabilities
        nil                     // reserved for future use
        );
end;

  

  总结:

  1. 周末加班很郁闷,独自一个人加班更加郁闷;
  2. PI OPC-Tool界面很丑陋,但兼容性很强大,多次发现我们的OPC客户端无法正常工作,PI OPC-Tool畅通无阻,搞得现在现场OPC客户端一出现问题,工程师先用这个工具测试,正常,找我;不正常,自己鼓捣先;
  3. 通过DCOM访问OPC Server必须调用CoInitializeSecurity(),否则在不同的计算机上可能会出现不同的错误现象,但根源问题殊途同归;
  4. OPC工业现场必备垃圾;

 --------------------------------------------------------------------------

https://blog.csdn.net/embededvc/article/details/18863535?locationNum=1&fps=1

DCOM是依赖于RPC服务的,是一种分布式远程过程(进程)调用,调用代码在远程主机上执行,使用远程主机的系统资源,因此要有远程主机所属的访问权限,一般来说访问用户应是远程主机本地用户或主机所属的域用户,所以

  第一步是在远程主机或其域上注册(获得)一个有足够权限的用户,

  第二步是使用此用户令牌激活远程COM服务器,方法是使用CoInitializeSecurity & CoCreateInstanceEx函数(见文后例子),成功激活后就得到相关请求接口的代理,此时代理并没有对远程服务器访问的权限,

  第三步是为接口代理设置访问权限,方法是使用CoSetProxyBlanket函数,此后就可以使用代理指针进行方法调用了。见文后例子

  以上是客户端要做的处理,至于服务器端,只要使用CoInitializeSecurity函数设置一下访问许可权限就可以了(有时客户端也要进行这一处理,比如使用了连接点),对于即存的服务器程序使用dcomcfg工具在注册表里设置也可以。

  CoSetProxyBlanket函数调用例子:

  *******************************

  原例子:

  

IRecordServerLink* pRSL=(IRecordServerLink*)mq[0].pItf;
 
 
 
hr = CoSetProxyBlanket( pRSL, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
 
   
 
RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, &caid, EOAC_NONE);
 
pRSL->Methods();

  

  ----------------------------------

  修改后的例子:

   

hr = CoSetProxyBlanket( pAccount, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
 
   
 
RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, &caid, EOAC_NONE);
 
pAccount->Deposit(x);

 

 

  ※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

  CoInitializeSecurity & CoCreateInstanceEx函数调用例子:

  *********************************************************

  例子1:

  

HRESULT hr;
 
hr = CoInitialize(NULL);
 
ASSERT(SUCCEEDED(hr));
 
MULTI_QI qi;
 
qi.pIID = &IID_ICRemoteTime;
 
qi.hr = NULL;
 
qi.pItf = NULL;
 
COAUTHIDENTITY authidentity;
 
authidentity.User = L"administrator";  你机子的帐号
 
authidentity.UserLength = wcslen(authidentity.User);
 
authidentity.Domain = NULL;
 
authidentity.DomainLength = 0;
 
authidentity.Password = L"";     密码
 
authidentity.PasswordLength = wcslen(authidentity.User);
 
authidentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
 
COAUTHINFO authinfo = {-1, 0, 0, RPC_C_AUTHN_LEVEL_DEFAULT,
 
   
 
RPC_C_IMP_LEVEL_IMPERSONATE, &authidentity, 0};
 
COSERVERINFO servInf;
 
servInf.dwReserved1 = NULL;
 
servInf.dwReserved2 = NULL;
 
// servInf.pAuthInfo = NULL;
 
servInf.pAuthInfo = &authinfo;
 
USES_CONVERSION;
 
servInf.pwszName = L"127.0.0.1";
 
hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
 
 
 
RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_ACCESS_CONTROL, NULL);
 
ASSERT(SUCCEEDED(hr));
 
hr = CoCreateInstanceEx(CLSID_CRemoteTime, NULL, CLSCTX_REMOTE_SERVER, &servInf, 1, &qi);
 
if (FAILED(hr))
 
{
 
 TRACE(_T("CoCreateInstanceEx failed"));
 
 return false;;
 
}
 
if (FAILED(qi.hr))
 
{
 
 TRACE(_T("Failed to connect to server"));
 
 return false;;
 
}
 
//通过IUnkonwn指针去查询接口指针,返回IAccount指针
 
hr = pUnknown->QueryInterface(IID_ICRemoteTime,(void**)&pIRetime)

 

 

  例子2:

  

HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
 
 
 
RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
 
 
 
 COAUTHIDENTITY us;
 
 
 
 us.User      = m_strName.AllocSysString();
 
 us.UserLength   = wcslen(us.User);
 
 us.Password    = m_strPassword.AllocSysString();
 
 us.PasswordLength = wcslen(us.Password);
 
 us.Domain     = m_strDomain.AllocSysString();
 
 us.DomainLength  = wcslen(us.Domain);
 
 us.Flags     = SEC_WINNT_AUTH_IDENTITY_UNICODE;
 
 
 
 COAUTHINFO auth;
 
 
 
 auth.dwAuthnSvc      = RPC_C_AUTHN_WINNT;
 
 auth.dwAuthzSvc      = RPC_C_AUTHZ_NONE;
 
 auth.pwszServerPrincName = NULL;
 
 auth.dwAuthnLevel     = RPC_C_AUTHN_LEVEL_CONNECT;
 
 auth.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
 
 auth.dwCapabilities    = EOAC_NONE;
 
 auth.pAuthIdentityData  = &us;
 
 
 
 COSERVERINFO si;
 
 MULTI_QI   qi;
 
 
 
 CComBSTR bstr = strComputer;
 
 LPWSTR name  = bstr.m_str;
 
 
 
 si.dwReserved1 = 0;
 
 si.pwszName  = name;
 
 si.pAuthInfo  = m_bAccess ? &auth : NULL;
 
 si.dwReserved2 = 0;
 
 
 
 IID iid = __uuidof(m_pIRemoteControl);
 
 qi.pIID = &iid;
 
 qi.pItf = NULL;
 
 
 
 do
 
 {
 
 
 
hr = CoCreateInstanceEx(__uuidof(RemoteControl), NULL, CLSCTX_SERVER, &si, 1, &qi);
 
 
 
if(FAILED(hr) || FAILED(qi.hr))
 
 
 
break ;
 
 
 
 
 
m_pIRemoteControl = (IRemoteControl *)qi.pItf;
 
 }while(0);

 

例子3:

  

HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
 
 
 
RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
 
 
 
 COAUTHIDENTITY us;
 
 
 
 us.User      = m_strName.AllocSysString();
 
 us.UserLength   = wcslen(us.User);
 
 us.Password    = m_strPassword.AllocSysString();
 
 us.PasswordLength = wcslen(us.Password);
 
 us.Domain     = m_strDomain.AllocSysString();
 
 us.DomainLength  = wcslen(us.Domain);
 
 us.Flags     = SEC_WINNT_AUTH_IDENTITY_UNICODE;
 
 
 
 COAUTHINFO auth;
 
 
 
 auth.dwAuthnSvc      = RPC_C_AUTHN_WINNT;
 
 auth.dwAuthzSvc      = RPC_C_AUTHZ_NONE;
 
 auth.pwszServerPrincName = NULL;
 
 auth.dwAuthnLevel     = RPC_C_AUTHN_LEVEL_CONNECT;
 
 auth.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
 
 auth.dwCapabilities    = EOAC_NONE;
 
 auth.pAuthIdentityData  = &us;
 
 
 
MULTI_QI MultiQi={&IID_IUnknown,NULL,NOERROR};
 
 COSERVERINFO si;
 
CComBSTR bstr = strComputer;
 
 LPWSTR name  = bstr.m_str;
 
 
 
 si.dwReserved1 = 0;
 
 si.pwszName  = name;
 
 si.pAuthInfo  = m_bAccess ? &auth : NULL;
 
 si.dwReserved2 = 0;
 
 
 
 
 
hr = CoCreateInstanceEx(__uuidof(RemoteControl), NULL, CLSCTX_SERVER, &si, 1, &MultiQi);
 
 
 
 if(FAILED(hr))
 
 {
 
 
 
MessageBox("创建对象实例失败!");
 
 
 
return;
 
 }
 
 
 
 
 
//通过IUnkonwn指针去查询接口指针,返回IAccount指针
 
 pUnknown = (IUnknown *) MultiQi.pItf;
 
hr = pUnknown->QueryInterface(IID_IAccount,(void**)&pAccount);
 
 if(FAILED(hr))
 
 {
 
 
 
MessageBox("没有查找的接口指针!");
 
 
 
return false;
 
 }
 
 pUnknown->Release();

 

http://www.warting.com/program/201110/37053_2.html


---------------------------------------------------------------------------------------
https://www.cnblogs.com/rainbowzc/archive/2009/10/07/1578832.html
偶今天遇到在多线程中调用CoInitializeSecurity 出现非常奇怪的返回值不争确的问题,看了一个前辈的解决方法,如下:
对于编程,我发现自己还很菜,还有很多东西要学习。今天又从我们公司那位牛人那里学了一课,什么叫程序员。有句话说的好:“如果你用了所有的智慧来写代码,那么你就没有足够的能力来调试程序”。这句话对于我们这些比较菜的程序员来说,有点伤感,不过的确是一个事实。作为一个程序员,不仅仅只是能完成功能,而是要很好的完成,更重要的是当功能出现问题时,你要能很好的找到原因并解决它。
下面是今天发生在我身上的一件事情,对于COM的使用我们都很熟悉,最基本的要求是CoInitialize(), CoUninitialize()。而对于CoInitializeSecurity()这个函数可能不是很熟悉,而我今天要讲的也正是这个函数,今天也在它身上花了大半天的时间。下面是这个函数在MSDN中的定义:

Registers security and sets the default security values for the process. This function is called exactly once per process, either explicitly or implicitly. It can be called by the client, server, or both. For legacy applications and other applications that do not explicitly call CoInitializeSecurity, COM calls this function implicitly with values from the registry. If you set processwide security using the registry and then call CoInitializeSecurity, the AppID registry values will be ignored and the CoInitializeSecurity values will be used.
注册并设置进程的默认的安全值。该函数只被每个进程确切的调用一次,以显式或隐式的方式。它可以被客户端,服务器端或是两边都调用。对于非COM的应用程序不应该显式的被调用,但是对于COM应用程序该函数会隐式的从注册表读取参数来调用。如果你使用注册表设置进程级的安全然后调用CoInitializeSecurity, 那么AppID的注册表值会被忽略而使用CoInitializeSecurity值。从这段话中,我们可以知道两个信息,一,CoInitializeSecurity函数用于设置进程安全;二,只能被进程调用一次。第一点是说明用途,而第二点说明用法。很简单,只要在CoInitialize()后面调用一下就可以。但是请记住一定要用下面的方式去验证返回值:

复制代码

HRESULT hr;

hr =
 CoInitialzieSecurity();
if (SUCCEED(hr) || RPC_E_TOO_LATE ==
 hr)
{
    do
 your work;
}
复制代码
因为你如果在开发一个多线程的程序并且多人一起开发,你很可能不知道谁在你之前已经调了一次,而这种问题又很难去定位,特别是你没有别人代码的情况下。下面是四个返回值的说明:
复制代码

This function supports the standard return value E_INVALIDARG, as well as the following: 

S_OK 

Indicates success.

RPC_E_TOO_LATE 

CoInitializeSecurity has already been called.

RPC_E_NO_GOOD_SECURITY_PACKAGES 

asAuthSvc was not NULL, and none of the authentication services in the list could be registered. Check the results saved in asAuthSvc for
 authentication service–specific error codes.

E_OUT_OF_MEMORY 

Out of memory.
复制代码



strncpy_s( dest, _countof(dest), src, count );

并且这句代码不是在所有平台上都有问题。
这个我今天也是在牛人的帮助下才找出来的,而最大地问题是它出现在同一是双核的只是速度不同的w2k3机器上,一台百分百返回S_OK; 而另一台百分百返回RPC_E_TOO_LATE,而且用的同样的代码。所以初步怀疑是多线程时序的问题。不得不承认调试很难^_^。顺便提一句,大家看到这样的代码hang在那里会有什么想法:


---------------------------------------------


https://www.cnblogs.com/killmyday/articles/1395096.html

用C#编写一个进程外的COM组件

我在以前的一篇文章《COM互操作 - 在VB 脚本里面使用.NET类型》里面写过如何在COM客户端程序里面使用.NET组件,但是这些.NET组件都属于进程内的组件,即COM客户端需要将CLR和.NET组件都加载进自身进程的内存空间里面才能使用。上一次在MSDN中文论坛上看到有网友问如何使用C#编写一个进程外的COM组件,由于在使用regasm.exe注册.NET组件的时候,regasm.exe将.NET组件里面发布的COM可见的类型对应CLSID的键值里加上了InprocServer32项,并且设置值为mscoree.dll。这也就是说,.NET的默认实现强制了我们只能在COM里面激活进程内的.NET组件,但是如何用.NET实现进程外的组件呢?难道真的要我们写一个新的COM程序来Host CLR?

答案是否定的,这里是另外一个替代方案,你需要完成下面这些步骤:

1.       在C#代码里面自己实现一个ClassFactory,用来激活我们的Com可见的(Com Visible)类型。

2.       调用COM API CoRegisterClassObject将我们自己的ClassFactory注册在COM库里面,以便监听COM的激活申请。

3.       COM端使用完毕以后,可以通过调用CoRevokeClassObject撤销我们ClassFactory在COM库里面的注册。

4.       如果我们的COM客户端是C++编写的话,并且采用前绑定接口的方式使用我们的Com可见(Com Visible)类型的话,为了能够将接口指针跨越进程边界传输,你还需要将.NET Assembly生成的Tlb文件注册,向COM库注册列集(Marshaling)接口的方法。

NET 代码

TestComVisibleClass.cs

1. using System;

2. using System.Runtime.InteropServices;

3. using System.Windows.Forms;

4.

5. namespace TestComServer

6. {

7.     internal static class ComHelperClass

8.     {

9.         public const string s_IID_ITestComVisible = "C66C0654-49AE-4f2e-8EDA-BD01C8259C20";

10.         public const string s_CLSID_TestComVisibleClass = "12D783BB-33BF-4973-B38B-2A8F0BA926E4";

11.         public static readonly Guid IID_ITestComVisible = new Guid(s_IID_ITestComVisible);

12.         public static readonly Guid CLSID_TestComVisibleClass = new Guid(s_CLSID_TestComVisibleClass);

13.

14.         public const string s_IID_IClassFactory = "00000001-0000-0000-C000-000000000046";

15.         public static readonly Guid IID_IClassFactory = new Guid("00000001-0000-0000-C000-000000000046");

16.         public static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");

17.

18.         [DllImport("ole32.dll")]

19.         public static extern int CoRegisterClassObject(

20.             [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,

21.             [MarshalAs(UnmanagedType.IUnknown)] object pUnk,

22.             uint dwClsContext,

23.             uint flags,

24.             out uint lpdwRegister);

25.

26.         [DllImport("ole32.dll")]

27.         public static extern int CoRevokeClassObject(uint dwRegister);

28.

29.         [DllImport("ole32.dll")]

30.         public static extern int CoInitializeSecurity(

31.          IntPtr securityDescriptor,

32.          Int32 cAuth,

33.          IntPtr asAuthSvc,

34.          IntPtr reserved,

35.          UInt32 AuthLevel,

36.          UInt32 ImpLevel,

37.          IntPtr pAuthList,

38.          UInt32 Capabilities,

39.          IntPtr reserved3);

40.

41.         public const int RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6; // Encrypted DCOM communication

42.         public const int RPC_C_IMP_LEVEL_IDENTIFY = 2; // No impersonation really required

43.         public const int CLSCTX_LOCAL_SERVER = 4;

44.         public const int REGCLS_MULTIPLEUSE = 1;

45.         public const int EOAC_DISABLE_AAA = 0x1000; // Disable Activate-as-activator

46.         public const int EOAC_NO_CUSTOM_MARSHAL = 0x2000; // Disable custom marshalling

47.         public const int EOAC_SECURE_REFS = 0x2;   // Enable secure DCOM references

48.         public const int CLASS_E_NOAGGREGATION = unchecked((int)0x80040110);

49.         public const int E_NOINTERFACE = unchecked((int)0x80004002);

50.

51.     }

52.

53.     [ComVisible(true)]

54.     [Guid(ComHelperClass.s_IID_ITestComVisible)]

55.     public interface ITestComVisible

56.     {

57.         [DispId(1)]

58.         string TestProperty { get; set; }

59.

60.         [DispId(2)]

61.         void TestMethod();

62.     }

63.

64.     [ComVisible(true)]

65.     [Guid(ComHelperClass.s_CLSID_TestComVisibleClass)]

66.     public class TestComVisibleClass : ITestComVisible

67.     {

68.         public string TestProperty { get; set; }

69.

70.         public void TestMethod()

71.         {

72.             MessageBox.Show("Test Method");

73.         }

74.     }

75.

76.     // 类厂

77.     [

78.      ComImport,

79.      InterfaceType(ComInterfaceType.InterfaceIsIUnknown),

80.      Guid(ComHelperClass.s_IID_IClassFactory)

81.     ]

82.     internal interface IClassFactory

83.     {

84.         [PreserveSig]

85.         int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);

86.

87.         [PreserveSig]

88.         int LockServer(bool fLock);

89.     }

90.

91.     internal class ComClassFactory : IClassFactory

92.     {

93.         #region IClassFactory Members

94.

95.         public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)

96.         {

97.             ppvObject = IntPtr.Zero;

98.

99.             if (pUnkOuter != IntPtr.Zero)

100.                 Marshal.ThrowExceptionForHR(ComHelperClass.CLASS_E_NOAGGREGATION);

101.

102.             if (riid == ComHelperClass.IID_ITestComVisible ||

103.                  riid == ComHelperClass.IID_IUnknown)

104.             {

105.                 ppvObject = Marshal.GetComInterfaceForObject(

106.                     new TestComVisibleClass(), typeof(ITestComVisible));

107.             }

108.             else

109.                 Marshal.ThrowExceptionForHR(ComHelperClass.E_NOINTERFACE);

110.

111.             return 0; // S_OK

112.         }

113.

114.         public int LockServer(bool fLock)

115.         {

116.             return 0; // S_OK

117.         }

118.

119.         #endregion

120.     }

121. }

 

Program.cs

1. using System;

2. using System.Windows.Forms;

3. using System.Runtime.InteropServices;

4.

5. namespace TestComServer

6. {

7.     static class Program

8.     {

9.         private static uint m_ComCookie = 0;

10.

11.         /// <summary>

12.         /// The main entry point for the application.

13.         /// </summary>

14.         [STAThread]

15.         static void Main()

16.         {

17.             Application.EnableVisualStyles();

18.             Application.SetCompatibleTextRenderingDefault(false);

19.

20.             RegisterDcomServer();

21.

22.             Application.ApplicationExit += new EventHandler(Application_ApplicationExit);

23.             Application.Run(new Form1());

24.         }

25.

26.         static void Application_ApplicationExit(object sender, EventArgs e)

27.         {

28.             RevokeDcomServer();

29.         }

30.

31.         private static void RegisterDcomServer()

32.         {

33.             // 做一些安全检查,确保只有一些有权限的人才能调用你的C# Dcom组件

34.             // 如果你对安全性不关心的话,可以删除下面的语句

35.             int hr = ComHelperClass.CoInitializeSecurity(

36.                 IntPtr.Zero, // 这里要输入你的安全描述符

37.                 -1,

38.                 IntPtr.Zero,

39.                 IntPtr.Zero,

40.                 ComHelperClass.RPC_C_AUTHN_LEVEL_PKT_PRIVACY,

41.                 ComHelperClass.RPC_C_IMP_LEVEL_IDENTIFY,

42.                 IntPtr.Zero,

43.                 ComHelperClass.EOAC_DISABLE_AAA | ComHelperClass.EOAC_SECURE_REFS | ComHelperClass.EOAC_NO_CUSTOM_MARSHAL,

44.                 IntPtr.Zero);

45.             if (hr != 0)

46.                 Marshal.ThrowExceptionForHR(hr);

47.

48.             hr = ComHelperClass.CoRegisterClassObject(

49.                 ComHelperClass.CLSID_TestComVisibleClass,

50.                 new ComClassFactory(),

51.                 ComHelperClass.CLSCTX_LOCAL_SERVER,

52.                 ComHelperClass.REGCLS_MULTIPLEUSE,

53.                 out m_ComCookie);

54.             if (hr != 0)

55.                 Marshal.ThrowExceptionForHR(hr);

56.         }

57.

58.         private static void RevokeDcomServer()

59.         {

60.             if (m_ComCookie != 0)

61.                 ComHelperClass.CoRevokeClassObject(m_ComCookie);

62.         }

63.     }

64. }

注册表代码

1. Windows Registry Editor Version 5.00

2.

3. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}]

4.

5. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0]

6. @="TestComServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"

7.

8. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0"0]

9.

10. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0"0"win32]

11. @="D:""Workspace""Forum""Test""TestComServer""bin""Debug""TestComServer.tlb"

12.

13. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0"FLAGS]

14. @="0"

15.

16. [HKEY_CLASSES_ROOT"TypeLib"{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"1.0"HELPDIR]

17.

18. [HKEY_CLASSES_ROOT"Interface"{C66C0654-49AE-4f2e-8EDA-BD01C8259C20}]

19.

20. [HKEY_CLASSES_ROOT"Interface"{C66C0654-49AE-4f2e-8EDA-BD01C8259C20}"ProxyStubClsid]

21. @="{00020424-0000-0000-C000-000000000046}"

22.

23. [HKEY_CLASSES_ROOT"Interface"{C66C0654-49AE-4f2e-8EDA-BD01C8259C20}"ProxyStubClsid32]

24. @="{00020424-0000-0000-C000-000000000046}"

25.

26. [HKEY_CLASSES_ROOT"Interface"{C66C0654-49AE-4f2e-8EDA-BD01C8259C20}"TypeLib]

27. "Version"="1.0"

28. @="{9903F14C-12CE-4c99-9986-2EE3D7D588A8}"

29.

30. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}]

31. @="TestComServer.TestComVisibleClass"

32.

33. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}"Implemented Categories]

34.

35. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}"Implemented Categories"{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]

36.

37. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}"LocalServer32]

38. @="D:""Workspace""Forum""Test""TestComServer""bin""Debug""TestComServer.exe"

39.

40. [HKEY_CLASSES_ROOT"CLSID"{12D783BB-33BF-4973-B38B-2A8F0BA926E4}"ProgId]

41. @="TestComServer.TestComVisibleClass"

 

客户端C++代码

1. // TestComClient.cpp : Defines the entry point for the console application.

2. //

3.

4. #include "stdafx.h"

5. #include <windows.h>

6. #import "D:"Workspace"Forum"Test"TestComServer"bin"Debug"TestComServer.tlb" no_namespace, named_guids

7.

8. int _tmain(int argc, _TCHAR* argv[])

9. {

10.    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

11.    assert(SUCCEEDED(hr));

12.

13.    CLSID clsid;

14.    hr = ::CLSIDFromProgIDEx(TEXT("TestComServer.TestComVisibleClass"), &clsid);

15.    assert(SUCCEEDED(hr));

16.   

17.     MULTI_QI mq;

18.    mq.pIID = &IID_ITestComVisible;

19.    mq.pItf = NULL;

20.    mq.hr = S_OK;

21.    hr = ::CoCreateInstanceEx(clsid, NULL, CLSCTX_LOCAL_SERVER, NULL, 1, &mq);

22.    assert(SUCCEEDED(hr));

23.

24.    ITestComVisible *pIt = (ITestComVisible *)mq.pItf;

25.    pIt->TestMethod();

26.    pIt->Release();

27.

28.     CoUninitialize();

29.    return 0;

30. }

 

另外一种客户端,使用VB Script代码

set obj = CreateObject("TestComServer.TestComVisibleClass")  

obj.TestMethod() 

 

 

---------------------------------------------------

 https://blog.csdn.net/u010002704/article/details/39062283

整个进程安全CoInitializeSecurity

整个进程安全CoInitializeSecurity
整个进程安全可以通过CoInitializeSecurity和相应参数设置。这个API内每个使用COM的进程(客户机和服务器)调用一次,如果不是显式调用,则COM用应用程序AppID中的安全设置(如有)或整个机器范围的缺省调用CoInitializeSecurity。CoInitializeSecurity说明如下:
HRESULT CoInitializeSecurity(
PSECURITY_DESCRIPTOR pVoid,
LONG cAuthSvc,
SOLE_AUTHENTICATION_SERVICE * asAuthSvc,
void * pReserved1,
DWORD dwAuthnLevel,
DWORD dwImpLevel,
SOLE_AUTHENTICATION_LIST * pAuthList,
DWORD dwCapabilities,
void * pReserved3
);
说明:每个进程调用CoInitializeSercurity一次,再次调用会失败,并返回RPC_E_TOO_LATE。要实现微调安全控制,可以指定接口范围的安全设置,覆盖CoInitializeSecurity中指定的整个进程范围设置。编写基于DLL的COM应用程序时,不能调用CoInitializeSecurity,因为代理会调用CoInitializeSecurity.
指定访问控制信息
第一个参数pVoid在进程作为COM服务器时传送访问控制信息,它可以取NULL,这时COM生成允许任何人访问的SID。也可以取参数pVoid,它为下列三种类型之一的指针:
1、AppID中的指针,COM查找和使用注册表指定AppID中存放的安全设置。这时CoInitializeSecurity的所有其它参数均忽略。
2、Win32 SID指针,这个Win32 SID中包含DACL(自主访问控制列表)指定谁能访问这个服务器。COM搜索这个DACL中的COM_RIGHTS_EXECUTE权限.由于COM目前不支持监查,因此SACL(系统访问控制列表)应该为NULL.
3、IAcessControl接口的指针。IAccessControl是COM定义的接口,提供COM服务器上的访问控制信息。如果向CoInitializeSecurity传送IAccessControl接口的指针,则COM在需要时,可从任何线程中调用接口的方法,检查用户对服务器上的访问权限。因此,实现IAccessControl时,要保证其为线程安全的。
说明:别把IAccessControl与COMTrader的IAccessControl接口混起来,它们完全无关,IID也不同。
指定验证服务信息
asAuthSvc参数指定验证服务信息数组。COM用这个信息选择安全提供者(例如NTLM或Kerberos),用来输入方法调用;输出调用可以用任何安全提供者。这个数组中的元素个数在cAuthSvc中指定。每个元素的类型为SOLE_AUTHENTICATION_SERVICE(底部认证服务),定义如下:
typedef struct tagSOLE_AUTHENTICATION_SERVICE{
DWORD dwAuthnSvc;
DWORD dwAuthzSvc;
OLECHAR* pPrincipalName;
HRESULT hr;
}SOLE_AUTHENTICATION_SERVICE;
其中:1、dwAuthnSvc指定枚举类型RPC_C_AUTHN_xxx所定义清单中的验证服务,目前只支持两个值:RPC_C_AUTHN_WINNT与RPC_C_AUTHN_GSS_KERBEROS(仅适用于Windows 2000)
2、dwAuthzSvc指定枚举类型RPC_C_AUTHZ_xxx中的授权服务.目前只支持RPC_CAUTHZ_NONE.在Windows 2000中还可以指定RPC_C_AUTHZ_DEFAULT.让COM在安全总括协议中选择授权服务.
3、pPrincipalName指定验证服务使用的用户标识符(主体名).对NTLM和Kerberos,它为NULL,COM用当前用户标识符.
4、hr返回调用注册验证服务的结果.如果CoInitializeSecurity失败,则可以检查hr,确定调用注册验证服务是否失败,为什么.
dwAuthnLevel指定RPC_C_AUTHN_LEVEL_xxx所定义的验证级别之一.同样dwImpLevel指定代理的缺省扮演级别.本章前面曾介绍过,客户机指定扮演级别,因此这个参数只在进程作为客户机时才适用.dwImpLevel应为RPC_C_IMP_LEVEL_XXX定义的级别。
pAuthList包含SOLE_AUTHENTICATION_INFO结构的数组,类似于前面介绍的SOLE_AUTHENTICATION_SERVICE结构。COM在安全总括协商之后选择验证服务时搜索pAuthList中针对所选服务的验证信息。
指定验证功能
CoInitializeSecurity最后一个有趣的参数dwCapabilites指定EOLE_AUTHENTICATION_CAPABILITES枚举类型中的一个或几个标志。这些标志在CoInitializeSecurity中设置其它安全信息。
例如,指定EOAC_SECURE_REFS时COM验证分布式引用次数调用(AddRef和Release),防止服务器对象恶意提前释放。其它标志包括EOAC_STATIC_CLOAKING和EOAC_DYNAMIC_CLOAKING,分别指定静态和动态掩盖。也可以用标志EOAC_APPID和EOAC_ACCESS_CONTROL表示CoInitializeSecurity第一个参数pVoid是AppID或IAccessControl的指针。

 

------------------------------------------------------------------------------------------------------------------------

https://www.icode9.com/content-1-518565.html

远程调试器使我感到怀疑,因为它使我想起了Visual Studio托管过程.另一行是System.Core.dll,该行未出现在VS2013的已加载程序集中.

码:

应用程式

 

<Application x:Class="WPFTestVS2017.App"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            StartupUri="MainWindow.xaml">
</Application>

App.xaml.cs

 

using System;
using System.Runtime.InteropServices;
using System.Windows;

namespace WPFTestVS2017
{
    internal static class NativeMethods
    {
        private enum RpcAuthnLevel
        {
            Default = 0,
            None = 1,
            Connect = 2,
            Call = 3,
            Pkt = 4,
            PktIntegrity = 5,
            PktPrivacy = 6
        }

        private enum RpcImpLevel
        {
            Default = 0,
            Anonymous = 1,
            Identify = 2,
            Impersonate = 3,
            Delegate = 4
        }

        private enum EoAuthnCap
        {
            None = 0x0000,
            MutualAuth = 0x0001,
            StaticCloaking = 0x0020,
            DynamicCloaking = 0x0040,
            AnyAuthority = 0x0080,
            MakeFullSIC = 0x0100,
            Default = 0x0800,
            SecureRefs = 0x0002,
            AccessControl = 0x0004,
            AppID = 0x0008,
            Dynamic = 0x0010,
            RequireFullSIC = 0x0200,
            AutoImpersonate = 0x0400,
            NoCustomMarshal = 0x2000,
            DisableAAA = 0x1000
        }

        [DllImport("Ole32.dll",
            ExactSpelling = true,
            EntryPoint = "CoInitializeSecurity",
            CallingConvention = CallingConvention.StdCall,
            SetLastError = false,
            PreserveSig = false)]
        private static extern void CoInitializeSecurity(
            IntPtr pVoid,
            int cAuthSvc,
            IntPtr asAuthSvc,
            IntPtr pReserved1,
            uint dwAuthnLevel,
            uint dwImpLevel,
            IntPtr pAuthList,
            uint dwCapabilities,
            IntPtr pReserved3);

        public static void Initialize()
        {
            CoInitializeSecurity(IntPtr.Zero,
                -1,
                IntPtr.Zero,
                IntPtr.Zero,
                (uint)RpcAuthnLevel.PktPrivacy,
                (uint)RpcImpLevel.Impersonate,
                IntPtr.Zero,
                (uint)EoAuthnCap.DynamicCloaking,
                IntPtr.Zero);
        }
    }

    public partial class App : Application
    {
        public App()
        {
            NativeMethods.Initialize();
        }
    }
}

MainWindow.xaml

 

<Window x:Class="WPFTestVS2017.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"/>

MainWindow.xaml.cs

 

using System.Windows;

namespace WPFTestVS2017
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

编辑:

我对App.xaml.cs进行了以下修改:

 

public App()
{
    try
    {
        NativeMethods.Initialize();
    }
    catch (Exception e)
    {
        MessageBox.Show(e.ToString());
    }
}

在Visual Studio 2017中进行调试时会显示该消息框,但是在Visual Studio外部运行相同的可执行文件时则不会出现.

解决方法:

您正在与VS2017中的托管调试引擎中的更改作斗争.它与您的猜测无关,我认为Visual Studio Hosting Process选项的删除很可能与之相关.盲目猜测,这是一个黑匣子,如果没有Microsoft调试器团队中的任何人的帮助,很难穿透.

您有几种可能的解决方法,按实用性排序:

>工具>选项>调试>常规,选中“使用托管的兼容模式”复选框.这将新的调试引擎替换为上一次在VS2010中使用的旧调试引擎.您会错过一些最新的调试器功能(新的PDB格式,返回值检查,64位“编辑继续”),几乎没有什么应该阻止您调试WPF应用程序的.
>如果不需要,可以阻止该函数引发异常.将[DllImport]的PreserveSig属性更改为true,将返回类型从void更改为int.它仍然会失败,由负的返回值指示,但是您可以继续调试其余代码.也许您想使用返回值来设置一个全局变量,以用于绕过棘手的COM代码.
>如果不需要,您可以延迟初始化调试引擎,直到CoInitializeSecurity调用之后.附加System.Diagnostics.Debugger.Launch();,并用#if DEBUG包装.现在,您可以按Ctrl F5开始调试,在出现提示时,将VS的运行实例选择为所需的调试器.使用调试>附加到进程是类似的解决方法.

 

 

posted on 2020-12-30 14:27  *(00)*  阅读(990)  评论(0编辑  收藏  举报