ShowTable of Contents
Introduction
Lotus Quickr connectors provide an easy way to contribute and access content. They are plug-ins into commonly used desktop applications such as Lotus Symphony
TM, Lotus Notes®, Lotus Sametime®, Microsoft Windows Explorer and Microsoft Office. Users can choose the suitable connector based on the desktop application they use most often in their routine work.
InstallShield is a software tool for creating installers or software packages. The qkrconn.exe file is an InstallShield-based Windows installer package, containing all the information that the Windows Installer requires to install or uninstall Lotus Quickr connectors and to run the setup user interface.
Comparing 32-bit Windows XP and 64-bit Windows 7
First let's discuss how the 32-bit Windows XP and 64-bit Windows 7 operating systems differ.
Compatibility
Nearly all 32-bit applications are able to run on 64-bit Windows. This allows both 32- and 64-bit versions of the same applications to be installed side-by-side on 64-bit Windows, without risk of overwriting one another’s files or inadvertently accessing the wrong versions of the same library.
Under 64-bit Windows, 32-bit applications run on top of an emulation of 32-bit Windows called Windows on Windows 64-bit (WOW64) as shown in figure 1. WOW64 intercepts all operating system calls made by a 32-bit application.
For each operating-system call made, WOW64 generates native 64-bit system calls, converting 32-bit data structures into 64-bit aligned structures. The appropriate native 64-bit system call is passed to the operating system kernel, and any output data from the 64-bit system call is translated into a format appropriate for the calling application before being passed back.
Figure 1. 32-bit application running on WOW64
Although it is possible for a 32-bit installer to run on 64-bit Windows, as a plug-in's installer, it is still not enough to support a 64-bit application without 64-bit versions of libraries. So, to support 64-bit applications with a 32-bit installer, the 32-bit and 64-bit versions of the same libraries must exist side-by-side in the same component of InstallShield. For qkrconn.exe, to support 64-bit Windows Explorer, the 64-bit DLLs should be included in it.
Registry
On 64-bit Windows, the Registry is divided into 32- and 64-bit keys. Many of the 32-bit keys have the same names as their 64-bit counterparts, and they are redirected from HKEY_LOCAL_MACHINE\Software to HKEY_LOCAL_MACHINE\Software\WOW6432Node.
WOW64 uses the Registry redirector to intercept 32- and 64-bit registry calls to their respective logical registry views and map them to the corresponding physical registry location.
For example, when you install Lotus Quickr connector on 64-bit Windows 7, the WOW64 intercepts registry calls to HKEY_LOCAL_MACHINE\Software that are made by qkrconn.exe, and then redirects them to the HKEY_LOCAL_MACHINE\Software\WOW6432node sub key. Registry calls won't be redirected if they are made by 64-bit applications accessing the HKEY_LOCAL_MACHINE\Software registry sub key.
File system
On 64-bit Windows, there are separate folders for program and operating-system files for 32- and 64-bit applications. The file system redirector ensures that requests from 32-bit applications to open files in C:\Program Files or C:\WINDOWS\SYSTEM32 are redirected to the appropriate 32-bit directories C:\Program Files(x86) and C:\WINDOWS\SysWOW64.
For Lotus Quickr connectors, the default installation path is "C:\Program Files (x86)\IBM\Places Connectors". Both 32- and 64-bit libraries are installed into this directory, and the Regsvr32.exe used by the qkrconn.exe is in "C:\WINDOWS\SysWOW64".
All these tasks are done transparently for 32-bit applications by WOW64, which, when intercepting calls to the operating system, detects references to file paths and registry keys, and maps them accordingly.
Access control
User Account Control (UAC) is another way in which Windows XP and Windows 7 differ. UAC aims to improve the security of Windows by limiting applications to standard user privileges until an administrator authorizes an increase or elevation. So there is an issue with administrator privileges of which developers should be aware, which we will discuss later.
Detecting the bitness of a Windows operating system
Since we have the 32- and 64-bit versions of the same libraries, we need to detect the bitness of Windows to determine which version of the DLLs should be registered or unregistered. Microsoft provides the method shown in listing 1.
Listing 1. Code to detect bitness
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
BOOL Is64BitOS() {
#if defined(_WIN64)
return TRUE; // 64-bit programs run only on Win64
#elif defined(_WIN32)
// 32-bit programs run on both 32-bit and 64-bit Windows
BOOL f64bitOS = FALSE;
return (SafeIsWow64Process(GetCurrentProcess(), &f64bitOS) && f64bitOS);
#else
return FALSE; // 64-bit Windows does not support Win16
#endif
}
BOOL WINAPI SafeIsWow64Process(HANDLE hProcess, PBOOL Wow64Process) {
if (fnIsWow64Process == NULL) {
HMODULE hModule = GetModuleHandle(L"kernel32.dll");
if (hModule == NULL) {
return FALSE;
}
fnIsWow64Process = reinterpret_cast<LPFN_ISWOW64PROCESS>(
GetProcAddress(hModule, "IsWow64Process"));
if (fnIsWow64Process == NULL) {
return FALSE;
}
}
return fnIsWow64Process(hProcess, Wow64Process);
}
Registering both 32- and 64-bit DLLs manually
If the 32-bit installer needs only to support 32-bit Windows, we can use the Self-Register property that is by provided InstallShield to register 32-bit DLLs automatically during installation. We don't need to write extra codes.
However, we cannot use the Self-Register property to register 64-bit DLLs, or else an error will occur during installation because the installer is 32-bit. For qkrconn.exe, if we use the Self-Register property, the error message in figure 2 will display during installation.
Figure 2. Error message when registering 64-bit DLL using Self-Register property
So we need register both 32- and 64-bit DLLs manually, meaning that we must use a command line in our code to register them. Regsvr32.exe is a command-line utility in Windows operating systems and is used to register and unregister DLLs and ActiveX controls in the Windows Registry.
We can use it to register or unregister applications; for example, use regsvr32 my_file.dll to register modules passed on the command line.
Also we could use Msiexec.exe to register or unregister DLLs. Msiexec.exe belongs to the Windows Installer and is used to interpret installation packages and install products on target systems. For example, msiexec /z my_file.dll is used to unregister modules passed on the command line.
There are two versions of Regsvr32.exe and Msiexec.exe. Files in the System32 folder are the 64-bit version, and the Syswow64 folder contains the 32-bit versions of Regsvr32.exe and Msiexec.exe.
For connectors, we use Regsvr32.exe to register or unregister our DLLs using the
ShellExecute function. Because of the WOW64, the Regsvr32.exe we use is a 32-bit version. The register code looks like this:
ShellExecute( handle, NULL, "regsvr32.exe", "/s my_file.dll", NULL, SW_SHOWNORMAL );
When we use Regsvr32.exe to register or unregister the DLL files, the Administrator privilege is needed; otherwise it will fail to register or unregister the DLLs (see figures 3 and 4).
Figure 3. Error when fail to register DLL file on Windows 7
Figure 4. Error when fail to register DLL file on Windows XP
To locate the DLL files and perform registration tasks with elevated privileges, we need to create a custom action in InstallShield for calling a registration function and schedule it as
Deferred Execution in System Context. It is a special sort of deferred custom action that is used to perform tasks with elevated privileges.
However, the deferred custom action runs in a separate process and only has access to some of the built-in Windows Installer properties, that is, CustomActionData, ProductCode, and UserSID. If we want a custom action to access any other properties, such as installdir, during deferred execution, we can pass them as CustomActionData by scheduling an immediate set-a-property type of custom action to set a property that matches the name of the custom action.
The value of this property is then available in the CustomActionData property within the deferred custom action. The registration function in Visual Studio would look like that shown in listing 2.
Listing 2. Code for registration function
APP_API APPRegisterDlls( MSIHANDLE hInstall ) {
TCHAR szPath[255];
TCHAR szDllToRegister[255];
DWORD cchPath = sizeof(szPath)/sizeof(TCHAR);
MsiGetCustomActionData(hInstall, TEXT("INSTALLDIR"), szPath, &cchPath);
BOOL Is64bit = Is64BitOS();
TCHAR *DLLName;
if(Is64bit==TRUE) {
DIViewName= L"my_file64.dll";
}else {
DIViewName= L"my_file.dll";
}
wsprintf(szDllToRegister,L"/s \"%s%s\"", szPath,DIViewName);
DWORD exRC = (DWORD)ShellExecute( HWND_DESKTOP, 0, L"regsvr32.exe", szDllToRegister, 0, SW_SHOWDEFAULT );
return ERROR_SUCCESS;
}
The MsiGetCustomActionData function is used to retrieve the INSTALLDIR that we set in the immediate custom action.
Unregistering DLLs when removing an application
Because we register both 32- and 64-bit DLLs manually, a problem due synchronous processes could occur when we use the
ShellExecute function to unregister DLLs directly when removing the application from Control Panel. Specifically, since the
ShellExecute function launches a new process to run the unregister command, the DLL files could be deleted before unregistering them.
To solve this problem, the main process needs to wait until the deferred custom action has finished running (see figure 5). So we use the
ShellExecuteEx and
WaitForSingleObject functions instead of the
ShellExecute function. The
WaitForSingleObject function lets the concurrent process wait until the specified object, such as Process, is in the signaled state.
Figure 5. Workflow between two processes
Listing 3 shows an example of this.
Listing 3. Example of WaitForSingleObject function
SHELLEXECUTEINFO ShExecInfo;
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = L"regsvr32.exe";
ShExecInfo.lpParameters = L"/s /u my_file.dll”;
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
We can also use the
CreateProcess function (see listing 4).
Listing 4. Example CreateProcess function
PROCESS_INFORMATION pi;
STARTUPINFO si;
// init the process parameters
ZeroMemory(&si, sizeof(si));
StartupInfo.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// start the process
CreateProcess("c:\\winnt\\notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
// close the handle
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
Retrieving process information from 64-bit Windows under WOW64
The usual way to retrieve the process information from a 32-bit Windows system is as follows:
- Get the list of process identifiers by using the EnumProcesses function.
- Call the OpenProcess function to obtain the process handle.
- Call the EnumProcessModules function to obtain the module handles.
- Call the GetModuleBaseName function to, for example, obtain the name of the executable file.
In our project, however, when we followed the above steps, the 32-bit installer failed to get process information from 64-bit Windows 7 because the
EnumProcessModules function doesn’t work on 64-bit windows.
Although the
EnumProcessModulesEx function can retrieve handles for modules on 64-bit Windows, it provides the same results as the
EnumProcessModules function if it is called by a 32-bit application running under WOW64.
There is still one way to retrieve process information when a 32-bit application is running under WOW64, and that is Windows Management Instrumentation (WMI). This WMI service provides the infrastructure for management data and operations on Windows-based operating systems and can be used in all Windows-based applications. For more information about creating applications for WMI, refer to the article, “
Getting WMI Data from the Local Computer.”
Conclusion
Although this article discusses only some of the points that must be addressed, our hope is that, by describing the more common scenarios, we have helped you understand how to best support 64-bit applications with 32-bit installer in your side.
Resources
Lotus Quickr Connectors product page:
http://www-01.ibm.com/software/lotus/products/quickr/connectors.html
MSDN article on WOW64, “Running 32-bit Applications:”
http://msdn.microsoft.com/en-us/library/aa384249(VS.85).aspx
MSDN article, “User Account Control:”
http://msdn.microsoft.com/en-us/library/aa511445.aspx
MSDN article, “Windows Management Instrumentation on WMI:”
http://msdn.microsoft.com/en-us/library/aa394582(v=vs.85).aspx
About the authors
De Liang Jiang is a member of the Lotus Connections Install team for Lotus Connections install development. You can reach him at
dljiang@cn.ibm.com.
Hao Jie Hang is a member of the Lotus Quickr connectors Install team for Team connectors install development. You can reach him at
hjhaojie@cn.ibm.com.
Hai Yang Liu is a member of the Lotus Quickr connectors Install team for Files connectors install development. You can reach him at
hiayangl@cn.ibm.com.