Udostępnij za pośrednictwem


Log File Information

You can create log files that record actions for the following operations:

  • Interoperating with native code.

  • Loading programs.

  • Networking.

For information about the registry keys that control logging and how to generate log files, see How to: Create Log Files.

This topic describes the output written to log files for interop and loader logging.

Interop Log Files

The output for interop logging consists of the signatures of the interop function calls as they occur at run time, with any error messages.

The .NET Compact Framework version 3.5 includes enhanced interop logging support, which is described in the "Deep Marshaling" section later in this topic.

Function Signatures

The signatures for both managed-to-native and native-to-managed calls are logged, and include the following types of calls:

  • Platform invoke calls.

  • COM vtable and Dispatch calls.

  • Delegate callbacks.

Interop logging can help you troubleshoot problems when you call or return from an interop function call, such as when an incorrect parameter type is marshaled or when the program terminates unexpectedly.

The output for a function signature entry consists of three lines for each interop call. The first line provides flags that identify the type of function call made, and includes one or more of the following elements:

  • [pinvokeimpl]
    Identifies a managed-to-native call that uses the DllImportAttribute attribute.

  • [Ctor]
    Identifies a constructor for an interop assembly class, generated by the Type Library Importer (Tlbimp.exe).

  • [preservesig]
    Assumes that the managed and native functions have the same signature, with no translation from HRESULT to exception enforced by the runtime.

  • [delegate]
    Indicates that the function is a native-to-managed delegate callback. The delegate acts as a function pointer in native code.

The second line of the interop log file represents the managed signature. For managed-to-native function calls, this line identifies the managed function that calls the native code. For native-to-managed function calls, this line identifies the managed function that is being called from native code.

The third line represents the native signature, as expected by the runtime. This line identifies data types for each parameter and provides information about how the managed object data is marshaled. The runtime assumes that the correct types are specified by the DllImportAttribute attribute or in the COM interface signature definition. Failure to specify the correct types is a common error that can cause unexpected behavior, because the function will be executed with incorrect parameter values.

Note

Specifying an incorrect parameter type may result in a NotSupportedException or a native exception. To help isolate the failure, change parameter types to known supported types or to an IntPtr.

Every type has a default marshaling type. Note that the marshaling behavior of a managed type can be different for COM calls and DllImportAttribute or delegate callback calls. You can use the MarshalAsAttribute attribute to specify a marshaling type other than the default. You must also use the ref keyword to identify any parameter that represents a pointer to a value type or a pointer to a pointer, for a reference type.

The following table shows interop logging of a platform invoke.

Line number and description

Log entry

1 - Type of function call

[pinvokeimpl][preservesig]

2 - Managed signature

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

3 - Native signature

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

The following table shows interop logging of a delegate callback.

Line number and description

Log entry

1 - Type of function call

[preservesig][delegate]

2 - Managed signature

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

3 - Native signature

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

The following table shows interop logging of a native-to-managed COM function call, where the runtime returns a failure HRESULT if a managed exception occurs.

Line number and description

Log entry

1 - Type of function call

(no flags)

2 - Managed signature

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

3 - Native signature

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

Deep Marshaling

The .NET Compact Framework version 3.5 also supports deep marshaling for interop logging. In deep marshaling, information is logged about marshaled objects that are contained in structures or in reference types.

The following log output shows an example of a platform invoke call that uses marshaled objects contained in a structure. The first line of the deep marshaling section specifies why the deep marshaler was called. In this example, it was called to compute the size of the structure. The log shows the data type and the size, in bytes, of each object. The index values (for example, 0004) represent the byte offsets for the specified variables.

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

Error Messages

