Home > Articles > Home & Office Computing > Microsoft Windows Desktop

📄 Contents

  1. Applications
  2. Single-Instance Applications
  3. Where Are We?
This chapter is from the book

Single-Instance Applications

By default, each EXE is an application that has an independent lifetime, even if multiple instances of the same application are running at the same time. However, it’s common to want to limit an EXE to a single instance, whether it’s an SDI application with a single top-level window, an MDI application, or an SDI application with multiple top-level windows. All these kinds of applications require that another instance detect the initial instance and then cut its own lifetime short.

Single-Instance Detection and Management

You could build a custom single-instance application using custom code that incorporates threading and .NET remoting. However, the VB.NET runtime library, Microsoft. VisualBasic.dll, contains a class that provides such an implementation for you: WindowsFormsApplicationBase, located in the Microsoft.VisualBasic.ApplicationServices namespace.5 WindowsFormsApplicationBase does not inherit from the Application class in System.Windows.Forms, but WindowsFormsApplicationBase is designed to replace the use of the Application class to run and manage an application’s lifetime, as you’ll see shortly.

If you are using C#, you add a reference to this assembly by right-clicking the project and selecting Add Reference from the context menu. From the .NET tab of the subsequently loaded Add Reference dialog, select Microsoft.VisualBasic.dll. When this DLL is referenced, you derive from WindowsFormsApplicationBase before extending your custom class with support for single-instance applications and passing command line arguments:

// SingleInstanceApplication.cs
using Microsoft.VisualBasic.ApplicationServices;
...
class SingleInstanceApplication : WindowsFormsApplicationBase {...}

Next, you configure SingleInstanceApplication to support single-instance applications. Set the SingleInstanceApplication class’s IsSingleInstance property (implemented by the base WindowsFormsApplicationBase class) to true:

// SingleInstanceApplication.cs
class SingleInstanceApplication : WindowsFormsApplicationBase {

 // Must call base constructor to ensure correct initial 
 // WindowsFormsApplicationBase configuration
 public SingleInstanceApplication() {

  // This ensures the underlying single-SDI framework is employed, 
  // and OnStartupNextInstance is fired
  this.IsSingleInstance = true;
 }
}

IsSingleInstance is false by default, and the constructor is a great place to change this situation. To incorporate this into your application, replace the standard application start-up logic from your application’s entry point. Then, use the following code to create an instance of your custom WindowsFormsApplicationBase type:

// Program.cs
static class Program {
 [STAThread]
 static void Main(string[] args) {
  Application.EnableVisualStyles();
  SingleInstanceApplication application = 
   new SingleInstanceApplication();
  application.Run(args);
 }
}

WindowsFormsApplicationBase exposes the Run method—the Application.Run method analog—which you invoke to open the main application form. Additionally, WindowsFormsApplicationBase.Run expects a string array containing command line arguments; passing null causes an exception to be thrown.

To specify which form is the main application form, you override WindowsFormsApplicationBase.OnCreateMainForm and set WindowsFormsApplicationBase.MainForm appropriately:

// SingleInstanceApplication.cs
class SingleInstanceApplication : WindowsFormsApplicationBase {
 ...
 protected override void OnCreateMainForm() {
  this.MainForm = new MainForm();
 }
}

As a final flourish, you can expose your custom WindowsFormsApplicationBase type via a static instantiation-helper method and thereby cut down on client code:

// SingleInstanceApplication.cs
class SingleInstanceApplication : WindowsFormsApplicationBase {

 static SingleInstanceApplication application;
 internal static SingleInstanceApplication Application {
  get {
   if( application == null ) {
    application = new SingleInstanceApplication();
   }
   return application;
  }
 }
 ...
}

// Program.cs
static class Program {
 ...
 [STAThread]
 static void Main(string[] args) {
  Application.EnableVisualStyles();
  SingleInstanceApplication.Application.Run(args);
 }
}

The effect of SingleInstanceApplication is to restrict an application to only one instance, no matter how many times it is executed. This single-instance scheme works fine as is, but it works better when the first instance of the application has a need to get command line arguments from any subsequent instances. Multiple-SDI and single-MDI applications are examples of applications that use this kind of processing.

