日志文件信息

更新:2007 年 11 月

您可以创建日志文件来记录以下操作的执行情况:

  • 与本机代码进行交互。

  • 加载程序。

  • 联网。

有关控制日志记录的注册表项以及如何生成日志文件的信息,请参见如何:创建日志文件

此主题描述为记录互操作和加载程序而写入的日志文件的输出。

互操作日志文件

互操作日志记录的输出包括在运行时进行互操作函数调用时互操作函数调用的签名,还包括任何错误消息。

.NET Compact Framework 3.5 版本提供了增强的互操作日志记录支持,本主题后面的“深层封送”一节对此进行了介绍。

函数签名

记录托管到本机调用和本机到托管调用的签名,还包括以下类型的调用:

  • 平台调用。

  • COM vtable 和调度调用。

  • 委托回调。

互操作日志记录可帮助您解决调用互操作函数时或从互操作函数调用返回时遇到的问题,例如,某一参数不能正常初始化,或者程序意外终止。

对于每个互操作调用,函数签名项的输出都包含三行。第一行提供标识所发出的函数调用类型的标志,而且包含以下一个或多个元素:

  • [pinvokeimpl]
    标识使用 DllImportAttribute 属性的托管到本机调用。

  • [Ctor]
    标识由类型库导入程序 (Tlbimp.exe) 生成的、互操作程序集类的构造函数。

  • [preservesig]
    假定托管和本机函数具有相同的签名,而且运行库不强制从 HRESULT 转换为异常。

  • [delegate]
    指示该函数是本机到托管委托回调。在本机代码中,该委托充当函数指针。

互操作日志文件的第二行表示托管签名。对于托管到本机函数调用,此行标识调用本机代码的托管函数。对于本机到托管函数调用,此行标识当前从本机代码调用的托管函数。

第三行表示本机签名,正如运行库所期望的那样。此行标识每个参数的数据类型,提供有关如何封送托管对象数据的信息。运行库假定正确的类型或者是由 DllImportAttribute 属性指定的,或者在 COM 接口签名定义中。指定正确类型失败是常见错误,它可能导致意外行为,因为函数将使用不正确的参数值执行。

每一种类型都有一个默认封送处理类型。请注意,对于 COM 调用和 DllImportAttribute 或委托回调调用,托管类型的封送处理行为可能互不相同。您可以使用 MarshalAsAttribute 属性指定默认的封送处理类型之外的封送处理类型。还必须使用 ref 关键字标识引用类型的任何参数,这些参数表示指向值类型的指针或表示指向指针的指针。

下表显示平台调用的互操作日志记录。

行号和说明

日志项

1 - 函数调用类型

[pinvokeimpl][preservesig]

2 - 托管签名

bool PlatformDetector::SystemParametersInfo(uint , uint , System.Text.StringBuilder , uint );

3 - 本机签名

BOOLEAN (I1_WINBOOL_VAL) SystemParametersInfo(unsigned int (U4_VAL) , unsigned int (U4_VAL) , WCHAR * (STRINGBUILDER_LPWSTR) , unsigned int (U4_VAL) );

下表显示委托回调的互操作日志记录。

行号和说明

日志项

1 - 函数调用类型

[preservesig][delegate]

2 - 托管签名

int WndProc::Invoke(WndProc , IntPtr , uint , uint , int );

3 - 本机签名

int (I4_VAL) (*)(INT_PTR (I_VAL) , unsigned int (U4_VAL) , unsigned int (U4_VAL) , int (I4_VAL) )

下表显示本机到托管 COM 函数调用的互操作日志记录,其中,在发生托管异常时,运行库会返回失败 HRESULT。

行号和说明

日志项

1 - 函数调用类型

(无标志)

2 - 托管签名

int N2MDualComponentImp.IN2MDualInterface::GetInt(N2MDualComponentImp.IN2MDualInterface This);

3 - 本机签名

HRESULT GetInt(IN2MDualInterface *(INTF_VAL) this, [retval] int (I4_VAL) retval);

深层封送

