| Index: installer/src/installer-lib/test/test-installer-lib-ca.cpp | 
| =================================================================== | 
| new file mode 100644 | 
| --- /dev/null | 
| +++ b/installer/src/installer-lib/test/test-installer-lib-ca.cpp | 
| @@ -0,0 +1,71 @@ | 
| +/** | 
| + * \file abp_ca.cpp Top-level source for custom actions. Includes DLL initialization. | 
| + */ | 
| +#include "DLL.h" | 
| +#include <stdexcept> | 
| + | 
| +/** | 
| + * DllMain is the standard entry point call when the DLL is loaded or unloaded. | 
| + * | 
| + * \param[in] module_handle | 
| + *    Handle for this instance of the DLL; same as the module handle. | 
| + *    This handle allows us to get the DLL file name for logging. | 
| + * \param[in] reason | 
| + *    The point in the DLL life cycle at which this call is made. Called "reason code" by Microsoft. | 
| + * \param[in] reserved | 
| + *    No longer reserved, since it contains a point in the thread life cycle. | 
| + *    We aren't using it, though. | 
| + | 
| + * \sa { http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx } | 
| + * Documentation on DLL entry points in Windows. | 
| + */ | 
| +extern "C" BOOL WINAPI DllMain( | 
| +  IN HINSTANCE module_handle, | 
| +  IN ULONG reason, | 
| +  IN LPVOID reserved ) | 
| +{ | 
| +  /* | 
| +   * Because this is an external API, we must ensure that there is a catch-all block for each execution path. There are two of these below. | 
| +   */ | 
| +  switch ( reason ) | 
| +  { | 
| +  case DLL_PROCESS_ATTACH: | 
| +    try | 
| +    { | 
| +      DLL_Module::attach( module_handle ); | 
| +      return TRUE; | 
| +    } | 
| +    catch(...) | 
| +    { | 
| +      // We can't log to the installation log yet, and this couldn't shouldn't be executed except in rare cases such as out-of-memory. | 
| +      // Since it's a lot of code to do something useful (such as logging to the Windows system event log), we don't do anything but return a failure. | 
| +      return FALSE; | 
| +    } | 
| +    break; | 
| + | 
| +  case DLL_PROCESS_DETACH: | 
| +    try | 
| +    { | 
| +      DLL_Module::detach(); | 
| +      return TRUE; | 
| +    } | 
| +    catch(...) | 
| +    { | 
| +      // See comment above in parallel catch-block. | 
| +      return FALSE; | 
| +    } | 
| +    break; | 
| + | 
| +  /* | 
| +   * This entry point is called for each thread after the first in a process with this DLL loaded. Note "after the first". | 
| +   * The process life cycle is always called, and we do our global initialization there.  So even though this DLL | 
| +   * doesn't support asynchronous operation, this entry point gets called anyway. We need to ignore these calls. | 
| +   */ | 
| +  case DLL_THREAD_ATTACH: | 
| +  case DLL_THREAD_DETACH: | 
| +    return TRUE; | 
| + | 
| +  default: | 
| +    return FALSE; | 
| +  } | 
| +} | 
|  |