Multiple-SDI Applications

A multiple-SDI application has multiple windows for content, although each window is a top-level window. Internet Explorer and Office 2003 are popular examples of multiple-SDI applications.6 Figure 14.4 shows an example of a multiple-SDI application.

Figure 14.4

Figure 14.4 A Sample Multiple-SDI Application

A multiple-SDI application typically has the following features:

  • A single instance of the application is running.
  • Multiple top-level windows are running independently of each other.
  • It doesn’t reopen files that are currently loaded.
  • When the last window goes away, the application does, too.
  • A Window menu allows a user to see and select from the currently available windows.

When a document is created or opened, it is loaded into a new window each time, whether the file was requested via the menu system or the command line. The first time the application is called, the first new instance of the top-level form is created and set as the main application form instance; if a file was requested, it is also opened by the form.

Subsequent requests to the application are routed to the custom WindowsFormsApplicationBase object located in the already-running application instance. Each request is handled to create a new form and build up the appropriate menu structures to support navigation between top-level instances, as well as opening and closing existing top-level instances. Figure 14.5 illustrates the work flow.

Figure 14.5

Figure 14.5 Work Flow of a Multiple-SDI Application with Support for Command Line Argument Passing

Multiple SDI requires single-instance support, which we acquire by deriving from WindowsFormsApplicationBase, as you saw earlier. We also need to ensure that the application stops running only after all top-level forms have been closed. We make the appropriate configurations from the constructor of the custom WindowsFormsApplicationBase class:

// MultiSDIApplication.cs
class MultiSDIApplication : WindowsFormsApplicationBase {

 static MultiSDIApplication application;
 internal static MultiSDIApplication Application {
  get {
   if( application == null ) {
    application = new MultiSDIApplication();
   }
   return application;
  }
 }
 public MultiSDIApplication() {
 
  // This ensures the underlying single-SDI framework is employed, 
  // and OnStartupNextInstance is fired
  this.IsSingleInstance = true;

  // Needed for multiple SDI because no form is the main form
  this.ShutdownStyle = ShutdownMode.AfterAllFormsClose;
 }
}

By default, the ShutdownStyle for a WindowsFormsApplicationBase object is AfterMainFormCloses, which refers to the form specified as the main form. However, with a multiple-instance SDI application, no form is the main form; therefore, no matter which form was created first, we want the application to close only after the last remaining top-level form is closed, and hence the need to explicitly set ShutdownStyle to AfterAllFormsClose.

Next, MultiSDIApplication must handle the first execution of the application. It does this by overriding OnCreateMainForm to create a new TopLevelForm object:

// MultiSDIApplication.cs
class MultiSDIApplication : WindowsFormsApplicationBase {
 ...
 public MultiSDIApplication() {...}

 // Create first top-level form
 protected override void OnCreateMainForm() {
  this.MainForm = this.CreateTopLevelWindow(this.CommandLineArgs);
 }

 TopLevelForm CreateTopLevelWindow(
  ReadOnlyCollection<string> args) {
  // Get file name, if provided
  string fileName = (args.Count > 0 ? args[0] : null);

  // Create a new top-level form
  return TopLevelForm.CreateTopLevelWindow(fileName);
 }
}

In this code, if a file argument was passed, a request is made to the main form to open it. Because all forms in a multiple-instance SDI application are top-level, however, no form is actually the main form. However, we must specify one if we override OnCreateMainForm, which helps later when the application needs to know which of the top-level forms is the active form. OnCreateMainForm passes the command line args—supplied by WindowsFormsApplicationBase.CommandLineArgs—to the helper Create TopLevelWindow method, which parses the args for a file name, passing whatever it finds to the static CreateTopLevelWindow method that’s implemented by TopLevelForm. CreateTopLevel Window is static because no specific form instance is responsible for creating another form.

To cope with subsequent requests to launch the application, we again override OnStartup NextInstance:

// MultiSDIApplication.cs
class MultiSDIApplication : WindowsFormsApplicationBase {
 ...
 public MultiSDIApplication() {...}

 // Create first top-level form
 protected override void OnCreateMainForm() {...}