.NET Compact Framework 3.5 版本还支持用于互操作日志记录的深层封送。在深层封送中,会记录有关结构或引用类型中所包含的封送对象的信息。

下面的日志输出显示一个使用结构中包含的封送对象的平台 invoke 调用示例。深层封送部分的第一行指定调用深层封送拆收器的原因。在此示例中,调用深层封送拆收器是为了计算结构的大小。该日志显示每个对象的数据类型和大小(以字节为单位)。索引值(例如,0004)表示指定变量的字节偏移量。

DEEP MARSHAL: Get size
struct interoplogging.MyStruct
{
0000: Int32 myVar as Int32 (4 bytes)
0004: Int32 myVar2 as Int32 (4 bytes)
0008: String myString as WCHAR[10] (20 bytes)
}
DEEP MARSHAL: Total size = 28 bytes

[pinvokeimpl][preservesig]
void  interoplogging.Form1::MyAPI(interoplogging.MyStruct );
void MyAPI(MyStruct (NONBLIT_VALUETYPE_VAL) );

DEEP MARSHAL: Managed -> Native
struct interoplogging.MyStruct
{
0000: Int32 myVar as Int32 (4 bytes)
0004: Int32 myVar2 as Int32 (4 bytes)
0008: String myString as WCHAR[10] (20 bytes)
}
DEEP MARSHAL: Total size = 28 bytes

错误消息

某些情况和异常可能会导致系统在日志文件中记录错误消息。如果要调查一些问题,这些问题需要与本机组件和 DLL 进行交互,而这些本机组件和 DLL 的源代码不可用,则这些消息便尤其有用。您可以使用错误消息帮助您解决以下问题:

  • 本机到托管函数调用。

  • 运行库 COM 接口调用。当调用运行库实现的 COM 接口函数时,可能会向本机代码返回一条 HRESULT 错误。运行库实现的接口有多种(包括 IUnknownIDispatchIConnectionPointContainerIEnumConnectionPointsIConnectionPoint),本机代码可通过使用一个作为 COM 接口封送的托管对象来调入这些运行库实现的接口。当其中某个接口的函数调用向本机代码返回错误时,运行库会输出一条相应的错误消息,其中包括 HRESULT 和任何其他相关信息。

  • 期望使用不受支持的功能的本机代码,如 IDispatch::GetTypeInfo

  • 未实现的接口。本机代码可能会从 IUnknown::QueryInterface 收到 E_NOINTERFACE 错误,而它期望托管 COM 对象已实现了一个附加接口。这种情况下,还会提供未实现的接口的 GUID。

  • 托管异常。托管异常可发生在托管函数调用内部,会导致托管函数调用过早返回。进行 COM 调用时,运行库会将该异常转换为失败 HRESULT 值,同时会将其返回给本机代码。但是,如果委托回调或 COM 调用不需要 HRESULT 返回值,则无法确保它们将察觉到错误。结果,您可能会看到意外的行为。当本机到托管互操作函数调用期间发生异常时,互操作日志将包含错误消息。此消息将帮助您确定那些需要附加错误处理逻辑才能正确使用本机代码的托管函数。以下因素可能导致托管异常:

    • 在 COM 接口定义或 DllImportAttribute 签名中使用 .NET Compact Framework 不支持的类型会导致 JIT 编译过程中发生异常。通常还存在可接受的其他选项,例如使用 IntPtr

    • 当无法将实际对象强制转换为签名中指定的类型或者对象数据无法转换为所需的类型时,如果调用该函数,则会在运行时引发异常。将本机对象转换为托管对象时通常会发生这种情况。

    • 要确定创建运行时可调用包装 (RCW) 或 COM 可调用包装 (CCW) 时引发异常的原因是非常困难的。互操作日志文件可以帮助您确定未随托管异常提供详细错误消息时出现这些问题的原因。

与 .NET Framework 的差异

.NET Compact Framework 实现的 COM 互操作与 .NET Framework 全功能版实现的 COM 互操作之间存在差异。.NET Compact Framework 不支持:

  • 创建一个包含没有指定 GUID 的接口的 CCW。

  • 为一个继承自互操作程序集类的类创建 RCW。

  • 使用泛型方法创建一个包含非通用接口的 CCW。

