How do I customize the console properties for a shortcut to a console application?


You already know how to create a shortcut:

#include <windows.h>
#include <tchar.h>
#include <shlobj.h>
#include <atlbase.h>

// class CCoInitialize incorporated here by reference

int __cdecl _tmain(int argc, TCHAR **argv)
{
 // error checking elided for expository purposes
 CCoInitialize init;
 CComPtr<IShellLink> spsl;
 spsl.CoCreateInstance(CLSID_ShellLink);
 spsl->SetPath(TEXT("C:\\Windows\\system32\\cmd.exe"));
 CComQIPtr<IPersistFile>(spsl)->Save(L"Here.lnk", TRUE);
 return 0;
}

If you double-click the resulting shortcut from Explorer, it will run the command processor in a default console window.

Today's Little Program customizes the other console properties, so you can control settings like the console buffer size and whether QuickEdit is enabled by default.

We use the IShell­Data­List interface to attach "bonus data" to the shell link. The data we are interested in here is the NT_CONSOLE_PROPS. Remember, Little Programs perform little to no error checking, use hard-coded paths, and all that other stuff that make them unsuitable for shipping-quality code.

int __cdecl _tmain(int argc, TCHAR **argv)
{
 CCoInitialize init;
 CComPtr<IShellLink> spsl;
 spsl.CoCreateInstance(CLSID_ShellLink);
 spsl->SetPath(TEXT("C:\\Windows\\system32\\cmd.exe"));

 NT_CONSOLE_PROPS props;
 ZeroMemory(&props, sizeof(props));
 props.dbh.cbSize = sizeof(props);
 props.dbh.dwSignature = NT_CONSOLE_PROPS_SIG;
 props.wFillAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN |
                        FOREGROUND_RED; // white on black
 props.wPopupFillAttribute = BACKGROUND_BLUE | BACKGROUND_GREEN |
                             BACKGROUND_RED | BACKGROUND_INTENSITY |
                             FOREGROUND_BLUE | FOREGROUND_RED;
                             // purple on white
 props.dwWindowSize.X = 132; // 132 columns wide
 props.dwWindowSize.Y = 50; // 50 lines tall
 props.dwScreenBufferSize.X = 132; // 132 columns wide
 props.dwScreenBufferSize.Y = 1000; // large scrollback
 props.uCursorSize = 25; // small cursor
 props.bQuickEdit = TRUE; // turn QuickEdit on
 props.bAutoPosition = TRUE;
 props.uHistoryBufferSize = 25;
 props.uNumberOfHistoryBuffers = 4;
 props.ColorTable[ 0] = RGB(0x00, 0x00, 0x00);
 props.ColorTable[ 1] = RGB(0x00, 0x00, 0x80);
 props.ColorTable[ 2] = RGB(0x00, 0x80, 0x00);
 props.ColorTable[ 3] = RGB(0x00, 0x80, 0x80);
 props.ColorTable[ 4] = RGB(0x80, 0x00, 0x00);
 props.ColorTable[ 5] = RGB(0x80, 0x00, 0x80);
 props.ColorTable[ 6] = RGB(0x80, 0x80, 0x00);
 props.ColorTable[ 7] = RGB(0xC0, 0xC0, 0xC0);
 props.ColorTable[ 8] = RGB(0x80, 0x80, 0x80);
 props.ColorTable[ 9] = RGB(0x00, 0x00, 0xFF);
 props.ColorTable[10] = RGB(0x00, 0xFF, 0x00);
 props.ColorTable[11] = RGB(0x00, 0xFF, 0xFF);
 props.ColorTable[12] = RGB(0xFF, 0x00, 0x00);
 props.ColorTable[13] = RGB(0xFF, 0x00, 0xFF);
 props.ColorTable[14] = RGB(0xFF, 0xFF, 0x00);
 props.ColorTable[15] = RGB(0xFF, 0xFF, 0xFF);
 CComQIPtr<IShellLinkDataList>(spsl)->AddDataBlock(&props);

 CComQIPtr<IPersistFile>(spsl)->Save(L"Here.lnk", TRUE);
 return 0;
}
Comments (9)
  1. Dan Bugglin says:

    For fun, here's the original EGA color palette (at least, this is what I observed it as, back in the day):

    props.ColorTable[ 0] = RGB(0x00, 0x00, 0x00);

    props.ColorTable[ 1] = RGB(0x00, 0x00, 0xAA);

    props.ColorTable[ 2] = RGB(0x00, 0xAA, 0x00);

    props.ColorTable[ 3] = RGB(0x00, 0xAA, 0xAA);

    props.ColorTable[ 4] = RGB(0xAA, 0x00, 0x00);

    props.ColorTable[ 5] = RGB(0xAA, 0x00, 0xAA);

    props.ColorTable[ 6] = RGB(0xAA, 0x55, 0x00);

    props.ColorTable[ 7] = RGB(0xAA, 0xAA, 0xAA);

    props.ColorTable[ 8] = RGB(0x55, 0x55, 0x55);

    props.ColorTable[ 9] = RGB(0x55, 0x55, 0xFF);

    props.ColorTable[10] = RGB(0x55, 0xFF, 0x55);

    props.ColorTable[11] = RGB(0x55, 0xFF, 0xFF);

    props.ColorTable[12] = RGB(0xFF, 0x55, 0x55);

    props.ColorTable[13] = RGB(0xFF, 0x55, 0xFF);

    props.ColorTable[14] = RGB(0xFF, 0xFF, 0x55);

    props.ColorTable[15] = RGB(0xFF, 0xFF, 0xFF);

  2. skSdnW says:

    Too bad this struct does not have a mask field to mark which fields you want to set, you either have to guess what the correct defaults should be for the things you don't need to change or read from the registry.

    You don't seem to set any of the font fields, does 0 mean default? MSDN does not say anything about it…

  3. John Doe says:

    I couldn't comment further on "Reading mouse input from a console program, and programmatically turning off Quick Edit mode" (can't link)

    So, I think the actual reason the ENABLE_EXTENDED_FLAGS exists is this: "Why isn't QuickEdit on by default in console windows?" (can't link)

    Probably, its name would better be something along the lines of "enable special mouse modes", as insert mode uses the right mouse button and quick-edit mode uses drag and drop and the right mouse button, both messing with mouse input.

    Being that NT_CONSOLE_PROPS is the structure used to deal with shortcuts, maybe the situation was only dealt with at runtime with SetConsoleMode, unlike what I previously suspected.

    Anyway, Raymond, what has the future reserved for shell experts? I mean, Windows 8 removed the start menu and yet added a ribbon to Explorer. Ok, I guess you can't answer this, but this is kind of contradictory, specially now that Modern is the New Thing, until it's the Old.

  4. Yuhong Bao says:

    John Doe: The Ribbon was in the Developer Preview, before they removed the start menu.

  5. Medinoc says:

    ^You mean the ribbon is not actually present in the retail Windows 8 explorer?

    On shortcuts: Sweet! It's PIF all over again! Minus the "keep console open after program ends" option.

  6. Neil says:

    @The MAZZTer: I always wondered why #6 was #AA5500 and not, say, #AAAA00.

  7. Typo in source says:
    • CComQIPtr<IShellDataList>(spsl)->AddDataBlock(&props);

    • CComQIPtr<IShellLinkDataList>(spsl)->AddDataBlock(&props);

  8. Lorin Geisendorfer says:

    Using CComQIPtr for an example is OK but in the real world you really need to get the hResult.

    ATL is nice if you know how to use it in production. You demand your readers learn the API that

    is what I respect most about all your posts. Good quality but could use more reader input. You

    have challenged me many times to write code that is correct and full.

    [I think you completely missed the point of Little Programs. -Raymond]
  9. Lorin Geisendorfer says:

    if you want to code review just ask me.

Comments are closed.

Skip to main content