 // Create subsequent top-level form
 protected override void OnStartupNextInstance(
  StartupNextInstanceEventArgs e) {
  this.CreateTopLevelWindow(e.CommandLine);
 }

 TopLevelForm CreateTopLevelWindow(
  ReadOnlyCollection<string> args) {...}
}

Here, the helper CreateTopLevelWindow is again passed command line arguments and called upon to create a new top-level window, opening a file if necessary.

Multiple-instance SDI applications also allow files to be opened from existing top-level forms via the File | Open menu, something we implement using the same static Create TopLevelWindow method to open files from the command line:

// TopLevelForm.cs
partial class TopLevelForm : Form {
 ...
 string fileName;
 ...
 public static TopLevelForm CreateTopLevelWindow(string fileName) {  
  // Detect whether file is already open
  if( !string.IsNullOrEmpty(fileName) ) {
   foreach( TopLevelForm openForm in Application.OpenForms ) {
    if( string.Compare(openForm.FileName, fileName, true) == 0 ) {
     // Bring form to top
     openForm.Activate();
     return openForm;
    }
   }
  }
   
  // Create new top-level form and open file
  TopLevelForm form = new TopLevelForm();
  form.OpenFile(fileName);
  form.Show();
  // Bring form to top
  openForm.Activate();
  return form;
 }

 void openToolStripMenuItem_Click(object sender, EventArgs e) {
  // Open new window
  if( this.openFileDialog.ShowDialog() == DialogResult.OK ) {
   TopLevelForm.CreateTopLevelWindow(this.openFileDialog.FileName);
  }
 }
 ...
 void OpenFile(string fileName) {
  this.fileName = fileName;
  using( StreamReader reader = new StreamReader(fileName) ) {
   textBox.Text = reader.ReadToEnd();
  }
  this.Text = this.Text + " (" + this.fileName + ")";
 }

 string FileName {
  get { return this.fileName; }
 }
}

CreateTopLevelWindow contains the code to check whether the desired file is already opened and, if it is, to bring the top-level window that contains it to the foreground; otherwise, the file is opened into a new top-level window.

Multiple-instance SDI applications also typically allow the creation of new files from the command line or from the File | New Window menu of a currently open top-level form. We tweak the OpenFile method to not open a file if null or if an empty string was passed as the file name:

// TopLevelForm.cs
partial class TopLevelForm : Form {
 ...
 static int formCount = 0;
 
 public TopLevelForm() { 
  InitializeComponent();

  // Set form count
  ++formCount;
  this.Text += ": " + formCount.ToString();
 }
 ...
 public static TopLevelForm CreateTopLevelWindow(string fileName) {  
  ...
  // Create new top-level form and open file
  TopLevelForm form = new TopLevelForm();
  form.OpenFile(fileName);
  form.Show();
  ...
 }

 void newWindowToolStripMenuItem_Click(
  object sender, EventArgs e) {
  // Open new window
  TopLevelForm.CreateTopLevelWindow(null);
 }
 ...
 void OpenFile(string fileName) {
  this.fileName = fileName;
  if( !string.IsNullOrEmpty(fileName) ) {
   using( StreamReader reader = new StreamReader(fileName) ) {
    textBox.Text = reader.ReadToEnd();
   }
  }
  else this.fileName = "Untitled" + formCount.ToString();
  this.Text = this.Text + " (" + this.fileName + ")";
 }
 ...
}

Because a new file doesn’t have a name, the top-level form gives it one; the standard naming convention for a new file is the concatenation of some default text with a version number. In this example, we use a combination of "Untitled" and an incremental count of the number of opened top-level forms, for uniqueness.

As mentioned before, a multiple-SDI application should implement a menu that allows users to navigate between open top-level forms as this is easier when files have unique names. MultiSDIApplication is an appropriate location for this logic because it manages the application:

// MultiSDIApplication.cs
class MultiSDIApplication : WindowsFormsApplicationBase {
 ...
 public void AddTopLevelForm(Form form) {

  // Add form to collection of forms and
  // watch for it to activate and close
  form.Activated += Form_Activated;
  form.FormClosed += Form_FormClosed;

  // Set initial top-level form to activate
  if( this.OpenForms.Count == 1 ) this.MainForm = form;
 }

