What is the difference between creating a MFC DLL from Visual Studio wizard and creating C++ Console Application and changing the configuration type to DLL instead of .exe?
You can surely figure out how to change a console application to dll type, but it's recommended to use the non-MFC DLL project template.
One major difference between a non-MFC and a MFC Extension DLL is that it would allow sharing resources like dialog templates or bitmaps to MFC appliactions by calling
// MFC extension DLL one-time initialization
AfxInitExtensionModule(PROJNAMEDLL, hInstance);
// Insert this DLL into the resource chain
new CDynLinkLibrary(Dll3DLL);
in DllMain(). Other benefits are that you can use MFC (CObject-derived) classes that sit in the dll and that the MFC Extension DLL can share the memory address space with the calling instance, meaning that two apps loading the same extension DLL will only share the code but won't interfere with allocated data.
Note that you need the "shared MFC DLL" project setting to use extension DLLs. Linking MFC statically into your project won't work. So extension DLLs aim at sharing code among different apps that run simultaneously, for example, but only use the code memory once. This way of code reuse was one intention at least when extension DLLs were introduced, but in the real world different apps tend to use different versions (dll hell, side-by-side). Speaking of:
One good use of an extension DLL is to customize an app (branding, localisation) just by installing differend versions of a dll.
Further reading: https://learn.microsoft.com/en-us/cpp/build/extension-dlls
According to Creating an MFC DLL Project it states:
An MFC DLL is a binary file that acts as a shared library of functions that can be used simultaneously by multiple applications. The easiest way to create an MFC DLL project is to use the MFC DLL Wizard.
This article Kinds of DLLs also states:
Using Visual Studio, you can build Win32 DLLs in C or C++ that do not
use the Microsoft Foundation Class (MFC) library. You can create a
non-MFC DLL project with the Win32 Application Wizard.
The MFC library itself is available, in either static link libraries
or in a number of DLLs, with the MFC DLL Wizard. If your DLL is using
MFC, Visual Studio supports three different DLL development scenarios ...
I believe the above explains the difference:
One version of the DLL exposes the MFC library.
One version does not.
That is my understanding.
Other related article: Create C/C++ DLLs in Visual Studio
An MFC DLL is a dynamic library that uses MFC components and the MFC runtime. This means that an MFC dynamic library usually requires the MFC support libraries along with the MFC runtime. To compile an MFC DLL requires the MFC include files and the MFC directives.
When you use the Visual Studio Wizard to create an MFC DLL all the compiler, linker, and other settings and options needed to create an MFC DLL are all generated for you along with an MFC DLL stub.
A Console Application is an application that uses the C++ Runtime from a console window.
When you use the Visual Studio Wizard to create a Console Application all the compiler, linker, and other settings and options to create a Console Application are all generated for you with a Console Application stub which is typically a Hello World type of application with a main() that contains a printf().
The source code for a DLL has required structure for a DLL main entry point that is different from the required structure for a Console Application main entry point. See the Microsoft article DllMain entry point which has this example source code:
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
So the differences between an MFC DLL and a Console Application involves a number of areas:
the structure of the source code
the include files used in the compile
the libraries used in the link
the options used in the compile
the options used in the link
Changing the configuration type does not modify the source code or include files specified in the source code. Nor does changing the configuration type change all of the necessary compiler and linker options and property settings that need to be changed.
See this Microsoft article, DLLs and Visual C++ run-time library behavior, that discusses the structure of DLLs and their run time behavior which provides an idea as to the differences between an EXE and a DLL.
An Application (executable) is a module that can be run. It contains one entrypoint, the main() (console) or WinMain() (windows GUI) function. A running instance of an executable is called a "process" in Win32.
A DLL is a library, intended for use by other applications. It is loaded at runtime - "dynamically", hence the name. DLLs contain no main entrypoint, instead they "export" functions or even classes and data. Lacking a main entrypoint, DLLs cannot be run stand-alone, instead they are "loaded into a process's (application's) address-space". The process can use their exported items. It is a good way to implement commonly used operations, for example a company's "development environment" or "foundation" - SDKs are typically implemented as DLLs.
MFC is a C++ library containing GUI (and other) classes and functions, largely (but not exclusively) wrapping Win32 objects. An application or DLL can be using the MFC library, or not.
As for your question, creating a console application and then changing it to DLL makes no sense. The Wizard will create a main() function, which you will have to manually remove. And finally you will have what, a normal DLL... You can simply create a DLL from the start, whether it will be using MFC or not.
EDIT:
According to the documentation from Microsoft:
Each process provides the resources needed to execute a program. A process has a virtual address space, executable code, open handles to system objects, a security context, a unique process identifier, environment variables, a priority class, minimum and maximum working set sizes, and at least one thread of execution. Each process is started with a single thread, often called the primary thread, but can create additional threads from any of its threads.
So yes, processes need to contain at least one thread - terminating the primary thread also terminates the process. Furthermore, an executable must contain an entry point, it's what the primary thread will execute and return a value to the system. It's actually impossible to build an executable without a main()/WinMain() function, it will generate Linker Error LNK1561:
entry point must be defined
The linker did not find an entry point, the initial function to call in your executable. By default, the linker looks for a main or wmain function for a console app, a WinMain or wWinMain function for a Windows app, or DllMain for a DLL that requires initialization. You can specify another function by using the /ENTRY linker option.
As for DLLs, the term dynamic "linking" is indeed used by MS, however only to highlight the differences to static linking (what most developers consider linking). It's not linking in the usual way, ie resolving externals, changing symbol names to addresses, performing fixups and the like. A DLL has no unresolved externals and the so called "linking" means just locating exported items from the loaded DLLs (in the case of using an import library they are also assigned to local functions) - the linker is not involved in the procedure. Further information here.
Therefore I don't think that there was something "slightly wrong" in what I had posted above, and certainly not "literally everything".
As for whether my answer should be considered useful or not, I think I was right to suggest not creating an executable and changing it to a dll. An MFC DLL is a DLL "based on" (using) the MFC library - this was clear in my first post. The OP didn't ask about MFC extension DLLs particularly.
Related
I have a VS2017 MFC C++ application which uses a ribbon based UI. Up until now I have been using the statically linked MFC libraries but now have to move to MFC in a DLL as I need Multithreaded DLL linkage /MD in order to support another third party SDK (Vulkan). One of the reasons for using statically linked MFC is that it allowed me overcome some problems in the implementation simply by including the source for the item I needed to change in my application. e.g. to use data the edit part of a combo box to select the nearest item in the drop down. This doesn't work when I use the DLL version of MFC for obvious reasons, is there any way around this? I can't simply inherit from MFC base classes as my application is building the ribbon interface from a ribbon resource file and there don't seem to be any hooks to customise this behaviour.
My current thoughts for possibilities include building my own version of the MFC DLLs or simply adding the full MFC source as a sub-project and change my main project Use of MFC to Use Standard Windows Libraries. Both of these seem like nasty hacks.
Edit: In response to the comment below from IInspectable, I'm not entirely sure why the current behaviour doesn't work but have some ideas. Linking the static lib version of the code, if I include my own copy of a function that occurs in the lib, the lib version never gets called (possibly never even gets linked). When linking the DLL version of MFC, my modified function never gets called. This could be because it is called by another function in the same DLL which never sees my code or it has a slightly different decorated name. My thinking is that including all the MFC source in my app and not linking any MFC in the compiler options is one brute force solution, though a pretty horrible one.
I ended up recompiling a custom version of the MFC DLL based on this project, https://www.codeproject.com/Tips/5263509/Compile-MFC-Sources-with-Visual-Studio-2019 This lets me keep my MFC modifications while also using MFC in a DLL with minimal changes to my existing project
Crashing Code
The following code makes my program crash (program exits) by heap corruption when the third line (the 'delete' command) is called:
1: CStringArray* pStringArray = new CStringArray();
2: ClassInDll::addToStringArray(_T("asdf"), *pStringArray);
3: delete pStringArray;
with
1: ClassInDll::addToStringArray(CString s, CStringArray& sa){
2: sa.Add(s);
3: }
addToStringArray() is static
Be aware that this is not actually my code, but simply the minimum with which I can reproduce the error. It is reproducible with CArray<CString> as well.
I verified, that the heap corruption does indeed not happen before that code line via
gflags /p /enable MyExe.exe /full
StackTrace:
What seems to be the problem
Dll dependency
MFC source
1
CStringArray creation
MyExe.exe > MFC
...\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\array_s.cpp
2
Internal array allocation
MyExe.exe > MyDll.dll > MFC
...\Microsoft Visual Studio 10.0\VC\atlmfc\include\afxcoll.inl
3
Deletion
MyExe.exe > MFC
...\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\array_s.cpp
The fact that the internal array is not deleted the same way it was created is probably the error. (Please correct me if I'm wrong)
Project Settings
I made sure that the same MFC settings are used in MyExe.exe as well as MyDll.dll, i.e.:
Use of MFC
Use MFC in a Shared DLL
Use of ATL
Not using ATL
Character Set
Use Unicode Character Set
I test in debug mode, so there is no optimization.
Question
MyDll.dll is not the only dll that is loaded, and there is too much going on with project dependencies (to third party dlls etc), so I cannot make all this part of my question.
So my questions boil down to:
Is my assumption correct that array_s.cpp and afxcoll.inl are not compatible with one another?
What makes one piece of code call array_s.cpp, and the other call afxcoll.inl?
What else could be the problem?
I have tried turning it off and on again ;)
Thank you in advance!
Update
PaulMcKenzie pointed out that this is the case if I build against different CRTs which was the case. One was "Multithreaded Debug DLL", the other was "Multithreaded DLL". Still, the problem persists, after making both equal. This page states that if using VS 2015 and above with Windows 10 and having project settings so that the same runtime library is used, the same CRT library is used at runtime (and therefore should use the same heap, right?).
I've made sure, that every entry within "Project Properties -> C/C++ -> Code Generation" is exactly the same in the exe and dll.
Passing MFC objects (even via pointers) between modules (EXEs and DLLs, or different DLLs) is a very tricky business. If you're simply using classes in the DLL, then you should (at the very least) be using the AFX_MANAGE_STATE macro (see here) in the DLL.
However, if your DLL is defining its own MFC-derived classes (your ClassInDll seems to be such), it should really be built as an MFC Extension DLL.
The whole process of building extension DLLs (and even using the 'regular' MFC DLLs) is rather too broad for me to provide any usable source code for you here. But, from the second link above, the following section is likely relevant to the problem(s) you are seeing (bold italics are mine):
Memory Management
MFCx0.dll and all MFC extension DLLs loaded into a client
application's address space use the same memory allocator, resource
loading, and other MFC global states as if they were in the same
application. This is significant because the non-MFC DLL libraries and
the regular MFC DLLs do the exact opposite and have each DLL
allocating out of its own memory pool.
If an MFC extension DLL allocates memory, that memory can freely
intermix with any other application-allocated object. Also, if an
application that dynamically links to MFC fails, the protection of the
operating system maintains the integrity of any other MFC application
sharing the DLL.
Similarly other global MFC states, like the current executable file to
load resources from, are also shared between the client application
and all MFC extension DLLs as well as MFCx0.dll itself.
It turned out that release and debug dlls were both being loaded (because of another dll):
msvcr100.dll
msvcr100d.dll
msvcp100.dll
msvcp100d.dll
The "modules" window sure does help, if you only know that you should look there.
Thanks to PaulMcKenzie and IInspectable for leading me into the right direction.
MFC projects provide enhanced support for satellite dlls which generally helps in creating localized application with multiple resources. Those dlls are called as Saltellite dlls. When program is executed, MFC automatically loads the localized resource based on environment.
If MFC does not find any satellite DLLs, it uses whatever resources are contained in the application itself. I want to know if there is any configuration setting or any other way which can help stopping MFC to load any resource specific dll.
I know that MFC tries to load resource dlls and some other initialization stuff at entry point by calling method InitInstance(). If I do not call InitInstance method, I am observing MFC does not try to load any resource specific dll. Not sure if this is right way or is there Microsoft suggested way?
I got the VC++ source code of a dll for a USB device project, which the deadline is close. Right now I have to call this usb dll from another VB program. But the source code is based on the template "MFC Extension DLL", which can´t be called by VB. On the other hand, "Regular DLL with MFC statically linked" can be called by programs written in Visual Basic.
Is there a way, with the least effort of modification of the source code, to be able to call this dll directly from VB?
I tried to modify the project´s configuration properties/Use of MFC to Use MFC in a Static Library. But there is build error.
Now I am modifying the source code based on the new template "Regular DLL with MFC", but there is a lot of problems. For example, I don´t know whether I can use AFX_EXTENSION_MODULE in my new dll code.
Your problem is likely due to not implementing a CWinApp derived object which provides services that the MFC classes in the DLL rely upon. Probably you can just bung one in and it will work.
See here for more information:
http://msdn.microsoft.com/en-US/library/h5f7ck28(v=VS.80).aspx
How are DLLs created out of C++ source code, and how are they used in other sources?
The DLL is a 'Dynamic Link Library' which works a lot like other libraries but is not linked with your executable application. At run time you can call specific functions for loading your DLL and executing its exported methods.
You can try creating a DLL yourself- create a project using visual studio and specify a DLL. This will create some of the base constructs for your project such as settings for your project to compile the DLL and also some base code for exposing methods, objects, or variables.
There are many walk through's to help you at this point: check here.
So, to summarize:
A DLL is a library which you can be loaded at runtime. This is a very flexible 'plug-in' model. Example: You can programmatically select and load different DLL at runtime. Each DLL can be a 'plug-in' to provide different functionality.
A DLL Has an entry point. Just like your Main function of your command line executable is the entry point, the DLL has an entry point function which is called when different events occur on the DLL such as loading, unloading, and more.
To use a DLL you must use the exported objects or methods of the DLL.
When Calling these exported functions from another application it is very important that you match compatible types! Also, make sure the calling conventions are compatible