VB6 COM+ 调用 .Net COM DLL

6

祝VB6 20岁生日快乐! 尽管支持已于13年前终止,但VB6仍然活着。 请随意嘲笑我,但也请提供您对此问题的任何见解。

我在Citrix farm上有一个VB6 EXE。数据通过COM+从另一台托管VB6 COM+ DLL的服务器获取。COM+包被导出并安装在每台Citrix机器上。

EXE和COM+ DLL都写入旧的logger中。我正在试图摆脱旧的logger,改用Log4Net版本。

我编写了一个.NET COM DLL,其唯一目的是写入日志。

EXE使用.NET DLL进行日志记录(只要我将log.config放在与EXE相同的文件夹中),但是COM+组件不会。我尝试将log.config复制到各种文件夹中,希望这可能是问题所在。我还编写了另一个EXE,仅用于测试.NET DLL,它起作用。

仅仅为了好玩,我尝试在COM+ DLL上使用后期绑定,但也没有帮助。我在Citrix机器上注册了.Net COM DLL和COM服务器。

我还尝试从vb6写入事件日志--两者都失败了。

我确信我的COM+ DLL正在被实现,因为没有任何日志被写入旧的logger。此外,当从我的本地机器运行时,我可以从我的EXE和COM+ DLL获得日志。

以下是一些代码...

这是我的VB.NET COM日志记录代码

Imports System.IO
Imports log4net

<Assembly: Config.XmlConfigurator(ConfigFile:="Log.config", Watch:=True)>

<ComClass(log.ClassId, log.InterfaceId, log.EventsId)>
Public Class log

    Public logger As log4net.ILog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)

#Region "COM GUIDs"
    Public Const ClassId As String = "6fae24c7-f86b-4fab-8b49-1d441de5bd18"
    Public Const InterfaceId As String = "223a30c4-ec1e-45a6-82d3-d23cd4c933f9"
    Public Const EventsId As String = "2087d93e-dd38-4cd1-b757-44dee322a8e3"
    Public Property TraceExtension As Object
#End Region

    Public Sub New()
        MyBase.New()

        WriteEvent("New Start")

        If Not log4net.LogManager.GetRepository().Configured Then
            Dim configFileDirectory = (New DirectoryInfo(TraceExtension.AssemblyDirectory)).Parent
            Dim configFile = New FileInfo(configFileDirectory.FullName + "\log.config")

            If configFile.Exists Then
                WriteEvent("New Config Exists")
                log4net.Config.XmlConfigurator.Configure(configFile)
            Else
                WriteEvent(String.Format("The configuration file {0} does not exist", configFile))
                Throw New FileLoadException(String.Format("The configuration file {0} does not exist", configFile))
            End If
        End If

        WriteEvent("New End")

    End Sub

    Private Sub WriteEvent(msg As String, Optional id As Integer = 11)
        Using eventLog As New EventLog("Application")
            eventLog.Source = "CSS"
            eventLog.WriteEntry(msg, EventLogEntryType.Error, id)
        End Using
    End Sub

    Public Sub Debug(msg As String)
        logger.Debug(msg)
    End Sub
    Public Sub Info(msg As String)
        logger.Info(msg)
    End Sub
    Public Sub Warn(msg As String)
        logger.Warn(msg)
    End Sub
    Public Sub Err(msg As String)
        logger.Error(msg)
    End Sub
    Public Sub Fatal(msg As String)
        logger.Fatal(msg)
    End Sub
End Class

这里是从EXE和COM+ DLL调用的VB6代码。

Public Sub AppLog(ByVal LogType As Integer, ByVal Data As String)
10  On Error Resume Next
20  Dim klog As New KerryLog.Log
30  Data = "EXE > " + Data ' the COM+ DLL has a Prefix of COM instead of EXE

    Select Case LogType
            Case LogTypeNone: klog.Info Data
            Case LogTypeAppStart: klog.Info Data
            Case LogTypeAppEnd: klog.Info Data
            Case LogTypeInfo: klog.Info Data
            Case LogTypeVerbose: klog.Debug Data
            Case LogTypeWarning: klog.Warn Data
            Case LogTypeHandledException: klog.Err Data
            Case LogTypeUnhandledException: klog.Fatal Data
            Case LogTypeAutomated: klog.Info Data
            Case LogTypeUsage: klog.Debug Data
    End Select

