Picks the best matching function from a list based on the supportedOS guids in the manifest
Syntax
FARPROC WINAPI SbSelectProcedure (
ULONG signature,
ULONG unk,
const SWITCHBRANCH_SCENARIO_TABLE* pScenarioTable,
ULONG scenarioIndex
)
Parameters
- signature
- The value 0xABABABAB
- unk
- Unknown. Always set to 1
- pScenarioTable
- The table describing the various scenarios in this module
- scenarioIndex
- Which scenario in the table to pick the function for
Return Value
The best matching function or NULL on failure
Remarks
All instances of usage of this function use the signature value 0xABABABAB, but this value is actually ignored
The Sb in the function name stands for SwitchBack which is the name of this technology, but the symbols for the structures used in support of it are named SwitchBranch
There are numerous support structures required in addition to the third argument, these are defined as:
// branch details in a table entry should be ordered from the highest windows compatability manifest version // that makes sense to the lowest. So the win10 branch first, then win8.1, then win8, etc // // You can skip any you'd like e.g. only have entries for Win10 then Win7 without any others typedef PVOID (NTAPI*pfnBranchFunc)(PVOID); typedef struct _SWITCHBRANCH_BRANCH_DETAILS { PCSTR pSpecificName; // the name of this branch pfnBranchFunc pBranch; ULONG unk; // always 1 // 4-byte paadding on x64 PCSTR pDescription; ULONG unk2; // ULONG unk3; // always 0 ULONG unk4; // always 1 ULONG unk5; // always 0 // the windows compatability guid specified in the manifest // that results in this branch being taken GUID windowsCompatGuid; // an id for this branch GUID branchGuid; } SWITCHBRANCH_BRANCH_DETAILS, *PSWITCHBRANCH_BRANCH_DETAILS; typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRY { PCSTR pBranchName; PCSTR pBranchDescription; PCSTR pBranchReason; ULONG unk; // always 1 ULONG unk2; // always 0 ULONG unk3; // always 0 ULONG unk4; // always 1 ULONG unk5; // always 0 GUID scenarioGuid; ULONG numScenarioBranches; SWITCHBRANCH_BRANCH_DETAILS branches[ANYSIZE_ARRAY]; // numScenarioBranches long } SWITCHBRANCH_SCENARIO_TABLE_ENTRY, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRY; typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRIES { ULONG numScenarios; SWITCHBRANCH_SCENARIO_TABLE_ENTRY* pEntries[ANYSIZE_ARRAY]; // numScenarios long } SWITCHBRANCH_SCENARIO_TABLE_ENTRIES, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRIES; typedef struct _SWITCHBRANCH_CACHED_MODULE_TABLE { ULONG64 changeCount; ULONG unk; ULONG numScenarios; PVOID pScenarios[ANYSIZE_ARRAY]; // numScenarios in size } SWITCHBRANCH_CACHED_MODULE_TABLE, *PSWITCHBRANCH_CACHED_MODULE_TABLE; typedef PVOID (WINAPI*pfnFilterFunc)(PVOID); typedef struct _SWITCHBRANCH_SCENARIO_TABLE { ULONG tag; // always 'EsLk', not ever checked even on checked builds ULONG unk; // Always 0x1000000 SWITCHBRANCH_CACHED_MODULE_TABLE* pModuleTable; PVOID unk2; // always 0 SWITCHBRANCH_SCENARIO_TABLE_ENTRIES* pScenarios; // this function probably has greater significance, but all occurances just return a string like // SbFilterProcedure_DdrawNamespace, // SbFilterProcedure_Scenario etc pfnFilterFunc filterProcedure; } SWITCHBRANCH_SCENARIO_TABLE, *PSWITCHBRANCH_SCENARIO_TABLE;
Example
// This example hardcodes two scenarios with two branches each // // It also demonstrates the complexities of using these functions // and the variable size arrays with static data // All uses of this in Windows' dll's use static data // so we are. Defining everything inline like this // and using hardcoded dimensions for the variable sized // arrays are the only way to make this compile #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x0600 #include#include typedef PVOID (NTAPI*pfnBranchFunc)(PVOID); // these are the compatibility manifest guids // {e2011457-1546-43c5-a5fe-008deee3d3f0} // DEFINE_GUID(COMPAT_Vista, 0xe2011457, 0x1546, 0x43c5, 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0); #define COMPAT_Vista {{0xe2011457}, {0x1546}, {0x43c5}, {0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0}} // {35138b9a-5d96-4fbd-8e2d-a2440225f93a} // DEFINE_GUID(COMPAT_Win7, 0x35138b9a, 0x5d96, 0x4fbd, 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a); #define COMPAT_Win7 {{0x35138b9a}, {0x5d96}, {0x4fbd}, {0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a}} // {4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38} // DEFINE_GUID(COMPAT_Win8, 0x4a2f28e3, 0x53b9, 0x4441, 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38); #define COMPAT_Win8 {{0x4a2f28e3}, {0x53b9}, {0x4441}, {0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38}} // {1f676c76-80e1-4239-95bb-83d0f6d0da78} // DEFINE_GUID(COMPAT_Win81, 0x1f676c76, 0x80e1, 0x4239, 0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78); #define COMPAT_Win81 {{0x1f676c76}, {0x80e1}, {0x4239}, {0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78}} // {8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a} // DEFINE_GUID(COMPAT_Win10, 0x8e0f7a12, 0xbfb3, 0x4fe8, 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a); #define COMPAT_Win10 {{0x8e0f7a12}, {0xbfb3}, {0x4fe8}, {0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a}} // branch details should be ordered from the highest windows compatability manifest version that makes sense // to the lowest. So the win10 branch first, then win8.1, then win8, etc typedef struct _SWITCHBRANCH_BRANCH_DETAILS { PCSTR pSpecificName; pfnBranchFunc pBranch; ULONG unk; // always 1 (enabled?) // ULONG x64 padding PCSTR pDescription; ULONG unk2; ULONG unk3; // always 0 ULONG unk4; // always 1 ULONG unk5; // always 0 // the windows compatability guid specified in the manifest // that results in this branch being taken GUID windowsCompatGuid; GUID branchGuid; } SWITCHBRANCH_BRANCH_DETAILS, *PSWITCHBRANCH_BRANCH_DETAILS; typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRY { PCSTR pBranchName; PCSTR pBranchDescription; PCSTR pBranchReason; ULONG unk; // always 1 ULONG unk2; // always 0 ULONG unk3; // always 0 ULONG unk4; // always 1 ULONG unk5; // always 0 GUID scenarioGuid; ULONG numScenarioBranches; SWITCHBRANCH_BRANCH_DETAILS branches[2]; // numScenarioBranches long } SWITCHBRANCH_SCENARIO_TABLE_ENTRY, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRY; //typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRIES //{ // ULONG numScenarios; // SWITCHBRANCH_SCENARIO_TABLE_ENTRY entries[2]; //} SWITCHBRANCH_SCENARIO_TABLE_ENTRIES, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRIES; typedef struct _SWITCHBRANCH_SCENARIO_TABLE_ENTRIES { ULONG numScenarios; SWITCHBRANCH_SCENARIO_TABLE_ENTRY* pEntries[2]; } SWITCHBRANCH_SCENARIO_TABLE_ENTRIES, *PSWITCHBRANCH_SCENARIO_TABLE_ENTRIES; typedef struct _SWITCHBRANCH_CACHED_MODULE_TABLE { ULONG64 changeCount; ULONG unk; ULONG numScenarios; PVOID pScenarios[2]; // numScenarios in size } SWITCHBRANCH_CACHED_MODULE_TABLE, *PSWITCHBRANCH_CACHED_MODULE_TABLE; typedef PVOID (NTAPI*pfnFilterFunc)(PVOID); typedef struct _SWITCHBRANCH_SCENARIO_TABLE { ULONG tag; // always 'EsLk' ULONG unk; // version? Always 0x1000000 SWITCHBRANCH_CACHED_MODULE_TABLE* pModuleTable; PVOID unk2; // always 0 SWITCHBRANCH_SCENARIO_TABLE_ENTRIES* pScenarios; // this function probably has greater significance, but all occurances just return a string like // SbFilterProcedure_DdrawNamespace, // SbFilterProcedure_Scenario etc pfnFilterFunc filterProcedure; } SWITCHBRANCH_SCENARIO_TABLE, *PSWITCHBRANCH_SCENARIO_TABLE; #ifdef __cplusplus extern "C" { #endif NTSYSAPI FARPROC //returns which function should be called NTAPI SbSelectProcedure( ULONG signature, // always 0xABABABAB ULONG p2, // always 1 const SWITCHBRANCH_SCENARIO_TABLE* pScenarioInfo, ULONG scenarioEntry // which scenario in the table the selection is for ); NTSYSAPI PVOID //returns the return value of the called function NTAPI SbExecuteProcedure( ULONG signature, // always 0xABABABAB ULONG p2, // always 1 const SWITCHBRANCH_SCENARIO_TABLE* pScenarioInfo, ULONG scenarioEntry, // which scenario in the table the selection is for PVOID pCtx // value passed to the selected procedure ); #ifdef __cplusplus } #endif // {17E5E81C-7D73-485b-9E8F-A3B2BB38594C} // DEFINE_GUID(GUID_NumberScenario, 0x17e5e81c, 0x7d73, 0x485b, 0x9e, 0x8f, 0xa3, 0xb2, 0xbb, 0x38, 0x59, 0x4c); #define GUID_NumberScenario {{0x17e5e81c}, {0x7d73}, {0x485b}, {0x9e, 0x8f, 0xa3, 0xb2, 0xbb, 0x38, 0x59, 0x4c}} // {DC7DA31C-EEF6-4310-8514-5367D3742EAD} // DEFINE_GUID(GUID_WordScenario, 0xdc7da31c, 0xeef6, 0x4310, 0x85, 0x14, 0x53, 0x67, 0xd3, 0x74, 0x2e, 0xad); #define GUID_WordScenario {{0xdc7da31c}, {0xeef6}, {0x4310}, {0x85, 0x14, 0x53, 0x67, 0xd3, 0x74, 0x2e, 0xad}} // {E70DA35B-C0D3-4496-A93B-7DCB20377E6A} // DEFINE_GUID(BRANCH_NumVista, 0xe70da35b, 0xc0d3, 0x4496, 0xa9, 0x3b, 0x7d, 0xcb, 0x20, 0x37, 0x7e, 0x6a); #define BRANCH_NumVista {{0xe70da35b}, {0xc0d3}, {0x4496}, {0xa9, 0x3b, 0x7d, 0xcb, 0x20, 0x37, 0x7e, 0x6a}} // {2082D2B2-E758-48e8-9F2A-974D4753F04C} // DEFINE_GUID(BRANCH_Num7, 0x2082d2b2, 0xe758, 0x48e8, 0x9f, 0x2a, 0x97, 0x4d, 0x47, 0x53, 0xf0, 0x4c); #define BRANCH_Num7 {{0x2082d2b2}, {0xe758}, {0x48e8}, {0x9f, 0x2a, 0x97, 0x4d, 0x47, 0x53, 0xf0, 0x4c}} // {FABAB681-60F4-4cd7-A405-6126F4CFA49B} // DEFINE_GUID(BRANCH_WordVista, 0xfabab681, 0x60f4, 0x4cd7, 0xa4, 0x5, 0x61, 0x26, 0xf4, 0xcf, 0xa4, 0x9b); #define BRANCH_WordVista {{0xfabab681}, {0x60f4}, {0x4cd7}, {0xa4, 0x5, 0x61, 0x26, 0xf4, 0xcf, 0xa4, 0x9b}} // {AE6D3F34-DA55-4470-AA72-29DEE48C9AF9} // DEFINE_GUID(BRANCH_Word7, 0xae6d3f34, 0xda55, 0x4470, 0xaa, 0x72, 0x29, 0xde, 0xe4, 0x8c, 0x9a, 0xf9); #define BRANCH_Word7 {{0xae6d3f34}, {0xda55}, {0x4470}, {0xaa, 0x72, 0x29, 0xde, 0xe4, 0x8c, 0x9a, 0xf9}} PVOID NTAPI NumBranchForVista(PVOID); PVOID NTAPI NumBranchFor7(PVOID); PVOID NTAPI WordBranchForVista(PVOID); PVOID NTAPI WordBranchFor7(PVOID); #define NUM_BRANCH_DETAIL_VISTA {"Vista Num Branch", &NumBranchForVista, 0, "Sets the flag to 0, because we hate Vista", 1, 0, 1, 0, COMPAT_Vista, BRANCH_NumVista} #define NUM_BRANCH_DETAIL_7 {"7 Num Branch", &NumBranchFor7, 0, "Sets the flag to 1, because we like 7", 1, 0, 1, 0, COMPAT_Win7, BRANCH_Num7} #define WORD_BRANCH_DETAIL_VISTA {"Vista Word Branch", &WordBranchForVista, 0, "Sets the word to No, because we hate Vista", 1, 0, 1, 0, COMPAT_Vista, BRANCH_WordVista} #define WORD_BRANCH_DETAIL_7 {"7 Word Branch", &WordBranchFor7, 1, "Sets the word to Yes, because we like 7", 1, 0, 1, 0, COMPAT_Win7, BRANCH_Word7} #define DIFF_NUM_SCENARIO \ { \ "DiffNumPrinter", \ "Will we print 4 or 5?", \ "Just because", \ 1, 0, 0, 1, 0, \ GUID_NumberScenario, \ 2, \ { \ NUM_BRANCH_DETAIL_7, \ NUM_BRANCH_DETAIL_VISTA \ } \ } #define DIFF_WORD_SCENARIO \ { \ "YesNoPrinter", \ "Will we say yes or no?", \ "Just because", \ 1, 0, 0, 1, 0, \ GUID_WordScenario, \ 2, \ { \ WORD_BRANCH_DETAIL_7, \ WORD_BRANCH_DETAIL_VISTA \ } \ } SWITCHBRANCH_SCENARIO_TABLE_ENTRY g_numEntry = DIFF_NUM_SCENARIO; SWITCHBRANCH_SCENARIO_TABLE_ENTRY g_wordEntry = DIFF_WORD_SCENARIO; enum ScenarioId { NumScenario, WordScenario }; SWITCHBRANCH_SCENARIO_TABLE_ENTRIES g_scenarios = { 2, { &g_numEntry, &g_wordEntry } }; SWITCHBRANCH_CACHED_MODULE_TABLE g_moduleTable = { 0ULL, 0, 2, {NULL, NULL} }; PVOID NTAPI ScenarioFilter(PVOID) { return "MySampleScenarios"; } const SWITCHBRANCH_SCENARIO_TABLE g_scenarioInfo = { 'EsLk', 0x01000000, &g_moduleTable, NULL, &g_scenarios, &ScenarioFilter }; // This is how the branch functions are coded // in the kernel32.dll/ddraw.dll etc PVOID NTAPI NumBranchForVista(PVOID p) { int* pFlag = (int*)p; *pFlag = 0; return p; } PVOID NTAPI NumBranchFor7(PVOID p) { int* pFlag = (int*)p; *pFlag = 1; return p; } PVOID NTAPI WordBranchForVista(PVOID p) { const char** ppWord = (const char**)p; *ppWord = "No"; return p; } PVOID NTAPI WordBranchFor7(PVOID p) { const char** ppWord = (const char**)p; *ppWord = "Yes"; return p; } // If you compile this and use a manifest with only Vista as a supported OS // or no supportedOS guids at all, it'll print the Vista values // If you then add a Windows 7 supportedOS and run it again // it'll print the 7 values int __cdecl wmain(int argc, wchar_t** argv) { int flag = -1; const char* pAnswer = NULL. pRet = NULL; pfnBranchFunc pBranchFunc = (pfnBranchFunc)SbSelectProcedure(0xABABABAB, 1, &g_scenarioInfo, NumScenario); pBranchFunc(&flag); printf("Thanks to the version manifesting, we're printing %d\n", 4 + flag); pRet = (const char*)SbExecuteProcedure(0, 1, &g_scenarioInfo, WordScenario, &pAnswer); printf("Thanks to the version manifesting, the answer to \"Do we like this OS?\" is %s\n", pAnswer); return 0;