skip to Main Content

There are two PCs with Visual Studio 2017 installed. I’m running a simple program on both of them, one that lists the name of modules (exes/DLLs) inside its own process.
But I get wildly different results. On one PC, I only get 7 modules:

    Lab7_1.exe
    ntdll.dll
    KERNEL32.DLL
    KERNELBASE.dll
    MSVCP140D.dll
    VCRUNTIME140D.dll
    ucrtbased.dll

On the other, I get whopping 31 modules. The full list includes, for example, user32.dll, which my sample program isn’t using (it’s a console app, not a GUI app).

So the question is: what exactly affects the list of DLLs imported by default? Debug/Release and x86/x64 switches produces some difference, but nothing that drastic.
Differences between platform tools versions (and corresponding versions of MS VC++ Redist) I can understand, but why are different system DLLs being imported as well?
I’m unsure where else to look.

Context: it’s a part of an assignment. On of those PCs is mine, the other is where the students work. The assignment goes like this "We have this set of modules by default, now we use MessageBoxA(), and we see that more modules are imported, user32.dll among them". Which doesn’t quite work if user32.dll is always imported by default.
Since the behaviour is vastly different, and I can’t reproduce it on my PC, it’s hard to adapt the assignment so the students can see import mechanics at work.

Sample program code:

#include <iostream>
#include <vector>
#include <string>
#include <Windows.h>
#include <Psapi.h>
using namespace std;
#pragma comment(lib, "psapi.lib") //needed for MS VS 2010

void EnumerateModules(vector<HMODULE>& modules)
{
    HANDLE me = GetCurrentProcess();
    DWORD needed_size = 0;
    while (true)
    {
        DWORD actual_size = modules.size() * sizeof(HMODULE);
        EnumProcessModules(
            me, //which process
            modules.data(), //where to put the module handlers
            actual_size, //allocated buffer size
            &needed_size //desired buffer size
        );
        if (needed_size != actual_size)
            modules.resize(needed_size / sizeof(HMODULE));
        else
            break;
    }
}

string ModuleName(HMODULE module)
{
    HANDLE me = GetCurrentProcess();
    string buffer(FILENAME_MAX, 0);
    DWORD real_length = GetModuleBaseNameA(
        me, //which process
        module, //which module
        &buffer[0], //where to put the name
        buffer.size() //size of the name buffer
    );
    if (real_length > 0)
        return buffer.substr(0, real_length);
    buffer = "";
    return buffer;
}


int main(int argc, char* argv[])
{
    setlocale(0, "");
    vector<HMODULE> modules;
    EnumerateModules(modules);
    cout << modules.size() << " modules:" << endl;
    for (size_t i = 0; i < modules.size(); i++)
    {
        string name = ModuleName(modules[i]);
        cout << name.c_str() << endl;
    }
    return 0;
}

2

Answers


  1. Chosen as BEST ANSWER

    Okay, turns out it's not related to Visual Studio settings. I compiled the sample code on one machine, ran in on the other, and got the same result as if I compiled the code there. So it's either Windows version (7 vs 10) or MS VS Redistributable version (though I think both projects used v140). In either case, I can't reproduce the behaviour on my machine unless I'm willing to set up a VM.


  2. The assignment goes like this "We have this set of modules by default, now we use MessageBoxA(), and we see that more modules are imported, user32.dll among them"

    Win32 programs, by default, will import ALL their dependent DLLs up front before any code is executed. When you invoke MessageBox it MIGHT pull in other modules via LoadLibrary, but user32.dll is already loaded before that function is invoked.

    The project setting you are wanting is delay loading which will generate the behavior you are claiming will happen. That is, the DLL won’t effectively be loaded until the function is actually invoked.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search