通常在终止时会清理 RCW,但是您还可以使用 ReleaseComObjectFinalReleaseComObject 方法来释放与对象关联的 RCW。如果您正在使用这些高级选项管理对象的生存期,并且您尝试在该对象已释放后使用该对象进行本机 COM 调用,则会引发一个异常,日志文件中包含一条关于异常原因的错误消息。

加载程序日志文件

加载程序日志文件包含两个部分:标题和正文。日志文件的标题包含以下数据:

  • 应用程序的主可执行文件的名称。

  • 由操作系统分配的进程 ID。

  • 创建日志文件的日期和时间。

  • 用于运行应用程序的 .NET Compact Framework 的版本。

  • 关于在其上运行应用程序的平台的信息。

日志文件的正文中包括应用程序加载每个程序集时有关每个程序集的诊断信息。这些信息可帮助您找到应用程序启动时类加载程序遇到的错误。

日志文件的正文包含以下数据:

  • 强制状态,它指示是否以向后兼容模式运行您的应用程序。

  • 每个程序集加载的跟踪,包括从何处加载程序集和加载的版本。

  • 加载模块时分配给每个模块的信任级别。

  • 与应用程序相关联的所有配置文件。

  • 找不到方法、类型、程序集和模块。

  • 找不到本机 DLL 或平台 invoke 调用的函数。

下表显示加载程序日志文件的示例。行号是大约值。

行号和说明

日志项

1 - 进程

Process [\Program Files\VW\VW.exe]

2 - 进程 ID

Process ID [0x4d9585d2]

3 - 日期

Date [2005/02/25]

4 - 时间

Time [18:33:14]

5 - .NET Compact Framework 版本

NETCF [2.0.5035.00]

6 - 平台

Platform [Windows CE v4.20.1081 (PocketPC) WinCE4ARMV4 release Beta2 ARMV4 IJITv2]

7–14 - 全局程序集缓存操作

GAC: Updating GAC [0x0]

GAC: Checking .gac files inside [\Windows\]

GAC: Found [Microsoft .NET CF 2.0.GAC] .gac file.

GAC: Done with the file system check. Checking the registry.

GAC: Found [Microsoft .NET CF 2.0.GAC] registry entry.

GAC: Done with the registry check. Let's compare.

GAC: Entry [Microsoft .NET CF 2.0.GAC] is up to date.

GAC: GAC is up to date.

15 - 兼容模式(0.0.0.0 指示未在兼容模式下)

Compatibility mode [0.0.0.0]

16 - 正在加载的模块

Loading module [\Windows\GAC_mscorlib_v2_0_0_0_cneutral_1.dll]

17 - 已加载的模块

Loaded [mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969DB8053D3322AC] from [\Windows\GAC_mscorlib_v2_0_0_0_cneutral_1.dll]

将为每个模块记录最后两项(正在加载的项和已加载的项)。这些项可标识程序集及其位置。加载程序日志中指示了加载模块时出现的任何错误。

错误示例

本节中的两个示例演示如何使用加载程序日志文件确定何时遇到了错误。

下面的示例演示加载程序找不到程序集时写入的日志项。

Loading module [\Program Files\VW\Golf.dll]
Attempt to load [\Program Files\VW\Golf.dll] has failed (err 0x80001000).
Loading module [\Program Files\VW\Golf.exe]
Attempt to load [\Program Files\VW\Golf.exe] has failed (err 0x80001000).
Failed to load [Golf, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]

下面的示例演示加载程序找不到特定类型时写入的日志项。

Missing Type. Type [Cars.Jetta], Assembly [Cars].
Missing Type. Class [Cars.Jetta], Assembly [Cars, Version=5.0.0.0, 
Culture=neutral, PublicKeyToken=null].

请参见

任务

如何:创建日志文件

如何:配置运行库版本

概念

.NET Compact Framework 帮助主题

其他资源

.NET Compact Framework 中的互操作性

.NET Compact Framework 的性能和诊断