void
gum_process_enumerate_threads (GumFoundThreadFunc func,
                               gpointer user_data)
{
  DWORD this_process_id;
  HANDLE snapshot;
  THREADENTRY32 entry;

  this_process_id = GetCurrentProcessId ();

  snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
  if (snapshot == INVALID_HANDLE_VALUE)
    goto beach;

  entry.dwSize = sizeof (entry);
  if (!Thread32First (snapshot, &entry))
    goto beach;

  do
  {
    if (RTL_CONTAINS_FIELD (&entry, entry.dwSize, th32OwnerProcessID) &&
        entry.th32OwnerProcessID == this_process_id)
    {
      GumThreadDetails details;

      if (gum_windows_get_thread_details (entry.th32ThreadID, &details))
      {
        if (!func (&details, user_data))
          break;
      }
    }

    entry.dwSize = sizeof (entry);
  }
  while (Thread32Next (snapshot, &entry));

beach:
  if (snapshot != INVALID_HANDLE_VALUE)
    CloseHandle (snapshot);
}
INT_PTR CALLBACK PhpProcessMitigationPolicyDlgProc(
    _In_ HWND hwndDlg,
    _In_ UINT uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
    )
{
    PMITIGATION_POLICY_CONTEXT context = NULL;

    if (uMsg == WM_INITDIALOG)
    {
        context = (PMITIGATION_POLICY_CONTEXT)lParam;
        SetProp(hwndDlg, L"Context", (HANDLE)context);
    }
    else
    {
        context = (PMITIGATION_POLICY_CONTEXT)GetProp(hwndDlg, L"Context");

        if (uMsg == WM_DESTROY)
        {
            RemoveProp(hwndDlg, L"Context");
        }
    }

    if (context == NULL)
        return FALSE;


    switch (uMsg)
    {
    case WM_INITDIALOG:
        {
            HWND lvHandle;
            PROCESS_MITIGATION_POLICY policy;

            PhCenterWindow(hwndDlg, GetParent(hwndDlg));
            context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
            PhSetListViewStyle(lvHandle, FALSE, TRUE);
            PhSetControlTheme(lvHandle, L"explorer");
            PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 350, L"Policy");
            PhSetExtendedListView(lvHandle);

            for (policy = 0; policy < MaxProcessMitigationPolicy; policy++)
            {
                PMITIGATION_POLICY_ENTRY entry = &context->Entries[policy];

                if (!entry->ShortDescription)
                    continue;

                PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry);
            }

            if (context->SystemDllInitBlock && RTL_CONTAINS_FIELD(context->SystemDllInitBlock, context->SystemDllInitBlock->Size, MitigationOptionsMap))
            {
                if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON)
                {
                    PMITIGATION_POLICY_ENTRY entry;

                    entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY));
                    entry->NonStandard = TRUE;
                    entry->ShortDescription = PhCreateString(L"Loader Integrity");
                    entry->LongDescription = PhCreateString(L"OS signing levels for depenedent module loads are enabled.");

                    PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry);
                }

                if (context->SystemDllInitBlock->MitigationOptionsMap.Map[0] & PROCESS_CREATION_MITIGATION_POLICY2_MODULE_TAMPERING_PROTECTION_ALWAYS_ON)
                {
                    PMITIGATION_POLICY_ENTRY entry;

                    entry = PhAllocate(sizeof(MITIGATION_POLICY_ENTRY));
                    entry->NonStandard = TRUE;
                    entry->ShortDescription = PhCreateString(L"Module Tampering");
                    entry->LongDescription = PhCreateString(L"Module Tampering protection is enabled.");

                    PhAddListViewItem(lvHandle, MAXINT, entry->ShortDescription->Buffer, entry);
                }
            }

            ExtendedListView_SortItems(lvHandle);
            ExtendedListView_SetColumnWidth(lvHandle, 0, ELVSCW_AUTOSIZE_REMAININGSPACE);
            ListView_SetItemState(lvHandle, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
            SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)lvHandle, TRUE);
        }
        break;
    case WM_DESTROY:
        {
            ULONG index = -1;

            while ((index = PhFindListViewItemByFlags(
                context->ListViewHandle,
                index,
                LVNI_ALL
                )) != -1)
            {
                PMITIGATION_POLICY_ENTRY entry;

                if (PhGetListViewItemParam(context->ListViewHandle, index, &entry))
                {
                    if (entry->NonStandard)
                    {
                        PhClearReference(&entry->ShortDescription);
                        PhClearReference(&entry->LongDescription);
                        PhFree(entry);
                    }
                }
            }
        }
        break;
    case WM_COMMAND:
        {
            switch (GET_WM_COMMAND_ID(wParam, lParam))
            {
            case IDCANCEL:
            case IDOK:
                EndDialog(hwndDlg, IDOK);
                break;
            }
        }
        break;
    case WM_NOTIFY:
        {
            LPNMHDR header = (LPNMHDR)lParam;
            HWND lvHandle = GetDlgItem(hwndDlg, IDC_LIST);

            switch (header->code)
            {
            case LVN_ITEMCHANGED:
                {
                    if (header->hwndFrom == lvHandle)
                    {
                        PWSTR description;

                        if (ListView_GetSelectedCount(lvHandle) == 1)
                            description = ((PMITIGATION_POLICY_ENTRY)PhGetSelectedListViewItemParam(lvHandle))->LongDescription->Buffer;
                        else
                            description = L"";

                        SetDlgItemText(hwndDlg, IDC_DESCRIPTION, description);
                    }
                }
                break;
            }

            PhHandleListViewNotifyForCopy(lParam, lvHandle);
        }
        break;
    }

    return FALSE;
}