 void Form_Activated(object sender, EventArgs e) {
  // Set the currently active form
  this.MainForm = (Form)sender;
 }

 void Form_ FormClosed(object sender, FormClosedEventArgs e) {
  // Set a new "main" if necessary
  if( ((Form)sender == this.MainForm) && 
    (this.OpenForms.Count > 0) ) {
   this.MainForm = (Form)this.OpenForms[0];
  }

  form.Activated -= Form_Activated;
  form.FormClosed -= Form_FormClosed;
 }
}

The MultiSDIApplication class uses the AddTopLevelForm method to keep track of a list of top-level forms as they are added. Each new form is kept in a collection and is watched for Activated and FormClosed events. When a top-level form is activated, it becomes the new "main" form, which is the one whose closure is detected by the base ApplicationContext class. When a top-level form closes, it’s removed from the list. If the closed form was the main form, another form is promoted to that lofty position. When the last form goes away, the base ApplicationContext class notices and exits the application.

To keep the context up-to-date with the current list of top-level forms, the custom context watches for the Closed event on all forms. In addition, the custom context needs to be notified when a new top-level form has come into existence, a task that is best handled by the new form itself:

// TopLevelForm.cs
partial class TopLevelForm : Form {
 ...
 public TopLevelForm() { 
  ...
  // Add new top-level form to the application context
  MultiSDIApplication.Application.AddTopLevelForm(this);
  ... 
 }
 ...
}

The only remaining task is to designate and populate the Window menu with one menu item for each top-level form. The forms themselves can do this by handling the DropDownOpening event on the ToolStripMenuItem’s Window object, using that opportunity to build the list of submenu items based on the names of all the forms. However, this code is boilerplate, so it’s a good candidate to be handled by MultiSDIApplication on behalf of all top-level windows, from the AddWindowMenu method:

// MultiSDIApplication.cs
class MultiSDIApplication : WindowsFormsApplicationBase {
 ...
 public void AddWindowMenu(ToolStripMenuItem windowMenu) {
  // Handle tool strip menu item’s drop-down opening event
  windowMenu.DropDownOpening += windowMenu_DropDownOpening;
 }
}

Each top-level form with a Window menu can add it to the context, along with itself, when it’s created:

// TopLevelForm.cs
partial class TopLevelForm : Form {
 ...
 public TopLevelForm() { 
  ...
  // Add Window ToolStripMenuItem to the application context
  MultiSDIApplication.Application.AddWindowMenu(
   this.windowToolStripMenuItem);
  ...
 }
 ...
}

Now, when the Window menu is shown on any top-level window, the DropDownOpening event fires. This constructs a new menu showing the currently open top-level forms during the time gap between mouse click and menu display:

// MultiSDIApplication.cs
class MultiSDIApplication : WindowsFormsApplicationBase {
 ...
 void windowMenu_DropDownOpening(object sender, EventArgs e) {
  ToolStripMenuItem menu = (ToolStripMenuItem)sender;

  // Clear current menu
  if( menu.DropDownItems.Count > 0 ) {
   menu.DropDown.Dispose();
  }
  menu.DropDown = new ToolStripDropDown();

  // Populate menu with one item for each open top-level form
  foreach( Form form in this.OpenForms ) {
   ToolStripMenuItem item = new ToolStripMenuItem();
   item.Text = form.Text;
   item.Tag = form;
   menu.DropDownItems.Add(item);
   item.Click += WindowMenuItem_Click;

   // Check menu item that represents currently active window
   if( form == this.MainForm ) item.Checked = true;
  }
 }
}

As each menu item is added to the Window menu, a handler is added to the Click event so that the appropriate form can be activated when it’s selected. The form associated with the ToolStripMenuItem’s Tag property is extracted and activated:

// MultiSDIApplication.cs
class MultiSDIApplication : WindowsFormsApplicationBase {
 ...
 void WindowMenuItem_Click(object sender, EventArgs e) {
  // Activate top-level form based on selection
  ((Form)((ToolStripMenuItem)sender).Tag).Activate();
 }
 ...
}

