.NET A Case Study for Interoperability What is .NET ? “[…] like the Solar System, .NET is huge. And it’s complex. And it’s filled with black holes and other things that don’t always make sense. Yet it turns out to be a fantastic system in which to develop software applications.” [Tim Patrick, An Introduction to .NET for Beginners] • A set of technologies for developing and using components to create: – Windows Applications – Web Forms – Web Services • Supports the software lifecycle – – – – Development Debugging Deployment Maintenance This course’s goal with .NET: a case study for language interoperability Microsoft .NET Framework Architecture Overview • .NET: new runtime environment and comprehensive base class library (FCL – Framework Class Library) .NET-aware programming languages (C#, J#, VB, C++) Common Language Specification Base Class Library Common Language Runtime Operating System Base Class Library Overwiev • The .NET framework class library supplies a standard set of classes, interfaces, and structures for any language targeting .NET CLR => simplifies multi-language development, effectively providing a common language API • Organized by namespaces. • A namespace consists of many classes and sub-namespaces. • General namespaces: the root namespace in the class library is the System namespace, which contains many basic classes such as Object, Console, and contains general sub-Namespaces such as IO, Net, Remoting, etc. • Application specific namespaces: define types that are used for building specific application types: System.Web.Services, System.Web.UI, System.Windows.Forms • In order to use classes in a namespace a directive as using <namespace> or import <namespace> must be included at the beginning of code. Some of the General Namespaces from the Class Library Namespace Description System All the basic types used by every application System.Collections Types for managing collections of objects; includes the popular collection types, such as stacks, queues, hash tables, and so on System.IO Types for doing stream I/O, walking directories and files System.NET Types for network communication System.Reflection Types that allow the inspection of metadata and late binding to types and their members System.Runtime.Remoting Types that allow for types to be accessed remotely System.Runtime.Serialization Types that allow for instances of objects to be persisted and regenerated from a Stream System.Security Types used for protecting data and resources System.Threading Types used for asynchronous operations and synchronizing access to resources Example: Using FCL in C# // compile with csc ex1.cs using System; using System.Collections; public class Program { public static void Main() { ArrayList myAL = new ArrayList(); myAL.Add( "one" ); myAL.Add( "two" ); myAL.Add( "three" ); Console.WriteLine( "myAL has {0} elements.", myAL.Count ); } } Example: Using FCL in J# //compile with vjc ex1.jsl import System.*; import System.Collections.*; public class Program { public static void main(String[] args) { ArrayList myAL = new ArrayList(); myAL.Add("one"); myAL.Add("two"); myAL.Add("three"); Console.WriteLine("myAL has {0} elements.", (Int32) myAL.get_Count()); } } Example: Using FCL in CPP //compile with cl /clr ex1.cpp using namespace System; using namespace System::Collections; int main() { ArrayList myAL = gcnew ArrayList(); myAL.Add("one"); myAL.Add("two"); myAL.Add("three"); Console::WriteLine( "{0}",myAL.Count ); } This courses goals with .NET • A case study for interoperability: How does .NET Architecture support Interoperability Interoperability problem • Problem: Developer wants to write different modules of an application in different languages • Other solutions: – Representation standards & Communication protocols: address the issues of passing data types between different machines. Data can be passed by inter process communication mechanisms – Using a language neutral Interface Description Language CORBA. Objects can call methods across language and process boundaries. – Binary standard: interoperability is assured at binary level – standardized calling model - COM – Disadvantages: • Permits only simple communication, no implementation inheritance between classes written in different languages • Developer has to do special actions for interop (interface descriptions) Characteristics of the .NET solution for interoperability • Consists of: – – – – • .NET managed code benefits from the runtime's support for language interoperability in the following ways: – – • Common Type System and Common Language Specification: defines common types and common features that have to be provided by all participating languages Metadata: defines an uniform mechanism for storing and retrieving type information: Compilers store type information as metadata, and the common language runtime uses this information to provide services during execution; MSIL: Intermediate Language: all code is compiled to MSIL, which is a high-level machine code executed by the runtime CLR: runtime can manage the execution of multilanguage applications because all type information is stored and retrieved in the same way, regardless of the language the code was written in. Types can inherit implementation from other types, pass objects as arguments to another type's methods, and call methods defined on other types, regardless of the language the types are implemented in. Debuggers, profilers, or other tools are required to understand only one environment — the Microsoft intermediate language (MSIL) and metadata for the common language runtime—and they can support any programming language that targets the runtime. Bottom line: What about interoperability of .NET managed code with unmanaged code ? [MSDN: .NET Framework Developer's Guide: Language Interoperability Overview ] Outline • • • • • • Common Language Runtime Managed Modules and Metadata Assemblies The Common Type System The Common Language Specification Examples of supported Multi-language interoperability • Interoperability with Unmanaged Code CLR • A runtime usable by different programming languages – CLR executes MSIL - it has no idea which language was used for the source code • The features of the CLR are available to any and all languages that target it • Features supported by CLR: – Just-in-time (JIT) compilers • JIT compiles intermediary language (MSIL) into native code – – – – – – Common Type System Garbage collector Permission and policy-based security Exceptions Threading Reflection Managed modules • • Compilers that target the CLR produce Managed modules Managed module: a standard Windows portable executable (PE) file that requires the CLR to execute – – End-users must have the CLR installed on their machine in order to execute any managed modules A managed module consists of MSIL code and metadata [Richter] – fig.1.1 Parts of a Managed module PE header The standard Windows PE file header. Indicates the type of file: GUI-EXE, CUI-EXE, or DLL. Has a timestamp indicating when the file was built. For modules that contain only IL code, the bulk of the information in the PE header is ignored. For modules that contain native CPU code, this header contains information about the native CPU code. CLR header Contains the information (interpreted by the CLR and utilities) that makes this a managed module. The header includes the version of the CLR required, some flags, the MethodDef metadata token of the managed module’s entry point method (Main method), and the location/size of the module’s metadata, resources, strong name,etc. Metadata Every managed module contains metadata tables. There are two main types of tables: tables that describe the types and members defined in your source code and tables that describe the types and members referenced by your source code. Conceptually metadata are a superset of IDL’s, but, unlike them, are embedded with the code. IL code IL (Intermediate Language) Code that the compiler produced as it compiled the source code. The CLR later compiles the IL into native CPU instructions IL is a CPU-independent machine language. IL is much higher level than most CPU machine languages: IL understands object types and has instructions that create and initialize objects, call virtual methods on objects, and manipulate array elements directly. [Richter] – Table 1.1 Uses of metadata • Metadata makes a module self-describing • IntelliSense parses metadata to tell you what methods a type offers and what parameters that method expects. • The CLR’s code verification process uses metadata to ensure that your code performs only “safe” operations. • Metadata allows an object’s fields to be serialized into a memory block, remoted to another machine, and then deserialized, re-creating the object and its state on the remote machine. • Metadata allows the garbage collector to track the lifetime of objects. For any object, the garbage collector can determine the type of the object and, from the metadata, know which fields within that object refer to other objects. Assemblies • An assembly is a logical grouping of one or more managed modules and resource files. – Single-file or multifile assemblies • An assembly is the logical unit of deployment, and the smallest unit of reuse, security, and versioning – CLR works with assemblies rather than managed modules • Each Assembly is defined by a Manifest: – Metadata that describes the assembly (version, contained files, resource files, dependencies, etc.) Assemblies [Richter] – fig.1.2 Assemblies Manifest Contents • Manifest contains: – Identity information • Name, version number, culture, strong name – List of files in the assembly – Map of assembly types to files – Dependencies • Other assemblies used by this assembly – Exported types – Security permissions needed to run Module Metadata Contents • Each module metadata contains: – Description of types • Name, visibility, base class, interfaces implemented • Members (methods, fields, properties, events, nested types) – Custom attributes • User-defined • Compiler-defined • Framework-defined How to create an assembly • Single-file assemblies: created with usual compiler options • The C# (csc) and J# (vjc) compilers produce an assembly when you specify any of the following command-line switches: /t[arget]:exe, /t[arget]:winexe, or /t[arget]:library. All these switches cause the compiler to generate a single PE file that contains the manifest metadata tables. The resulting file is either a CUI executable, a GUI executable, or a DLL, respectively. • The C++ compiler can produce managed or unmanaged code. In order to produce managed code (an assembly) use the /CLR switch Example // File Prog1.cs using System; public class Program { public static void Main() { Console.WriteLine( "Hi" ); } } • • • • • Compile with: csc /t:exe Prog1.cs Produces file Prog1.exe, that is a standard PE file of type Windows console application Prog1.exe is a single-file assembly (contains only one module) You can (and usually do so) generate a single-file assembly from multiple files of source-code: – csc /target:library /out:lib.dll *.cs Multifile assemblies refer to assemblies consisting of several IL modules (nothing to do with the number of source files !) => later IL Disassembler: ILDASM.EXE • Allows you to inspect the metadata and disassembled IL code from an assembly • Example: ILDASM on Prog1.exe Example: MSIL code for Program::Main Example: Metadata for Prog1.exe • TypeDef: – Specifies the types defined here: Program – Type Program has 2 methods: Main and .ctor • TypeRef: – Specifies the types referenced by the module - these can be implemented in the same module (TypeRef), in another module (ModuleRef) of the same assembly or in another assembly (AssemblyRef) Example: Manifest for Prog1.exe Multifile assemblies • [Richter] identifies 3 reasons to use multifile assemblies: – You can partition your types among separate files, allowing for files to be incrementally downloaded. Partitioning the types into separate files also allows for partial or piecemeal packaging and deployment for “shrinkwrapped” scenarios. – You can add resource or data files to your assembly. For example, you could have a type that calculates some insurance information. This type might require access to some actuarial tables to make its computations. Instead of embedding the actuarial tables in your source code, you could use a tool (such as the assembly linker (AL.exe), discussed later) so that the data file is considered to be part of the assembly. By the way, this data file can be in any format – You can create assemblies consisting of types implemented in different programming languages. When you compile C# source code, the compiler produces a module. When you compile Visual Basic source code, the compiler produces a separate module. You can implement some types in C#, some types in Visual Basic, and other types in other languages. You can then use a tool to combine all these modules into a single assembly. To developers using the assembly, the assembly just contains a bunch of types; developers won’t even know that different programming languages were used. How to create a multifile assembly • • Important: The Visual Studio .NET IDE doesn’t natively support the ability for you to create multifile assemblies. If you want to create multifile assemblies, you must resort to using command-line tools. Generating a module: – C# and J# compilers: /t[arget]:module – C++ compiler: /CLR:NOASSEMBLY /LD – This switch tells the compiler to produce a PE file that doesn’t contain the manifest metadata tables. The PE file produced is always a DLL PE file, and this file must be added to an assembly before the types within it can be accessed • • Adding a module to an assembly: C# compiler supports the /addmodule:module switch Creating an assembly from several modules: Assembly linker tool AL: – al /out:assembly /t:type netmodule1 netmodule2 … • Adding a resource file to an assembly: – al /embed [resource] – al /link [resource] • Example: – we have 2 source code files: RarelyUsedTypes.cs and FrecventlyUsedTypes.cs and want to build a 2-modules assembly Multifile Assembly Example (v1) • Generating a multifile assembly consisting of 2 managed modules, one with a manifest: csc /t:module RUT.cs csc /out:JeffTypes.dll /t:library /addmodule:RUT.netmodule FUT.cs [Richter – Fig. 2-1] Multifile Assembly Example (v2) • Generating a multifile assembly consisting of 3 managed modules, one with a manifest: csc /t:module RUT.cs csc /t:module FUT.cs al /out:JeffTypes.dll /t:library FUT.netmodule RUT.netmodule [Richter – Fig. 2-3] Assembly Version Resource Information • When AL or a compiler produces a PE file assembly, it also embeds a default standard Win32 Version resource • It can be examined by viewing the file’s properties • => Example: Version tab of the Prog1.exe Properties dialog box Setting Version Information • The version resource fields can be set using custom attributes applied at the assembly level in the source code using System.Reflection; [assembly:AssemblyCompany("Trei Biti SRL")] [assembly:AssemblyCopyright("Copyright (c) 2008 Programatorul Iscusit")] [assembly:AssemblyProduct("Program exemplu curs PASSC")] [assembly:AssemblyInformationalVersion("2.0.0.0")] [assembly:AssemblyFileVersion("1.0.0.0")] [assembly:AssemblyVersion("3.0.0.0")] Deployment of Assemblies • Two kinds of assemblies: – Privately deployed assemblies: • Are used by a single application • Reside in the application directory (or in a place explicitly configured in the application) • Can be simply installed (copied) and uninstalled – Shared assemblies: • Are accessible to multiple applications • Located at c:\winnt\assembly • Add assemblies by – Installer program – gacutil.exe • Shared Assemblies must have a “strong name”: – Guarantees name uniqueness (two different producers could write a library with the same name) – Protect version lineage » No one else can create a new version of your assembly – a strongly named assembly is signed with a publisher’s public/private key pair that uniquely identifies the assembly’s publisher. Conclusion on Assemblies • An assembly is a unit of reuse, versioning, and security. • It allows you to partition your types and resources into separate files so that you and consumers of your assembly get to determine which files to package together and deploy. • Once the CLR loads the file containing the manifest, it can determine which of the assembly’s other files contain the types and resources that the application is referencing. • Assemblies are self-describing: Anyone consuming the assembly is required to know only the name of the file containing the manifest; the file partitioning is then abstracted away from the consumer and may change in the future without breaking the application’s behavior. • An application consists of one or more assemblies: this assures the needed technical infrastructure (metadata, MSIL) for language interoperability – Example: – MyClassInCsharp – MyProgramInJsharp Example: J# program uses C# class // compile with // csc /t:library MyClassInCsharp.cs // produces MyClassInCsharp.dll C# //compile with // vjc /r:MyClassInCsharp.dll MyProgramInJsharp.jsl J# Import System.*; using System; public class MyClassInCsharp { public void doSomething(int x) { Console.WriteLine("doSomething on {0}", x); } } public class MyClassInJsharp extends MyClassInCsharp { public void doSomethingSpecial() { doSomething(999); } } public class MyProgramInJsharp { public static void main(String[] args) { MyClassInCsharp c=new MyClassInCsharp(); c.doSomething(5); MyClassInJsharp j=new MyClassInJsharp(); j.doSomethingSpecial(); } } Interoperability Cross Language • Common Type System (CTS) – • Common Language Specification (CLS) – • Defines what language features are supported by the CLR: superset of the data types used by most modern programming languages Defines what language features are essential to be implemented by languages that want to produce code guaranteed to interoperate with other languages. A subset of CTS that allows code written in different languages to interoperate. What languages? – – Microsoft: C#, C++, Visual Basic, J#, JScript Third-Party: Cobol, Eiffel, Smalltalk, Scheme, Oberon, Haskell, Python, Perl, … [Richter] – fig.1.6 Common Type System • • CTS is a formal specification that describes how types are defined and how they behave. CTS establishes several rules regarding following issues: – – – – – • • • What kind of members can a type contain Type visibility and access to the members of a type. Type inheritance, virtual functions Object lifetime All types must (ultimately) inherit from a predefined type: System.Object. This Object is the root of all other types and therefore guarantees every type instance has a minimum set of behaviors. These rules have been designed to accommodate the semantics expressible in modern-day programming languages. In fact, developers don’t need to learn the CTS rules per se since the language they choose will expose its own language syntax and type rules and will map the language-specific syntax into the “language” of the CLR when it emits the managed module. CTS rules are more important for language and compiler developers CTS: Type members • The CTS specification states that a type can contain zero or more members, that can be: – Field A data variable that is part of the object’s state. Fields are identified by their name and type. – Method A function that performs an operation on the object, often changing the object’s state. Methods have a name, a signature, and modifiers. The signature specifies the calling convention, the number of parameters (and their sequence), the types of the parameters, and the type of value returned by the method. – Property To the caller, this member looks like a field. But to the type implementer, looks like a method (or two). Properties allow an implementer to validate input parameters and object state before accessing the value and/or calculate a value only when necessary. They also allow a user of the type to have simplified syntax. Finally, properties allow you to create read-only or write-only “fields.” – Event An event allows a notification mechanism between an object and other interested objects. For example, a button could offer an event that notifies other objects when the button is clicked CTS: Type visibility and access to members • • • The CTS also specifies the rules for type visibility and for access to the members of a type. The CTS establishes the rules by which assemblies form a boundary of visibility for a type, and the CLR enforces the visibility rules. The valid options for controlling access to a method or a field: – Private The method is callable only by other methods in the same class type. – Family The method is callable by derived types, regardless of whether they are within the same assembly. Note that many languages (such as C++ and C#) refer to family as protected. – Family and assembly The method is callable by derived types, but only if the derived type is defined in the same assembly. Many languages (such as C# and Visual Basic) don’t offer this access control. Of course, IL Assembly language makes it available. – Assembly The method is callable by any code in the same assembly. Many languages refer to assembly as internal. – Family or assembly The method is callable by derived types in any assembly. The method is also callable by any types in the same assembly. C# refers to family or assembly as protected internal. – Public The method is callable by any code in any assembly. CTS: System.Object • Here’s another CTS rule: All types must ultimately inherit from a predefined type: System.Object. • System.Object is the root of all other types and therefore guarantees every type instance has a minimum set of behaviors. • Specifically, the System.Object type allows you to do the following: – – – – – Compare two instances for equality Obtain a hash code for the instance Query the true type of an instance Perform a shallow (bitwise) copy of the instance Obtain a string representation of the instance’s object’s current state Common Language Specification • CLS is a subset of CTS • A component that uses only CLS features in the API that it exposes to other code (including derived classes) is guaranteed to be accessible from any programming language that supports the CLS. • Components that adhere to the CLS rules and use only the features included in the CLS are said to be CLS-compliant components. • Why do we need CLS, besides CTS ? – CTS is too large to be integrally supported by all languages: the CLS was designed to be large enough to include the language constructs that are commonly needed by developers, yet small enough that most languages are able to support it. – In addition, any language construct that makes it impossible to rapidly verify the type safety of code was excluded from the CLS so that all CLS-compliant languages can produce verifiable code if they choose to do so. Some of the CLS Rules • CLS rules apply only to those parts of a type that are exposed outside the defining assembly. • For two identifiers to be considered distinct, they must differ by more than just their case. • The .NET Framework class library includes types that correspond to the primitive data types that compilers use. Of these types, the following are CLS-compliant: Byte, Int16, Int32, Int64, Single, Double, Boolean, Char, Decimal, IntPtr, and String. • Methods are allowed to be overloaded only based on the number and types of their parameters. Operator overloading is not in the CLS. • The only calling convention supported by the CLS is the standard managed calling convention; variable length argument lists are not allowed CLSCompliant Attribute • Assemblies explicitly indicate CLS compliance with CLSCompliantAttribute. • [assembly:CLSCompliant(true)] • This setting will generate warnings at compilation if the assembly contains non-CLS-compliant code Example: J# program uses C# class // compile with // csc /t:library MyClassInCsharp.cs // produces MyClassInCsharp.dll C# //compile with // vjc /r:MyClassInCsharp.dll MyProgramInJsharp.jsl J# [assembly: CLSCompliant(true)]; Import System.*; using System; public class MyClassInCsharp { public void doSomething(int x) { Console.WriteLine("doSomething on {0}", x); } } A module that will be consumed in another language must be CLSCompliant. The consumer module doesn’t has to be CLSCompliant. public class MyClassInJsharp extends MyClassInCsharp { public void doSomethingSpecial() { doSomething(999); } } public class MyProgramInJsharp { public static void main(String[] args) { MyClassInCsharp c=new MyClassInCsharp(); c.doSomething(5); MyClassInJsharp j=new MyClassInJsharp(); j.doSomethingSpecial(); } } Example: J# program uses C# class // compile with // csc /t:library MyClassInCsharp.cs // produces MyClassInCsharp.dll //compile with // vjc /r:MyClassInCsharp.dll MyProgramInJsharp.jsl C# [assembly: CLSCompliant(true)]; using System; public class MyClassInCsharp { public void doSomething(int x) { Console.WriteLine("doSomething on {0}", x); } } J# Import System.*; public class MyClassInJsharp extends MyClassInCsharp { public void doSomethingSpecial() { doSomething(999); } public void dosomethingspecial() { doSomething(111); } } Type MyClassInJsharp is now NonCLSCompliant because it has 2 members with the same name and signature (name case doesen’t matter). Adding Non-CLSCompliant code to the consumer module is OK ! MyProgramInJsharp works public class MyProgramInJsharp { public static void main(String[] args) { MyClassInCsharp c=new MyClassInCsharp(); c.doSomething(5); MyClassInJsharp j=new MyClassInJsharp(); j.doSomethingSpecial(); } } Example: Defining a CLS-Compliant class in C++ // compile with // cl /CLR:safe /LD MyClassInCpp.cpp // produces MyClassInCpp.dll C++ using namespace System; [assembly: CLSCompliant(true)]; public ref class MyClassInCpp { public: void doSomething (int x); }; void MyClassInCpp::doSomething (int x) { Console::WriteLine("CPP: do Something on {0}", x); } The Visual C compiler can generate managed or native code (default) A CLSCompliant module in C++ A managed class (C++ can support both managed and unmanaged types) Example: J# program uses C# and C++ classes MyClassInCpp.dll C++ //compile with // vjc /r:MyClassInCsharp.dll // /r:MyClassInCpp.dll // MyProgramInJsharp.jsl J# Import System.*; MyClassInCsharp.dll C# public class MyClassInJsharp extends MyClassInCsharp { public void doSomethingSpecial() { doSomething(999); } } public class MyProgramInJsharp { public static void main(String[] args) { MyClassInCsharp c=new MyClassInCsharp(); c.doSomething(5); MyClassInJsharp j=new MyClassInJsharp(); j.doSomethingSpecial(); MyClassInCpp cpp=new MyClassInCpp(); cpp.doSomething(77); } } Example: C++ program uses C# and C++ classes MyClassInCpp.dll C++ // compile with // cl /CLR MyProgramInCpp.cpp #using <MyClassInCpp.dll> #using <MyClassInCsharp.dll> MyClassInCsharp.dll C# public ref class MySpecial:MyClassInCsharp { public: void doSpecial(); }; void MySpecial::doSpecial() { doSomething(777); } void main(void) { MyClassInCpp cpp; cpp.doSomething(56); MyClassInCsharp c; c.doSomething(99); MySpecial s; s.doSpecial(); } C++ .NET Generics across languages • Generics authored in one .NET language may be used in other .NET languages. • Only some languages on the .NET Framework platform provide support for authoring generic types and methods. • J# does not support authoring of generic collection classes, but it does extend the Java-language syntax to provide support for using specializations of generic types and methods defined in other .NET Framework languages. • Example: a generic is defined in C# and consumed in J#. – The C# code defines a type parameter T which is unknown in the compiled assembly. The J# code supplies a type argument to the generic, thus generating a constructor where all unknown type parameters have been replaced by actual types. [MSDN Library: Generics in J#] Example: J# program consumes C# Generic Class C# // compile with // csc /t:library MyGeneric.cs // produces MyGeneric.dll public class MyGeneric<T> { public T Field; } J# //compile with // vjc /r:MyGeneric.dll GenericConsumer.jsl public class MyClass { public int x; } public class app { public static void main(String [] args) { MyGeneric<int> g1 = new MyGeneric<int>(); MyGeneric<MyClass> g2 = new MyGeneric<MyClass>(); } } Interoperability Managed/Unmanaged • .NET provides interoperability mechanism to permit managed code to call into unmanaged code and vice versa • Why? – Existing code works, why rewrite it? – Calling Microsoft functionality not yet available as .NET assemblies – Calling 3rd party native code – Migrate your code incrementally Interoperability Managed/Unmanaged • Three complementary technologies enable these managed/unmanaged interactions: – Platform Invoke (sometimes referred to as P/Invoke) enables calling any function in any unmanaged language as long as its signature is redeclared in managed source code. – COM interop enables calling into COM components in any managed language in a manner similar to using normal managed components, and vice versa. COM interop is comprised of core services provided by the CLR, plus some tools and APIs in the System.Runtime.InteropServices namespace. – C++ interop (sometimes referred to as It Just Works (IJW)) is a C++-specific feature, which enables flat APIs to be used directly, as they have always been used. [MSDN Library: An Overview of Managed/Unmanaged Code Interoperability ] Platform Invoke • When platform invoke calls an unmanaged function, it performs the following sequence of actions: – Locates the DLL containing the function. – Loads the DLL into memory. – Locates the address of the function in memory and pushes its arguments onto the stack, marshaling data as required. – Transfers control to the unmanaged function. [MSDN Library] Calling a DLL Export Directly from C# • To declare a method as having an implementation from a DLL export, do the following: – Declare the method with the static and extern C# keywords. – Attach the DllImport attribute to the method. The DllImport attribute allows you to specify the name of the DLL that contains the method. The common practice is to name the C# method the same as the exported method, but you can also use a different name for the C# method, specifying the EntryPoint. using System; using System.Runtime.InteropServices; class PlatformInvokeTest { [DllImport("msvcrt.dll")] public static extern int puts(string c); public static void Main() { puts("Test"); } } [MSDN Library: Platform Invoke Tutorial ] Default Marshaling and Specifying Custom Marshaling for Parameters to Unmanaged Methods • When calling an unmanaged function from C# code, the common language runtime must marshal the parameters and return values. • For every .NET Framework type there is a default unmanaged type, which the common language runtime will use to marshal data across a managed to unmanaged function call. • For example, the default marshaling for C# string values is to the type LPTSTR (pointer to TCHAR char buffer). You can override the default marshaling using the MarshalAs attribute in the C# declaration of the unmanaged function. [DllImport("msvcrt.dll")] public static extern int puts( [MarshalAs(UnmanagedType.LPStr)] string m); C++ Interop • The Visual C++ compiler (cl) can generate IL code or native code • Using compile switch /CLR it generates IL code from old C++ source files • Although the IL code produced is managed, the data is not: data objects that are not explicitly defined as managed types have no metadata associated, are not allocated from the managed heap and are not garbage collected. • A C++ program can use both managed and unmanaged types (IJW - It Just Works) – Example: A program that calls the standard C library function printf (unmanaged code) and the System.Console.WriteLine method (managed code). C++ Interop Example // compile with cl /CLR CppInterop.cpp #include <stdio.h> // For printf using namespace System; // For System namespace types // Implement a normal C/C++ main function void main() { // Call the C runtime library’s printf function. printf("Displayed by printf.\r\n"); // Call the FCL’s System.Console’s WriteLine method. Console::WriteLine("Displayed by Console::WriteLine."); }