BOOL
pthread_win32_process_attach_np ()
{
  TCHAR QuserExDLLPathBuf[1024];
  BOOL result = TRUE;
  const UINT QuserExDLLPathBufSize = sizeof(QuserExDLLPathBuf) / sizeof(QuserExDLLPathBuf[0]);

  result = ptw32_processInitialize ();

#if defined(_UWIN)
  pthread_count++;
#endif

#if defined(__GNUC__)
  ptw32_features = 0;
#else
  /*
   * This is obsolete now.
   */
  ptw32_features = PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE;
#endif

  /*
   * Load QUSEREX.DLL and try to get address of QueueUserAPCEx.
   * Because QUSEREX.DLL requires a driver to be installed we will
   * assume the DLL is in the system directory.
   *
   * This should take care of any security issues.
   */
#if defined(__GNUC__) || defined(PTW32_CONFIG_MSVC7)
  if(GetSystemDirectory(QuserExDLLPathBuf, QuserExDLLPathBufSize))
  {
    (void) strncat(QuserExDLLPathBuf,
                   "\\QUSEREX.DLL",
                   QuserExDLLPathBufSize - strlen(QuserExDLLPathBuf) - 1);
    ptw32_h_quserex = LoadLibrary(QuserExDLLPathBuf);
  }
#else
  /* strncat is secure - this is just to avoid a warning */
  if(GetSystemDirectory(QuserExDLLPathBuf, QuserExDLLPathBufSize) &&
     0 == _tcsncat_s(QuserExDLLPathBuf, QuserExDLLPathBufSize, _T("\\QUSEREX.DLL"), 12))
  {
    ptw32_h_quserex = LoadLibrary(QuserExDLLPathBuf);
  }
#endif

  if (ptw32_h_quserex != NULL)
    {
      ptw32_register_cancellation = (DWORD (*)(PAPCFUNC, HANDLE, DWORD))
#if defined(NEED_UNICODE_CONSTS)
	GetProcAddress (ptw32_h_quserex,
			(const TCHAR *) TEXT ("QueueUserAPCEx"));
#else
	GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx");
#endif
    }

  if (NULL == ptw32_register_cancellation)
    {
      ptw32_register_cancellation = ptw32_Registercancellation;

      if (ptw32_h_quserex != NULL)
	{
	  (void) FreeLibrary (ptw32_h_quserex);
	}
      ptw32_h_quserex = 0;
    }
  else
    {
      /* Initialise QueueUserAPCEx */
      BOOL (*queue_user_apc_ex_init) (VOID);

      queue_user_apc_ex_init = (BOOL (*)(VOID))
#if defined(NEED_UNICODE_CONSTS)
	GetProcAddress (ptw32_h_quserex,
			(const TCHAR *) TEXT ("QueueUserAPCEx_Init"));
#else
	GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Init");
#endif

      if (queue_user_apc_ex_init == NULL || !queue_user_apc_ex_init ())
	{
	  ptw32_register_cancellation = ptw32_Registercancellation;

	  (void) FreeLibrary (ptw32_h_quserex);
	  ptw32_h_quserex = 0;
	}
    }

  if (ptw32_h_quserex)
    {
      ptw32_features |= PTW32_ALERTABLE_ASYNC_CANCEL;
    }

  return result;
}
BOOL
pthread_win32_process_attach_np ()
{
    BOOL result = TRUE;

    result = ptw32_processInitialize ();
#ifdef _UWIN
    pthread_count++;
#endif

    ptw32_features = 0;

#ifndef TEST_ICE

    /*
     * Load KERNEL32 and try to get address of InterlockedCompareExchange
     */
    ptw32_h_kernel32 = LoadLibrary (TEXT ("KERNEL32.DLL"));

    ptw32_interlocked_compare_exchange =
        (PTW32_INTERLOCKED_LONG (WINAPI *)
         (PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG,
          PTW32_INTERLOCKED_LONG))
#if defined(NEED_UNICODE_CONSTS)
        GetProcAddress (ptw32_h_kernel32,
                        (const TCHAR *) TEXT ("InterlockedCompareExchange"));
#else
        GetProcAddress (ptw32_h_kernel32, (LPCSTR) "InterlockedCompareExchange");
#endif

    if (ptw32_interlocked_compare_exchange == NULL)
    {
        ptw32_interlocked_compare_exchange = ptw32_InterlockedCompareExchange;

        /*
         * If InterlockedCompareExchange is not being used, then free
         * the kernel32.dll handle now, rather than leaving it until
         * DLL_PROCESS_DETACH.
         *
         * Note: this is not a pedantic exercise in freeing unused
         * resources!  It is a work-around for a bug in Windows 95
         * (see microsoft knowledge base article, Q187684) which
         * does Bad Things when FreeLibrary is called within
         * the DLL_PROCESS_DETACH code, in certain situations.
         * Since w95 just happens to be a platform which does not
         * provide InterlockedCompareExchange, the bug will be
         * effortlessly avoided.
         */
        (void) FreeLibrary (ptw32_h_kernel32);
        ptw32_h_kernel32 = 0;
    }
    else
    {
        ptw32_features |= PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE;
    }

#else /* TEST_ICE */

    ptw32_interlocked_compare_exchange = ptw32_InterlockedCompareExchange;

#endif /* TEST_ICE */

    /*
     * Load QUSEREX.DLL and try to get address of QueueUserAPCEx
     */
    ptw32_h_quserex = LoadLibrary (TEXT ("QUSEREX.DLL"));

    if (ptw32_h_quserex != NULL)
    {
        ptw32_register_cancelation = (DWORD (*)(PAPCFUNC, HANDLE, DWORD))
#if defined(NEED_UNICODE_CONSTS)
                                     GetProcAddress (ptw32_h_quserex,
                                             (const TCHAR *) TEXT ("QueueUserAPCEx"));
#else
                                     GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx");
#endif
    }

    if (NULL == ptw32_register_cancelation)
    {
        ptw32_register_cancelation = ptw32_RegisterCancelation;

        if (ptw32_h_quserex != NULL)
        {
            (void) FreeLibrary (ptw32_h_quserex);
        }
        ptw32_h_quserex = 0;
    }
    else
    {
        /* Initialise QueueUserAPCEx */
        BOOL (*queue_user_apc_ex_init) (VOID);

        queue_user_apc_ex_init = (BOOL (*)(VOID))
#if defined(NEED_UNICODE_CONSTS)
                                 GetProcAddress (ptw32_h_quserex,
                                         (const TCHAR *) TEXT ("QueueUserAPCEx_Init"));
#else
                                 GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Init");
#endif

        if (queue_user_apc_ex_init == NULL || !queue_user_apc_ex_init ())
        {
            ptw32_register_cancelation = ptw32_RegisterCancelation;

            (void) FreeLibrary (ptw32_h_quserex);
            ptw32_h_quserex = 0;
        }
    }

    if (ptw32_h_quserex)
    {
        ptw32_features |= PTW32_ALERTABLE_ASYNC_CANCEL;
    }

    return result;
}