Skip to content

Custom error message when Visual Studio distributable package is not installed on Windows #48

Open
@kubo

Description

@kubo

How about custom error message when Visual Studio distributable package is not installed?
IMO, oracle/node-oracledb#404 (comment) should be checked in ODPI-C.

When GetLastError() returns ERROR_MOD_NOT_FOUND(The specified module could not be found), do the following.

  1. Search OCI.DLL in the following directories in this order:
    1. Executable directory (Get the full path of the executable by GetModuleFileName(NULL, buf, sizeof(buf)) and truncate the file name.)
    2. Current directory
    3. each directory in the environment variable PATH.
  2. If OCI.DLL is not found, use the message from FormatMessage().
  3. If OCI.DLL is found, get the bit of the DLL (see the function below) and skip if it isn't same with the executable.
  4. If step 3 passes, get import DLL files (see the function below) and get the DLL whose name is 'MSVCR*.DLL'.
  5. Call LoadLibrary with the 'MSVCR*.DLL' at step 4.
  6. If step 5 fails, map the 'MSVCR*.DLL' name to VS distributable package name and create a custom error message.

The following is a sample function which prints bit and dependent DLL files.
It is easy to customize this to fit this issue's need.

// link dbghelp.lib also
#include <dbghelp.h>

static void print_import_dlls(const char *name)
{
    HANDLE hFile = CreateFile(name, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    HANDLE hFileMapping = NULL;
    void *base = NULL;
    if (hFile == INVALID_HANDLE_VALUE) {
        printf("failed to open: %s\n", name);
        return;
    }
    hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (hFileMapping == NULL) {
        printf("failed to create file mapping: %s\n", name);
        goto cleanup;
    }
    base = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
    if (base == NULL) {
        printf("failed to map file: %s\n", name);
        goto cleanup;
    }
    IMAGE_NT_HEADERS *nt_hdr = ImageNtHeader(base);
    if (nt_hdr == NULL) {
        printf("not executable nor DLL: %s\n", name);
        goto cleanup;
    }

    printf("%s (%s bit):\n", name, nt_hdr->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ? "32" : "64");
    ULONG uSize = 0;
    IMAGE_IMPORT_DESCRIPTOR *desc = (IMAGE_IMPORT_DESCRIPTOR *)ImageDirectoryEntryToDataEx(base, FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &uSize, NULL);

    while (desc->Characteristics != 0) {
        char *name = (char*)ImageRvaToVa(nt_hdr, base, desc->Name, NULL);
        printf("  %s\n", name);
        desc++;
    }
cleanup:
    if (base != NULL) {
        UnmapViewOfFile(base);
    }
    if (hFileMapping != NULL) {
        CloseHandle(hFileMapping);
    }
    CloseHandle(hFile);
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions