November 17th, 2025
0 reactions

How can I detect that Windows is running in S-Mode, redux

Igor Levicki asked for a plain C version of the sample code to detect whether Windows is running in S-Mode. I didn’t write one for two reasons. First, I didn’t realize that so many people still tried to use COM from plain C. And second, I didn’t realize that the people who try to use COM from plain C are not sufficiently familiar with how COM works at the ABI level to perform the mechanical conversion themselves.

  • p->Method(args) becomes p->lpVtbl->Method(p, args).
  • Copying a C++ smart COM pointer consists of copying the raw pointer and performing an AddRef if the raw pointer is non-null.
  • Destroying a C++ smart COM pointer consists of performing a Release if the raw pointer is non-null.
  • Before overwriting a C++ smart COM pointer, remember the old pointer value, and if it is non-null, Release it after you AddRef the new non-null pointer value.

The wrinkle added by the Windows Runtime is that C doesn’t support namespaces, so the Windows Runtime type names are decorated by their namespaces.

And since you’re not using WRL, then you don’t get the WRL helpers for creating HSTRINGs, so you have to call the low-level HSTRING functions yourself.

#include <Windows.System.Profile.h>

HRESULT ShouldSuggestCompanion(BOOL* suggestCompanion)
{
    HSTRING_HEADER header;
    HSTRING className;
    HRESULT hr;

    hr = WindowsCreateStringReference(RuntimeClass_Windows_System_Profile_WindowsIntegrityPolicy,
                ARRAYSIZE(RuntimeClass_Windows_System_Profile_WindowsIntegrityPolicy) - 1,
                &header, &className);
    if (SUCCEEDED(hr))
    {
        __x_ABI_CWindows_CSystem_CProfile_CIWindowsIntegrityPolicyStatics* statics;
        hr = RoGetActivationFactory(className, &IID___x_ABI_CWindows_CSystem_CProfile_CIWindowsIntegrityPolicyStatics, (void**)&statics);
        if (SUCCEEDED(hr))
        {
            boolean isEnabled;
            hr = statics->lpVtbl->get_IsEnabled(statics, &isEnabled);
            if (SUCCEEDED(hr))
            {
                if (isEnabled)
                {
                    // System is in S-Mode
                    boolean canDisable;
                    hr = statics->lpVtbl->get_CanDisable(statics, &canDisable);
                    if (SUCCEEDED(hr))
                    {
                        // System is in S-Mode but can be taken out of S-Mode
                        *suggestCompanion = TRUE;
                    }
                    else
                    {
                        // System is locked into S-Mode
                        *suggestCompanion = FALSE;
                    }
                }
                else
                {
                    // System is not in S-Mode
                    *suggestCompanion = TRUE;
                }
            }
            statics->lpVtbl->Release(statics);
        }
    }

    return hr;
}

There is a micro-optimization here: We don’t need to call Windows­Delete­String(hstring) at the end because the string we created is a string reference, and those are not reference-counted. (All of the memory is preallocated; there is nothing to clean up.) That said, it doesn’t hurt to call Windows­Delete­String on a string reference; it’s just a nop.

It wasn’t that exciting. It was merely annoying. So that’s another reason I didn’t bother including a plain C sample.

Baltasar García offered a simplification to the original code:

bool s_mode = WindowsIntegrityPolicy.IsEnabled;
bool unlockable_s_mode = WindowsIntegrityPolicy.CanDisable;
bool suggestCompanion = !s_mode || (s_mode && unlockable_s_mode);

and Csaba Varga simplified it further:

bool suggestCompanion = !s_mode || unlockable_s_mode;

I agree that these are valid simplifications, but I spelled it out the long way to make the multi-step logic more explicit, and to allow you to insert other logic into the blocks that right now merely contain an explanatory comment and a Boolean assignment.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments