Re: VC++ .NET 2002: Which Wizard/Template to Use to Get a Regular DLL and a non-MFC DLL of native C++ programming

Tech-Archive recommends: Fix windows errors by optimizing your registry

From: Bronek Kozicki (brok_at_rubikon.pl)
Date: 03/27/04

  • Next message: Joachim: "SSH API for C++?"
    Date: Sat, 27 Mar 2004 20:53:33 +0100
    
    

    On Fri, 26 Mar 2004 08:01:15 -0800, Scott Chang wrote:
    > Hi all,

    Hi Scott

    I have a feeling that you do not quite understand what "regular DLL" is.
    It's a single executable file compiled to machine code (not MSIL, ie.
    not .NET assembly - just old-fashioned Win32 executable) exporting
    C-style functions, which can be called from other DLL-s or programs, but
    cannot be started in own process (like .exe executables). It's also
    called "dynamic library", as it's just a library of functions which can
    be dynamically loaded into memory by other programs and then called.
    Prior to this use such DLL file must be loaded into memory by host
    process, and when it's no longer needed it might be unloaded. When DLL
    file is loaded to or unloaded from memory by host process, function
    DllMain contained within this DLL is called to notify
    your code to prepare for work or do final cleanup. It's also called when
    process hosting your DLL starts new threads or terminates them. There
    are some restrictions on what can be called from within DllMain - most
    notably you may not create new threads. Thanks to recent additions to
    Visual C++ it's also possible to export variables or C++ classes from
    DLL, as you will see later on. Do not use these features if you want to
    make your DLL usable from other compilers or other programming
    languages, though. Please also note that I did not use words "MFC" or
    "Managed C++" above - as those are NOT plain dynamic libraries!

    Let me first show you how to make "regular DLL". Start Visual Studio
    .NET (I'm talking about version 2002, aka 7.0), select menu File > New >
    Project... . Select "Visual C++ Project" on the left pane and then
    "Win32 Project" on right one (last icon, at least on my computer). Name
    your project (your .dll file will use this name - make is short and
    without special characters) and click OK. "Win32 Application Wizard -
    your_name" appears, but do not close it yet! Click on "Application
    Settings" on the left side of the wizard window. Now you can see
    "Application type" option - default one is "Windows application". Change
    it to "DLL". If you press "Finish" now, you will get what you are
    looking for: project for plain Win32 dynamic library, aka "regular
    DLL". Before you click OK you have two options, NONE of them is related
    to MFC or Managed C++:

    * "Empty project" means that wizard will not create any source file
    (like .c, .cpp or .h) for your project - you need to manually create
    these files in your project. It also means that wizard will not create
    precompiled header and will setup your project not to use it (I will
    explain later what's "precompiler header"). If you leave this option
    unchecked, wizard will setup your project to use precompiled header and
    create few source files:
      stdafx.cpp - it's used to compile precompiled header (you compile it
    whenever you change project settings or content of stdafx.h)
      your_name.cpp - here you can put functions you are going to export
    from your DLL, but there's nothing special about this file. Currently it
    contains only DllMain function. You can read more about this function
    in MSDN. If your code do not need to do anything on startup (when loaded
    into memory, just before any of its functions is called) or cleanup
    (just before being unloaded from memory) you may leave this function as
    it is. I advice that you look for more information here:
    http://msdn.microsoft.com/library/en-us/dllproc/base/dynamic_link_library_entry_point_function.asp

      stdafx.h - here you may include all headers you are going to put in
    precompiled header. By default there's only <windows.h>. I usually
    include there number of standard C++ headers, like:
    #include <string>
    #include <vector>
    #include <algorithm>
    #include <memory>
    #include <sstream>
    (because I use standard C++ library in my code quite often), but you
    may leave it as it is, or put any other common includes (ie. ones you
    are going to include from all .cpp files in your project). Make sure all
    your .cpp files start with:
    #include "stdafx.h"
    This will indirectly include to your .cpp files all files included in
    stdafx.h. There is performance gain however - all these headers has been
    processed once, when you compiled stdafx.cpp. As a result all .cpp files
    which included "stdafx.h" header will compile faster, thus saving your
    (developer) time. This is the sole purpose of precompiled header - as
    you can see, it has nothing to do with MFC. Of course MFC projects do
    use stdafx.h for own purposes, as you can - without all burden of MFC.
    Just remember that whatever you put into stdafx.h will be included by
    all .cpp files (technically it's called "translation units", not ".cpp
    files") and anytime you change it, you need to recompile stdafx.cpp

    * If you do not check "Empty project", you may check "Export symbols".
    This will result in slightly longer your_name.cpp file and new file
    named your_name.h.
      your_name.h - this file is intended to contain declarations of all
    entities you are exporting from your DLL library. It also contains
    sample definition of simple class, declaration of variable and
    declaration of function - all exported from your DLL. I suggest that you
    comment out everything below #endif preprocessor directive and use it
    later only for reference. This file is designed to accompany your DLL
    file when you want others to see declarations of exported functions (or
    classes or variables) - it will help them to use your DLL properly. It's
    specific to Visual C++ - other compilers might not understand
    "__declspec" keyword. If someone with different compiler is going to use
    your DLL, he/she will probably need to manually adjust this header file.
      your_name.cpp - this file now contains little longer DllMain and
    definitions of entities declared in your_name.h - namely body of
    constructor of sample class, definition of variable and body of sample
    function. If you commented out in your_name.h everything below #endif,
    you also need to comment out in this file everything below DllMain.
      
    Please note that there's no .def file - it's no longer required in
    Visual Studio .NET . Instead you put "__declspec(dllexport)" before
    declaration or definition of entities (functions, classes, variables)
    you are going to export from DLL. If you do not use it, users of your
    dynamic library will not see these entities (but you can still use .def
    file for required effect). BTW: If you are going to use this DLL from
    other compilers than Visual C++ or programs compiled in other languages
    (like Delphi or .NET), do not export anything else but functions, and
    make sure you put:
    extern "C"
    prior to function definition (and declaration), just before
    "__declspec(dllexport)" if your function is defined in .cpp file (ie. is
    written in C++, not C). Otherwise users of your library will see mangled
    name of your function instead of expected name. As mangling is specific
    to compiler, users of other compilers will not be able to find your
    function using name you provided, also GetProcAddress won't be able to
    find your exported function.

    Here is sample implementation file of dynamic library - you may use it
    in place of of your_name.cpp if you did not checked "Export symbols" (or
    if you checked it but commented out parts of your_name.h and
    your_name.cpp, as advised above).

    #include "stdafx.h"
    BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
    {
      if (reason == DLL_PROCESS_ATTACH)
      {
        DisableThreadLibraryCalls(hModule);
        ; // your initialization code goes here
      }
      else if (reason == DLL_PROCESS_DETACH)
      {
        ; // your cleanup code goes here
      }

      return TRUE;
    }

    extern "C" __declspec(dllexport) int Add(int a, int b)
    {
      return a + b;
    }

    You may also use it in "Empty project", but please change first line
    from:
    #include "stdafx.h"
    to:
    #include <windows.h>
    as "empty project" by default is set not to use precompiled header.

    If you define exported function inside .c file (ie. you write it in C,
    not in C++ programming language) do not use extern "C"

    You should consider adding version resource to your project. Select
    menu Project > Add Resource, in "Add Resource" dialog select "Version"
    (last one) and press "New" - version info will appear. Here you can put
    some information about your DLL - like version number, full project name
    and copyright.

    Another thing you should take care of is to select right runtime version
    - by default its static, but if you want to return pointers from
    functions exported in your DLL and allow your users to free these
    pointers, you need to use dynamic runtime instead. Click on your project
    in one of windows "Solution Explorer", "Class View" or "Resource View"
    then select Properties from right-click menu. You will see project
    properties window. On the left pane select "C/C++" (you need to have at
    least one .c or .cpp file in your project, otherwise you won't see this
    option there), then "Code Generation" below. Now you need to change
    Runtime Library on the right pane - in Debug configuration it should be
    "Multi-threaded Debug DLL (/MDd)" (by default it's "Multi-threaded Debug
    (/MTd)"); in Release configuration it should be "Multi-threaded DLL
    (/MD)" (by default it's "Multi-threaded (/MT)"). Make sure you change
    both configurations - Debug and Relase! You will also need to distribute
    your DLL file together with runtime libraries: msvcr70.dll and
    msvcp70.dll (together with Release version of your DLL) or msvcr70d.dll
    and msvcp70d.dll (together with Debug version of your DLL). These files
    have nothing to do with MFC - you are not using it! It's just Microsoft
    C and C++ runtime library for Visual C++ 7.0 . Good news is that you do
    not always need to redistribute these files (as many users already have
    them) and thanks to use of dynamic runtime your own DLL will be smaller.
    If you want to use static runtime library (and not to worry about
    distribution of DLLs stated above) there's nothing wrong, just make sure
    that functions exported from your DLL do not allow your users to free
    any kind of resources you are allocating. Otherwise they will experience
    all kinds of strange errors. These errors will also happen if you are
    using dynamic runtime, but your users are using different dynamic
    runtime or static runtime. It's best not to allow your users to free any
    resources allocated by your dynamic library - if you follow this advice,
    you do not need to worry about runtime version your DLL is using.

    I hope you get the basics now. Good luck and best regards!

    B.

    PS. it's updated version


  • Next message: Joachim: "SSH API for C++?"

    Relevant Pages

    • Re: building dynamic runtime library through command line.
      ... libraries and for exporting and importing, ... dllexport or dllimport. ... linker file, ...
      (microsoft.public.vc.language)
    • Re: building dynamic runtime library through command line.
      ... libraries and for exporting and importing, ... dllexport or dllimport. ... autolink it to boost lib file when building main. ...
      (microsoft.public.vc.language)
    • Re: How to seperate the C++ template implementation and definition in different files?
      ... library for compilers that have it, ... header-only libraries would be less common. ... Non-template code in a DLL + import library set is most definitely usable by ...
      (microsoft.public.vc.language)
    • Re: Compile with different versions of Visual Studio
      ... VC6 has a different C runtime library (including memory manager) than VC8, therefore you can't share the same RTL between the two modules. ... It doesn't mean that you can't use dynamic RTL for your application, but you can't share the same dynamic RTL between modules compiled with different compilers. ... For example, if you use MFC from both the DLL and the application, they were be completely independent copies of the MFC library that have nothing to do with each other. ...
      (microsoft.public.dotnet.languages.vc)
    • Need assistance in converting sample C code to C# to be used in an unmanaged DLL
      ... a DLL that will be used in an application that I am writing code for. ... The recommended compilers to build the C code are Bloodshed Dev-CPP & ... BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID ... I do appreciate the assistance of members from this forum. ...
      (microsoft.public.dotnet.framework.interop)