That’s it. The extensible lifetime management of Windows Forms applications via a custom application context, along with a helper to find and activate application instances already running, provides all the help we need to build a multiple-SDI application in only a few lines of code. The result is shown in Figure 14.6.

Figure 14.6

Figure 14.6 Multiple-Instance SDI Application in Action

Multiple-SDI applications share much in common with MDI applications, although each document in an MDI application is loaded into a child window rather than a new main window. The key similarities include the requirement for MDI applications to be managed from a single executable and the ability to handle command line parameters.

Single-MDI Applications

Consider an MDI application like Microsoft Excel; files opened from the file system (by double-clicking) are all opened as separate child windows within the parent Excel window.7 For the first instance of an MDI application to open a new child window to display the file that was passed to the second instance of the application, the second instance must be able to communicate with the initial instance.

A single-MDI application exhibits the characteristics we described in Chapter 2: Forms, as well as the following features:

  • A single instance of the application is running.
  • Multiple MDI child windows are running within the same MDI parent window.
  • Currently opened files are not reopened.
  • When the last MDI child window goes away, the application remains.
  • When the MDI parent window goes away, the application exits.
  • A Window menu allows a user to see and select from the currently available windows.

The work flow for a single-MDI application ensures that a new MDI child form is opened each time the application is called, whether or not a file was requested for opening.

The first time the application is called, the MDI parent is created and set as the main application form instance; if a file was requested, it is also opened into a new MDI child form. Subsequent requests to the application are routed through the MDI parent form to create a new MDI child form and build up the appropriate menu structures to support navigation between top-level instances, as well as opening and closing existing top-level instances. Figure 14.7 illustrates the work flow.

Figure 14.7

Figure 14.7 Work Flow of a Single-MDI Application with Support for Passing Command Line Arguments

With WindowsFormsApplicationBase ensuring that only one instance of the application executes, we need to handle two specific scenarios: first, when arguments are passed from the command line directly when the first instance loads and, second, when the first instance is passed command line arguments from a second instance.

Handling the first scenario requires a main application form that’s an MDI parent and can open a new or existing file into an MDI child form:

// MDIParentForm.cs
partial class MDIParentForm : Form {
 ...
 // This is necessary to bring the MDI parent window to the front,
 // because Activate and BringToFront don’t seem to have any effect.
 [DllImport("user32.dll")]
 static extern bool SetForegroundWindow(IntPtr hWnd);
 
 public void CreateMDIChildWindow(string fileName) {

  SetForegroundWindow(this.Handle);
   
  // Detect whether file is already open
  if( !string.IsNullOrEmpty(fileName) ) {
   foreach( MDIChildForm openForm in this.MdiChildren ) {
    if( string.Compare(openForm.FileName, fileName, true) == 0 ) {
     openForm.Activate();
     return;
    }
   }
  }

  // If file not open, open it
  MDIChildForm form = new MDIChildForm();
  form.OpenFile(fileName);
  form.MdiParent = this;
  form.Show();
 }

 void newToolStripMenuItem_Click(object sender, EventArgs e) {
  this.CreateMDIChildWindow(null);
 }

 void openToolStripMenuItem_Click(object sender, EventArgs e) {
  if( this.openFileDialog.ShowDialog() == DialogResult.OK ) {
   this.CreateMDIChildWindow(this.openFileDialog.FileName);
  }
 }
 ...
}

This code allows users to open a file using a menu strip item, and it lays the foundation for opening a file from the command line, including preventing the reopening of an already open file. We continue using WindowsFormsApplicationBase to achieve this, updating the earlier sample to acquire the command line arguments and pass them to the application main form’s CreateMDIChildWindow method to open a file:

// SingleMDIApplication.cs
class SingleMDIApplication : WindowsFormsApplicationBase {

 static SingleMDIApplication application;
 internal static SingleMDIApplication Application {
  get {
   if( application == null ) {
    application = new SingleMDIApplication();
   }
   return application;
  }
 }

