void CPimcManager::LoadWisptis()
// NOTE: PenIMC has duplicated the code for loading wisptis from InkObj.
// Whenever WIC team makes any changes, we should coordinate with them to work on fixes.
// DDVSO 144719. There are some scenarios were we must skip loading wisptis since
// they are not supported and can cause delays or crashes.
// we do this to signal TabSvc that it needs to spin up wisptis
// so that it is at the right IL.
HANDLE hEventRequest = OpenEvent(EVENT_MODIFY_STATE, FALSE, PENPROCESS_WISPTIS_REQUEST_EVENT);
HANDLE hEventRunning = OpenEvent(SYNCHRONIZE, FALSE, PENPROCESS_WISPTIS_RUNNING_EVENT);
//if we don't have the event (TabSvc isn't running), or we timed out,
// that means Wisptis isn't running, so we'll start it; we do this via
// ShellExecute so that it gets started at high-IL (as indicated by
// Wisptis's manifest) to avoid IL-mismatch issues
//we allow wisptis to be started without TabSvc for backcompat
if(hEventRunning == NULL)
// create the event since TabSvc isn't running
hEventRunning = CreateEvent(NULL, TRUE, FALSE, PENPROCESS_WISPTIS_RUNNING_EVENT);
if(hEventRequest != NULL && hEventRunning != NULL)
//when this wait returns, wisptis will have registered its classes with COM
//if this fails or times out, we'll risk starting wisptis at a mismatched IL
DWORD dwResult = SignalObjectAndWait(hEventRequest, hEventRunning, 30000 /* thirty seconds */, FALSE);
hr = dwResult == WAIT_OBJECT_0 ? S_OK : E_FAIL;
// Since hEventRequest is no longer of use at this point, close the handle.
SafeCloseHandle(&hEventRequest);
if(/* wait timed out */ FAILED(hr) ||
/* couldn't open the event for some reason */ hEventRunning == NULL ||
/* wisptis isn't already running */ WaitForSingleObject(hEventRunning, 0) == WAIT_TIMEOUT)
LPFNWOW64DISABLEWOW64FSREDIRECTION fnWow64DisableWow64FsRedirection = NULL;
LPFNWOW64REVERTWOW64FSREDIRECTION fnWow64RevertWow64FsRedirection = NULL;
HMODULE hKernel32 = NULL;
// Check whether this is running under Wow64 and, if so, disable file system redirection
// on the current thread - otherwise it will look for wisptis in the syswow64 directory
TPDBG_VERIFY(IsWow64Process(GetCurrentProcess(),&bIsWow64));
// NOTICE-2006/06/13-WAYNEZEN,
// Since penimc may also run on the top of XPSP2, We cannot call Wow64DisableWow64FsRedirection/Wow64RevertWow64FsRedirection
// directly. Otherwise it will cause Entry Point Not Found error even though we don't really on those functions on 32-bit XP.
// So we have to use GetProcAddress to resovle the function address dynamically.
hKernel32 = GetModuleHandle(KERNEL32_NAME);
fnWow64DisableWow64FsRedirection = (LPFNWOW64DISABLEWOW64FSREDIRECTION)GetProcAddress(
hKernel32, WOW64DISABLEWOW64FSREDIRECTION_NAME);
fnWow64RevertWow64FsRedirection = (LPFNWOW64REVERTWOW64FSREDIRECTION)GetProcAddress(
hKernel32, WOW64REVERTWOW64FSREDIRECTION_NAME);
TPDBG_VERIFY(fnWow64DisableWow64FsRedirection(&pvOldValue));
SHELLEXECUTEINFO sei = {0};
sei.cbSize = sizeof(sei);
sei.lpFile = WISPTIS_DIR WISPTIS_NAME;
sei.lpParameters = WISPTIS_MANUAL_LAUNCH;
sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI;
sei.lpDirectory = WISPTIS_DIR;
sei.hInstApp = (HINSTANCE)0;
BOOL bResult = ShellExecuteEx(&sei);
// Restore the file system redirection settings.
TPDBG_VERIFY(fnWow64RevertWow64FsRedirection(pvOldValue));
hr = bResult ? S_OK : E_FAIL;
OutputDebugString(L"PimcManager::LoadWisptis failed to ShellExecuteEx.\r\n");
if(SUCCEEDED(hr) && hEventRunning != NULL)
(void)WaitForSingleObject(hEventRunning, PENPROCESS_WISPTIS_LOADING_TIMEOUT /* 30 seconds */);
//regardless of the return from this, we'll still try to spin wisptis up via COM
SafeCloseHandle(&hEventRunning);
CHR(m_pMgrS.CoCreateInstance(CLSID_TabletManagerS)); //, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER));
// Ensure the WISP tablet manager is added to the GIT.
m_wispManagerLock = GitComLockableWrapper<ITabletManager>(m_pMgrS, ComApartmentVerifier::Mta());
CHR(m_wispManagerLock.CheckCookie());