Click here to Skip to main content
15,881,804 members
Articles / Programming Languages / C#
Article

Using P/Invoke in a managed C++ application

Rate me:
Please Sign up or sign in to vote.
3.50/5 (2 votes)
15 Oct 20011 min read 103.1K   1.6K   18   3
This article demonstrates interoperability between .NET managed code and old unmanaged code. It uses the P/Invoke mechanism to call unmanaged DLL entry points.

Introduction

This article demonstrates interoperability between .NET managed code and old unmanaged code. It uses the P/Invoke mechanism to call unmanaged DLL entry points.

To demonstrate this technique let's create a managed C++ console program that will run an application specified as a parameter of its command line. We use the ShellExecute function exported by the unmanaged DLL shell32.dll

First we create a new C++ project based on the managed C++ Console Application. The application wizard creates a class that has one static method main() that is an entry point to our application.

To access the .NET classes for P/Invoke support add the following line to your code:

using namespace System::Runtime::InteropServices;

In order to call a DLL export, we need to declare the method with the attached a DllImport attribute.

// Declare the function that is exported from unmanaged dll (shell32.dll).
[DllImport("shell32.dll")]
extern "C" int _cdecl ShellExecute(int hwnd,              // Handle to a parent window.
                                   String *strVerb,       // Action to be performed.
                                   String *strFileName,   // File or object on which to execute the specified verb.
                                   String *strParameters, // Parameters to be passed to the application.
                                   String *strDirectory,  // Default directory.
                                   int nShowCmd);         // Flags.

The marshaling service will marshal the managed types to the unmanaged types according its built-in rules. During the P/Invoke call the marshaler will automatically copy the managed integer type into an unmanaged integer type, it will convert (copy) the Unicode character buffer of the String objects to the ANSI character buffer.

Other data types have other marshalling characteristics. You can override the default behavior by specifying custom marshalling. Refer to the Data Marshaling Specification section of the .NET Beta Specification in MSDN.

Now you can call your declared method. The following code illustrates this.

#using <mscorlib.dll>

using namespace System;
using namespace System::Runtime::InteropServices;

// Declare the function that is exported from unmanaged dll (shell32.dll).
[DllImport("shell32.dll")]
extern "C" int _cdecl ShellExecute(int hwnd,              // Handle to a parent window.
                                   String *strVerb,       // Action to be performed.
                                   String *strFileName,   // File or object on which to execute the specified verb.
                                   String *strParameters, // Parameters to be passed to the application.
                                   String *strDirectory,  // Default directory.
                                   int nShowCmd);         // Flags.

// Managed class demonstrates Runtime's Platform Invocation Service
// (P/Invoke) to call unmanaged code from managed code.

 __gc class Launcher
{
public:
    // Starts program that specified by strFileName parameter
    static int StartProgram(String *strFileName)
    {
        return ShellExecute(0,
                            S"Open",
                            strFileName,
                            String::Empty,
                            String::Empty,
                            1 /*SW_SHOWNORMAL*/);
    }
};

// This is the entry point for this application
int main( int argc, char *argv[ ])
{
    // Check parameters.
    if(argc < 2)
    {
        Console::Write(S"Not enough parameters.");
        return 0;
    }

    // Call static function of the Launcher class and start program.
    if(Launcher::StartProgram(new String(argv[1])) < 33)
        Console::Write(S"Couldn't launch the program!");

    return 0;
}

History

16 Oct 2001 - updated source for VS .NET beta 2

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generala problem Pin
clark_xiao7-Sep-04 19:05
clark_xiao7-Sep-04 19:05 
a windows form class, use these name space:

using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices;

build error :
f:\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include\WinBase.h(3139): error C2872: 'FILETIME' : ambiguous symbol

about twenty err messages in WinBase.h
now what?

no signature
GeneralQuery regarding ShellExecute( ) Pin
Member 48497615-Jan-04 22:19
Member 48497615-Jan-04 22:19 
Generalold unmanaged code Pin
Rodrigo Strauss12-Jun-02 7:19
Rodrigo Strauss12-Jun-02 7:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.