 public SingleMDIApplication() {
  // This ensures the underlying single-SDI framework is employed, 
  // and OnStartupNextInstance is fired
  this.IsSingleInstance = true;
 }

 // Load MDI parent form and first MDI child form
 protected override void OnCreateMainForm() {
  this.MainForm = new MDIParentForm();
  this.CreateMDIChildWindow(this.CommandLineArgs);
 }

 void CreateMDIChildWindow(ReadOnlyCollection<string> args) {
  // Get file name, if provided
  string fileName = (args.Count > 0 ? args[0] : null);
  
  // Ask MDI parent to create a new MDI child 
  // and open file
  ((MDIParentForm)this.MainForm).CreateMDIChildWindow(fileName);
 }
}

During construction, we specify that this application is a single-instance application. Unlike with multiple-SDI applications, however, we don’t need to set the ShutdownStyle property because its value defaults to AfterMainFormCloses—exactly what is needed for an MDI application.

OnCreateMainForm creates the MDI parent form and sets it as the application’s main form and the one responsible for creating MDI child windows. Then, the command line arguments are passed to the helper CreateMDIChildWindow method, which parses them for a file name. Either a file name or null is passed to the MDI parent form’s version of CreateMDIChildWindow, which creates the new MDI child window, into which it loads a file; then CreateMDIChildWindow establishes the MDI parent-child relationship and shows the requested file. CreateMDIChildWindow also activates the MDI parent form to bring the application to the foreground.

In the second scenario, the desired processing is for the command line arguments to be passed from the second instance to the first, to which the first instance responds by processing the command line arguments and, if required, creating a new MDI child form. WindowsFormsApplicationBase handles the underlying mechanics of passing arguments from the second instance to the first, but it is up to you to process the command line arguments accordingly. You can achieve this by overriding WindowsFormsApplicationBase.OnStartupNextInstance, which passes the command line arguments via the CommandLine property of a StartupNextInstanceEventArgs object. The following code shows the OnStartupNextInstance override implementation:

// SingleMDIApplication.cs
class SingleMDIApplication : WindowsFormsApplicationBase {
 ...
 // Must call base constructor to ensure correct initial 
 // WindowsFormsApplicationBase configuration
 public SingleMDIApplication() {...}

 // Load MDI parent form and first MDI child form
 protected override void OnCreateMainForm() {...}

 // Load subsequent MDI child form
 protected override void OnStartupNextInstance(
  StartupNextInstanceEventArgs e) {
  this.CreateMDIChildWindow (e.CommandLine);
 }

 void CreateMDIChildWindow(ReadOnlyCollection<string> args) {...}
}

As you can see, centralizing CreateMDIChildWindow into a single helper method greatly simplifies the implementation of OnStartupNextInstance.

That’s the complete solution, so let’s look at how it operates. Suppose we start the application for the first time by executing the following statement from the command line:

C:\SingleInstanceSample.exe C:\file1.txt

The result is to load the application, configure the single-instance command line argument (passing support from our derivation of WindowsFormsApplicationBase), load the main MDI parent form, and, finally, open an MDI child form, displaying the file specified from the command line arguments. Figure 14.8 illustrates the result.

Figure 14.8

Figure 14.8 Result of Creating a First Instance of a Single-Instance Application

Now, consider the next statement being called while the first instance is still executing:

C:\SingleInstanceSample.exe C:\file2.txt

This time, a second instance of the application is created, but—thanks to SingleMDIApplication, our WindowsFormsApplicationBase derivation—the second instance passes its command line arguments to the first instance before closing itself down. The first instance processes the incoming command line arguments from OnStartupNextInstance, requesting the MDI parent form to open a new MDI child and display the specified file. The result is shown in Figure 14.9.

Figure 14.9

Figure 14.9 Result of Creating a Second Instance of a Single-Instance Application

Although it would be difficult to code single-instance applications such as single MDI and multiple SDI by hand, the presence of support in the Visual Basic runtime assembly makes life a lot easier. This is one of the strengths of Windows Forms; unlike forms packages of old, Windows Forms is only one part of a much larger, integrated whole. When its windowing classes don’t meet your needs, you still have all the rest of the .NET Framework Class Library to fall back on.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020