Measuring the Performance of Thunks

This appendix contains the application used to measure the performance of thunks in Chapter 9. You can download this sample from the Source Code Download section of the Apress web site (http www.apress.com). compile with CL c clr TestLibPart2.cpp extern C __declspec(dllexport) class __declspec(dllexport) NativeClassFromDLLWithManagedCode TestLib.cpp build with CL MD LD TestLib.cpp link TestLibManagedParts.obj extern C _declspec(dllexport) class __declspec(dllexport)...

DLLs and Module Constructors

To allow the definition of global variables, even when their constructor executes managed code, mixed-code assemblies provide a module constructor. In the context of application initializations, I have already discussed that the module constructor is the first managed method of an assembly that is executed. For DLLs, the CRT provides a module constructor that can initialize global and static variables. This means there are two ways to initialize global variables via_DllMainCRTStartup (native...

When Is a Reference on the Stack a Root Reference

As mentioned before, it is a simplification to assume that references stored on the stack are always root references. It depends on the current point of execution whether a reference on the stack is considered a root reference or not. At first, it sounds straightforward that all references on the stack are roots, because each function can use the references in its stack frame. In fact, garbage collection would work correctly if all stack variables were considered to be root references until the...

Clipinptr pb bytes[0

char*> (pb), bytes-> Length, key) Instead of an interior pointer, a pinned pointer is used here. Like an interior pointer, a pinned pointer is declared with a template-like syntax. In fact, a pinned pointer is a special kind of interior pointer. It differs from a normal interior pointer because it prevents the referred object from being relocated during garbage collection. To reduce the overhead of pinning, the CLI specifies that pinned pointers can only be defined as local variables....

Dynamic Type Instantiation

In addition to retrieving static information about a type, it is possible to instantiate a type dynamically. A typical usage of this feature is the creation of plug-in objects. Since pluggable applications allow a user to configure new plug-ins, a class implementing a plug-in is not known at compile time. Therefore, the operator gcnew cannot be used to instantiate the object. Dynamic instantiation is also helpful if you want to write generic code. As an example, an MFC document view template is...

Avoiding Naming Conflicts

Chapter 1 summarized the evolution from C to C++ CLI. In all the different phases of this evolution, new names have been introduced for types, functions, templates, variables, and so on. C++ has introduced the concept of namespaces to avoid naming conflicts. The CTS supports namespaces for the same reason. C++ CLI allows you to manage CTS namespaces with language syntax you already know from C++. As a C++ CLI programmer, chances are good that you have to solve naming conflicts between names of...

CRT Initialization in clr DLLs

So far I have discussed only the initialization of the CLR. When DLLs are used, the CRT is at least as important. In contrast to the CLR, the CRT cannot be delay-loaded, because native code may depend on it. For example, in the preceding code, there is a global variable used to hold the interface implementation in Lib3.cpp Interface impl as a global variable InterfaceImpl impl An address to this variable is returned by the exported function GetInterface, which is a native function. Without the...

General Hints Regarding gcroot and autogcroot

There are a few subtle pitfalls that you should know about when using the gcroot and auto_gcroot templates. As discussed already, in many cases you can use a gcroot or auto_gcroot variable as if it were of the wrapped tracking handle type. However, in a few cases, this is not possible. For example, you cannot invoke a default indexed property via a gcroot or auto_gcroot variable. The following code shows an example List lt int gt A ints GetIntListFromSomeWhere Console WriteLine ints 0 legal...

OutOfMemory Exception

Another asynchronous exception that needs attention is System OutOfMemoryException. At first, it seems that an OutOfMemroyException is not an asynchronous exception at all, because according to the official MSDN documentation, an OutOfMemoryException can be thrown by the IL instructions newobj, newarr, and box. It is obvious that a gcnew operation which is translated to the IL instructions newobj or newarr can result in an OutOfMemoryException. Boxing can also cause an OutOfMemoryException...

Custom Startup Logic and Load Time Deadlocks

Imageloader

DllMain in native as well as mixed-code DLLs must be implemented with special care. If you do not follow certain rules, a deadlock can occur while a DLL is being loaded. DllMain is called either directly or indirectly via the DLL's PE entry point. Before calling the PE entry point of a DLL, the operating system's image loader acquires a special critical section with the famous name loader lock. This loader lock can affect the PE entry point itself as well as all functions that are directly or...

Defining Custom Events

Instead of waiting for a key from the console, the FileDumper can do a callback to leave it up to the client what should happen when a full page has been dumped to the console. To do this, the FileDumper component class can provide a PageDumped event. A client can implement the event handler to wait for a keystroke like before, but it would also be an option to display a message box instead. It would even be possible to not handle the event. In this case, one page after the other would be...

Step 2 Creating a Second Precompiled Header

Before starting to write code that uses managed types and constructs, I recommend further preparation steps. If your project has a precompiled header typically called stdafx.pch , you will not be able to use that one for files compiled to managed code. A source file can only use a precompiled header that was created with the same compilation model. Since stdafx.pch was created without any of the clr switches, it can only be used by files compiled to native code. To create a second precompiled...

Assemblies and Metadata

.NET assemblies can be defined as byte streams containing metadata, managed code, and managed resources.1 The format of the byte stream is an extension of the PE file format the file format of DLL and EXE files on Windows NT and later Windows operating systems . In fact, most assemblies are stored as files however, it is also possible to store assemblies in other locations. As an example, assemblies implementing stored procedures can be stored in SQL Server 2005 databases. All managed services...

Step 3 Building and Testing

Your project is now configured to produce a mixed-code assembly. If you build a mixed-code EXE file and the linker property Configuration Properties gt Linker gt General gt Register Output is set to true, your project will fail with the following error message RegAsm error RA0000 Attempt to load an unverifiable executable with fixups IAT with more than 2 sections or a TLS section. Exception from HRESULT 0x80131019 Project error PRJ0050 Failed to register output. Please ensure you have the...

Event Handler Delegates

Before an event can be defined, you must either choose an existing event handler delegate or define a new one. The choice of an event handler delegate depends on the information that should be passed with the callback. If no special information is passed, the delegate System EventHandler can be used public delegate void EventHandler ObjectA sender, EventArgsA ea The type EventArgs does not have instance-specific properties or fields. Therefore, no information is passed with an EventArgs object....

Reducing the Overhead of gcroot and autogcroot

Operator Conversion

Operations based on gcroot or auto_gcroot variables are slower than operations based on a tracking handle. For a detailed description of the overhead that is caused by each gcroot or auto_gcroot instance, as well as for each usage of operator- gt , read the following sidebar, entitled How Is gcroot Implemented To minimize the overhead caused by gcroot and auto_gcroot, there are two optimization strategies as follows Avoid defining gcroot variables whenever possible. There are many situations in...

Interaction Between Managed and Unmanaged Code

Linking native code and managed code into one assembly is only useful if native code can call managed code and vice versa. Here is an example that shows how easy this is. Assume you have a file like this one compile with CL c EHs MD UnmanagedCode.cpp include lt iostream gt using namespace std cout lt lt Hello again from unmanaged code. n lt lt endl If you compile this file with the command mentioned in the comment, you will get an unmanaged object file named UnmanagedCode.obj. Obviously,...

Initialization of Global and Static Variables

The Win32 SDK documentation for DllMain contains another important statement If your DLL is linked with the C runtime library CRT , the entry point provided by the CRT calls the constructors and destructors for global and static C objects. Therefore, these restrictions for DllMain also apply to constructors and destructors and any code that is called from them. This statement is especially important if you implement mixed-code DLLs. Constructors of native types can be executed...

Using C Structures in Managed Code

To properly use native structures and classes in managed code, the C CLI compiler generates managed proxy types. As an example, consider the following function from the Win32 API The return type HWND is defined by the Win32 API as a pointer to a structure named HWND_ The structure HWND_is defined as follows To use the return type HWND of the function GetDesktopWindow in managed code, the C CLI compiler generates a managed proxy type .class private sequential ansi sealed beforefieldinit HWND_...

Load Time Dependencies to Other DLLs

Since assemblies built with clr pure do not have native code, dependent DLLs are loaded differently. This difference is another aspect that must be considered when choosing a compilation model. To get some more information about this difference, consider the following simple application compile with CL clr DependentDLLs.cpp or with CL clr pure DependentDLLs.cpp by including windows.h, the function Beep is declared include lt windows.h gt this line adds kernel32.lib the import lib for...

Mapping SEH Exceptions to NET Exceptions

Win32 SEH exceptions can also be caught as .NET exceptions. In the following code, a managed function main calls a native function f , which throws the SEH exception EXCEPTION_INT_DIVIDE_BY_ZERO. In main, this exception is caught in a catch block that handles exceptions of type System ExceptionA. compile with cl clr ExceptionHandling2.cpp As I will discuss later, pargma managed is not recommended it is only used to show exceptions thrown across managed unmanaged boundaries without using two...

Converting Between Managed and Native Strings

C programmers often have to deal with a variety of string types. From its C roots, an array of char and wchar_t is often treated as a null-terminated string. The C standard library provides the type std string for convenient string handling. Many other libraries also have string implementations. For example, the MFC and ATL use the type CString. Last but not least, COM has its own string definition, the BSTR. When you write interoperability code, you often have to convert between native strings...

Gcnew File SystemEvent Handlerthis Changed FileDumperOnChanged error C3364 invalid argument for delegate constructor

Void OnChanged ObjectA sender, FileSystemEventArgsA e StreamReader sr name Console WriteLine sr.ReadToEnd The event handler must match the requirements of delegate target functions. Unfortunately, ChangedFileDumper OnChanged as well as all member functions of native classes cannot be used as a delegate target. Only global functions and static and non-static methods of managed types can act as delegate targets. To solve this problem, you could create a managed proxy class that provides a target...

Why Should You Use clrpure at

After all these arguments against clr pure, you probably want to ask the question, Why should clr pure be used at all Well, there are two special restrictions of mixed-code assemblies that can be bypassed with clr pure. These restrictions are as follows Mixed-code assemblies must be stored in files. Mixed-code EXE files cannot be loaded dynamically into a process. At first glance, both restrictions sound strange. It seems to be obvious that all assemblies are stored in files. However, it is in...

Components

Visual C , as well as other .NET languages integrated into the Visual Studio .NET IDE, have a sophisticated support for software development based on has-a relationships. Using designers, you can easily add a new field to a class by dragging an item from the Toolbox window which contains a palette of available components and dropping it onto the designer. In this context, Visual Studio and the FCL use the misleading term component. For most developers, a component is a deployable unit of...

DLLs with Managed Entry Points

You can also factor managed code out into a separate DLL so that your existing projects remain completely unmanaged. Figure 1-4 shows a simple example of such a scenario. extern C declspec dllexport voidfO extern C delspec dllimport void fQ C gt LINK.EXE TheApp.obj TheLib.lib Figure 1-4. Separating managed code in DLLs In this simple scenario, TheApp.cpp shall represent your existing project. To extend it with managed features, a new DLL is created from the source file TheLib.cpp. Notice that...

DLL Startup

Often, the majority of the executed code is not written in the application itself, but in various DLLs that the application loads. There are significant differences between application startup and DLL startup. When a mixed-code EXE file is loaded to start an application, the CLR is automatically initialized. In mixed-code DLLs, this can be different. Mixed-code DLLs can be used to delay-load the CLR. This means that the CLR is initialized only when managed code is executed. In addition to that,...

Object File Compatibility

Partial migration obviously depends heavily on source code compatibility. Once existing C source code is compiled to managed code, you can straightforwardly and seamlessly integrate other .NET components and benefit from the many features the .NET Framework offers. However, there is a second pillar that you must understand to use C CLI efficiently. I like to refer to this feature as object file compatibility. Like source code compatibility, the object file compatibility feature of C CLI has an...

The Managed Entry Point

In addition to the PE entry point, which is always mscoree _CorExeMain, an EXE assembly has a managed entry point. In contrast to the PE entry point, the managed entry point is a managed function. After the module constructor has initialized the assembly, the managed entry point is executed. Technically, the managed entry point is a managed function with the IL metadata .entrypoint, as shown in the following sample compileWith ILASM HelloWorld.il .assembly HelloWorld .assembly extern mscorlib...

Referencing Assemblies

Like native libraries and COM servers, assemblies are used to share code. Allowing your C CLI code to use another assembly requires certain steps that differ from the way native libraries and COM servers are made available to your projects. To understand these differences and the reasons behind them, it makes sense to take a step back and look at the way the compiler is enabled to call foreign code in the old ways of code sharing. Using a native library requires including the library's header...

Stack OverflowException

The second asynchronous exception that is important for reliable resource management is System StackOverflowException. The managed stack in the CLR is heavily based on the native stack. Elements pushed on the managed stack exist either on the native stack or in processor registers. A System StackOverflowException occurs as a result of a native stack overflow exception, which is a Win32 SEH exception with the exception code EXCEPTION_STACK_OVERFLOW 0xC00000FD . A stack overflow exception can be...

Handling Exceptions Across Managed Unmanaged Boundaries

When you mix native and managed code, you often face the situation that an exception thrown in native code must be handled in managed code and vice versa. In native code, there are two exception models C exception handling and Win32 SEH. In mixed code, you also have to care about managed exceptions. The exception handling architecture in .NET has remarkable similarities to the Win32 SEH model. This enables managed code to catch native C exceptions as well as SEH exceptions. In addition to these...

Linking the CRT in Mixed Code Assemblies

As discussed in Chapter 7, only the DLL variant of the CRT can be used to produce mixed-code assemblies. In the following sections, I will explain how the compiler and the linker work together to integrate the CRT into an assembly. Depending on the compilation model and CRT variant multithreaded DLL MD or multithreaded debug DLL MDd , the compiler automatically ensures that certain linker options are effective. To achieve this, the compiler uses linker directives. Linker directives can be used...

Internals of the Delegate

The preceding code shows the simple steps necessary to handle events in native types. If you extend existing code with .NET features, you will likely use the delegate map quite often. To understand how the delegate map is implemented, it is necessary to see what these macros expand to. This is shown in the following code Created by delegate_proxy_factory lt ChangedFileDumper gt m_delegate_map_proxy ChangedFileDumper m_p_native_target public pNativeTarget m_p_native_target pNativeTarget void...

Safe Handle

There is a helper class called SafeHandle that allows you to benefit from all the reliability features discussed so far. SafeHandle is an abstract class that can be used to write a wrapper class. The following code shows how you can modify the XYZHandle class from the previous examples build with CL LD clr ManagedWrapper4.cpp MT outputresource ManagedWrapper4.dll 2 continued in next line manifest ManagedWrapper4.dll.manifest pragma comment lib, XYZLib.lib using namespace System using namespace...

Calling Local Native Functions from Managed Code

The first scenario that I will discuss is a call of a native function that is invoked by a managed function from the same assembly. Figure 9-3 shows this scenario. Figure 9-3. Managed code calling local native code Figure 9-3. Managed code calling local native code To call fNative in main, the compiler emits a CALL instruction as if a managed function were called .method assembly static int32 main cil managed There is a managed function in the metadata of the assembly to allow such a CALL...

Calling C Classes Across Managed Unmanaged Boundaries

Developers new to C CLI sometimes confuse managed classes and native classes whose member functions are compiled to managed code. Even when all member functions of a C class are compiled to managed code, the resulting class is still a C type, not a managed type. However, compiling all member functions of a native class to managed code can imply a native-managed transition if native code calls a member function of the native class. The application shown in Figure 9-4 gives an example SampleClass...

Calling Native Functions Imported from DLLs

P Invoke metadata is also generated if you call a native function that is imported from a DLL. The following code shows an example of this scenario compile with CL clr AutoPInvoke.cpp or with CL clr pure AutoPInvoke.cpp by including windows.h, the function Beep is declared include lt windows.h gt this line adds the import lib for kernel32.dll to the list of like inputs pragma comment lib, kernel32.lib When you compile the AutoPInvoke sample shown previously with clr, the resulting P Invoke...

Vtentry 2

Call void Both functions in this ILDASM output have a line starting with .vtentry. This .vtentry instruction is used to define data structures that are needed for method calls from native code to managed code. The term vtentry stands for vtable entry, because these data structures, like vtables for C classes, are arrays of function pointers. In further explanations, I will refer to these data structures as interoperability vtables. For each of the global functions fManaged and fManaged2, a...

Managed Callers Only

The following code shows another special case. Even though the function fManaged has a native calling convention, it is not called by native functions build with cl clr OnlyManagedCallers.cpp using namespace System Console WriteLine fManaged called When the compiler can be sure that a managed function with a native calling convention is called only from managed code, there is no need for interoperability metadata. Therefore, in the preceding code, the compiler and the linker do not emit vtfixup...

Virtual Functions and Double Thunking

The double-thunking problem described in the context of native function pointers can also occur when managed virtual functions are called from managed code. Figure 9-9 shows an example. compiled with clr include SampleClass.h SampleClass p p new SampleClass p- gt F2 compiled with clr include SampleClass.h Figure 9-9. Calling managed virtual functions from native code In this sample, both main and the virtual functions of SampleClass are compiled to managed code. Since native callers could also...

Managed Arrays

Array Visual Basic Diagram

Even though there are various collection classes in the FCL, arrays are often the simplest and most effective option for storing data. Arrays are a special kind of type in the CTS. One of the most special aspects of a managed array type is the fact that it is not created by a compiler at build time, but by the just-in-time JIT compiler at runtime. When the compiler generates some code that uses a managed array, it emits only a description of this array instead of a full type definition. Such a...