Some situations and exceptions can cause error messages to be recorded in the log file. These messages can be especially useful when you are investigating issues that involve interoperating with native components and DLLs for which the native source code is not available. You can use error messages to help with the following issues:

  • Native-to-managed function calls.

  • Runtime COM interface calls. An HRESULT error can be returned to native code when a COM interface function that is implemented by the runtime is called. There are several runtime-implemented interfaces (including IUnknown, IDispatch, IConnectionPointContainer, IEnumConnectionPoints, and IConnectionPoint) that native code can call by using a managed object marshaled as a COM interface. When a function call returns an error to native code into one of these interfaces, the runtime prints out an appropriate error message that includes the HRESULT and any additional relevant information.

  • Native code that expects to use functionality that is unsupported, such as IDispatch::GetTypeInfo.

  • Unimplemented interfaces. Native code may receive an E_NOINTERFACE error from IUnknown::QueryInterface where it expects the managed COM object to have implemented an additional interface. In this case, the GUID of the unimplemented interface is also provided.

  • Managed exceptions. These can occur inside the managed function call and cause it to return prematurely. When making a COM call, the runtime converts the exception into a failure HRESULT value, which it returns to native code. However, if a delegate callback or COM call does not expect a HRESULT return value, you cannot make sure that it will become aware of the error, and you may see unexpected behavior as a result. The interop log will contain an error message when an exception occurs during a native-to-managed interop function call. This message will help you identify managed functions that need additional error-handling logic to work well with native code. The following factors can cause a managed exception:

    • Using types in your COM interface definition or DllImportAttribute signature that are not supported by the .NET Compact Framework will cause an exception to occur during the JIT compilation process. There are often alternative options that are acceptable, such as using an IntPtr.

    • When either the actual object cannot be coerced to the type specified in the signature or the object data cannot be converted to the type requested, an exception is thrown at run time when the function is called. This usually occurs when you convert a native object into a managed object.

    • Determining what causes an exception when you create a runtime callable wrapper (RCW) or a COM callable wrapper (CCW) is difficult. The interop log file can help determine the cause of these problems when a detailed error message is not provided with the managed exception.

Differences with the .NET Framework

There are differences between the .NET Compact Framework implementation of COM interoperability and that of the full .NET Framework. The .NET Compact Framework does not support the following:

  • Creating a CCW that contains an interface without a specified GUID.

  • Creating an RCW for a class that inherits from an interop assembly class.

  • Creating a CCW that contains a nongeneric interface with a generic method.

RCWs are usually cleaned up upon finalization, but you can also use the ReleaseComObject or FinalReleaseComObject method to release the RCW that is associated with an object. If you are using these advanced options to manage the lifetime of your objects and you try to use the object after it has been freed to make a native COM call, an exception is thrown and the log file contains an error message about the cause of the exception.

Loader Log Files

Loader log files consist of two sections: a header and a body. The header of the log file contains the following data:

  • Name of the application’s main executable.

  • Process ID, as assigned by the operating system.

  • Date and time the log file was created.

  • Version of the .NET Compact Framework that was used to run the application.

  • Information about the platform on which your application is running.

The body of the log file includes diagnostic information about each assembly as it is loaded by your application. This information can help you find errors encountered by the class loader as your application starts.

The body of the log file contains the following data:

  • Coercion state, which indicates whether your application was run in backward-compatibility mode.

  • Tracing for each assembly load, including where the assembly was loaded from and which version was loaded.

  • Trust level assigned to each module as it is loaded.

  • Any configuration files associated with your application.

  • Failure to find methods, types, assemblies, and modules.

  • Failure to find a native DLL or a function for a platform invoke call.

The following table shows an example of a loader log file. Line numbers are approximate.

Line number and description

Log entry

1 - Process

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

2 - Process ID

Process ID [0x4d9585d2]

3 - Date

Date [2005/02/25]

4 - Time

Time [18:33:14]

5 - .NET Compact Framework version

NETCF [2.0.5035.00]

6 - Platform

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

7–14 - Global assembly cache operations

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 - Compatibility mode (0.0.0.0 indicates not in compatibility mode)

Compatibility mode [0.0.0.0]

16 - Loading module

Loading module [\Windows\GAC_mscorlib_v2_0_0_0_cneutral_1.dll]

17 - Loaded module

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

The last two entries (Loading and Loaded) are logged for each module. They identify the assemblies and their locations. Any errors from loading a module are indicated in the loader log.

Examples of Errors

The two examples in this section show how you can use the loader log file to determine when errors are encountered.

This following example shows the log entries that are written when the loader does not find an assembly.

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]

The following example shows the log entries that are written when the loader does not find a specific type.

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

See Also

Tasks

How to: Create Log Files

How to: Configure Runtime Version

Concepts

.NET Compact Framework How-to Topics

Other Resources

Interoperability in the .NET Compact Framework

Performance and Diagnostics in the .NET Compact Framework