40  Set klog = Nothing

这是我使用的第一种写入事件日志的方法:

App.StartLogging "", vbLogToNT
App.LogEvent "this is the error message", vbLogEventTypeError

下面介绍写入事件日志的第二种方法

Private Declare Function ReportEvent _
    Lib "advapi32.dll" Alias "ReportEventA" ( _
    ByVal hEventLog As Long, _
    ByVal wType As Integer, _
    ByVal wCategory As Integer, _
    ByVal dwEventID As Long, _
    ByVal lpUserSid As Long, _
    ByVal wNumStrings As Integer, _
    ByVal dwDataSize As Long, _
    plpStrings As String, _
    lpRawData As Long) As Long

Private Declare Function RegisterEventSource _
    Lib "advapi32.dll" Alias "RegisterEventSourceA" ( _
    ByVal lpUNCServerName As String, _
    ByVal lpSourceName As String) As Long

Public Sub LogThis(nErrNo As Long, sLogMsg As String, EventType As LogEventTypeConstants)
    Dim hEvent As Log

    hEvent = RegisterEventSource("", "CSS")
    Call ReportEvent(hEvent, EventType, 0, nErrNo, 0, 1, Len(sLogMsg), sLogMsg, 0)
End Sub

事件日志只是一个侧记——我正在尝试写入某个东西,以便进行调试。我猜下一步将是尝试写入文本文件。

也许这是一个权限问题?Citrix和COM+服务器都是Win Server 2008 R2标准版SP1/64位。

有什么想法吗?


2
我不确定这是否有帮助,但当log4net与COM+无法正常工作时,他们谈论某种存储库配置:https://dev59.com/XnNA5IYBdhLWcg3wQ7m4,https://weblogs.asp.net/george_v_reilly/Using-Log4Net-from-a-COM_2B00_-Application - scor4er
我没有看到任何原因说明它不能工作,但很多事情可能会失败(安全性、位数、文件路径等)。如果不重现代码很难说。为了调试和测试,建议您使用 OutputDebugString 或更好的 ETW。我编写了一个名为 TraceSpy 的工具,可以追踪 ETW(ETW 的好处是它们可跨越 Windows 工作站、Web 等),并提供了 ETW 的 VBA 支持代码(在 vba 目录中)(正如您所知,VBA 是 ole' VB6 的近亲)https://github.com/smourier/TraceSpy - Simon Mourier
COM+ 的托管进程是什么,这个二进制文件存放在哪里?也许这就是配置文件被查找的位置? - tcarvin
1个回答

0

COM+组件将其当前工作文件夹设置在C:\ Windows \ System32中,因此它很可能会在COM +中出现路径访问错误或文件写入错误,直到您为COM +日志记录的配置设置绝对路径。

我的方法是使用独立于日志机制并且不受现有日志解决方案限制的ActiveX“中间件”代理来访问外部进程COM +服务器进行日志记录。对于外部进程COM +激活,我编写了一个小模块来直接调用CoCreateInstance,因为漂亮而干净的VB6类似方法只使用进程内COM +激活,并且没有选择外部进程激活的方法。

通过这种架构,找到适当的日志记录机制和错误处理的所有职责都转移到了目标VB6项目的侧面VB6 ActiveX上,后者使用与现有COM +服务器(外部进程,记住吗?)的连接或回退到ActiveX中的默认记录器实现,因此任何代码似乎都不需要编写任何日志记录错误处理代码或编写除'New ILoggerFactory.CreateLogger'之外的其他内容。因为ActiveX组件本身具有用于日志记录支持的COM +接口实现。

在我的COM+服务器(.NET 5应用程序)运行之前,我可以使用NLog格式(包括扩展DB等)来获取额外的高级结构化日志记录。同样的方式,您可以使用自己的log4net .NET可执行文件并进行配置,以将其用作COM+日志记录接口的默认实现,因此,只要它对系统具有有限的权限,在最坏的情况下,您可以将默认的记录器实现作为EventLog记录器嵌入您的ActiveX库中,这样就不会出现文件/访问异常,从而保持主COM+服务器记录器的安全可写位置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接