diff --git a/2.x/trunk/CHANGELOG.txt b/2.x/trunk/CHANGELOG.txt
index 3849f0372..9d566334c 100644
--- a/2.x/trunk/CHANGELOG.txt
+++ b/2.x/trunk/CHANGELOG.txt
@@ -2,6 +2,7 @@ Process Hacker
2.13
* NEW/IMPROVED:
+ * Added copy support to PE viewer
* FIXED:
2.12
diff --git a/2.x/trunk/ProcessHacker/ProcessHacker.vcxproj b/2.x/trunk/ProcessHacker/ProcessHacker.vcxproj
index e57665f32..c67110f4e 100644
--- a/2.x/trunk/ProcessHacker/ProcessHacker.vcxproj
+++ b/2.x/trunk/ProcessHacker/ProcessHacker.vcxproj
@@ -222,6 +222,7 @@
+
@@ -266,7 +267,6 @@
-
diff --git a/2.x/trunk/ProcessHacker/ProcessHacker.vcxproj.filters b/2.x/trunk/ProcessHacker/ProcessHacker.vcxproj.filters
index 12029be45..5fe85f18a 100644
--- a/2.x/trunk/ProcessHacker/ProcessHacker.vcxproj.filters
+++ b/2.x/trunk/ProcessHacker/ProcessHacker.vcxproj.filters
@@ -177,9 +177,6 @@
Process Hacker
-
- Process Hacker
-
Process Hacker
@@ -435,6 +432,9 @@
Process Hacker
+
+ phlib
+
diff --git a/2.x/trunk/ProcessHacker/appsup.c b/2.x/trunk/ProcessHacker/appsup.c
index 1199387c1..00bbe023f 100644
--- a/2.x/trunk/ProcessHacker/appsup.c
+++ b/2.x/trunk/ProcessHacker/appsup.c
@@ -22,6 +22,7 @@
#include
#include
+#include
#include "mxml/mxml.h"
#include
#include
diff --git a/2.x/trunk/ProcessHacker/include/phapp.h b/2.x/trunk/ProcessHacker/include/phapp.h
index 7ee07d214..8782d9f7e 100644
--- a/2.x/trunk/ProcessHacker/include/phapp.h
+++ b/2.x/trunk/ProcessHacker/include/phapp.h
@@ -1150,39 +1150,6 @@ BOOLEAN PhShowChooseProcessDialog(
__out PHANDLE ProcessId
);
-// cpysave
-
-#define PH_EXPORT_MODE_TABS 0
-#define PH_EXPORT_MODE_SPACES 1
-#define PH_EXPORT_MODE_CSV 2
-
-PHAPPAPI
-PPH_FULL_STRING PhGetTreeListText(
- __in HWND TreeListHandle,
- __in ULONG MaximumNumberOfColumns
- );
-
-PPH_LIST PhGetProcessTreeListLines(
- __in HWND TreeListHandle,
- __in ULONG NumberOfNodes,
- __in PPH_LIST RootNodes,
- __in ULONG Mode
- );
-
-PPH_LIST PhGetGenericTreeListLines(
- __in HWND TreeListHandle,
- __in ULONG Mode
- );
-
-PPH_FULL_STRING PhGetListViewText(
- __in HWND ListViewHandle
- );
-
-PPH_LIST PhGetListViewLines(
- __in HWND ListViewHandle,
- __in ULONG Mode
- );
-
// findobj
VOID PhShowFindObjectsDialog();
diff --git a/2.x/trunk/ProcessHacker/include/uimodels.h b/2.x/trunk/ProcessHacker/include/uimodels.h
index 87a08acda..180f88169 100644
--- a/2.x/trunk/ProcessHacker/include/uimodels.h
+++ b/2.x/trunk/ProcessHacker/include/uimodels.h
@@ -303,6 +303,13 @@ VOID PhRemoveProcessTreeFilter(
PHAPPAPI
VOID PhApplyProcessTreeFilters();
+PPH_LIST PhGetProcessTreeListLines(
+ __in HWND TreeListHandle,
+ __in ULONG NumberOfNodes,
+ __in PPH_LIST RootNodes,
+ __in ULONG Mode
+ );
+
VOID PhCopyProcessTree();
VOID PhWriteProcessTree(
diff --git a/2.x/trunk/ProcessHacker/mainwnd.c b/2.x/trunk/ProcessHacker/mainwnd.c
index ab7e6a4f3..ea8e9f409 100644
--- a/2.x/trunk/ProcessHacker/mainwnd.c
+++ b/2.x/trunk/ProcessHacker/mainwnd.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/2.x/trunk/ProcessHacker/procprp.c b/2.x/trunk/ProcessHacker/procprp.c
index 745cac7c6..6bc52491e 100644
--- a/2.x/trunk/ProcessHacker/procprp.c
+++ b/2.x/trunk/ProcessHacker/procprp.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/2.x/trunk/ProcessHacker/proctree.c b/2.x/trunk/ProcessHacker/proctree.c
index f11abb1ea..6117882de 100644
--- a/2.x/trunk/ProcessHacker/proctree.c
+++ b/2.x/trunk/ProcessHacker/proctree.c
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
VOID PhpEnableColumnCustomDraw(
__in HWND hwnd,
@@ -2131,6 +2132,125 @@ VOID PhApplyProcessTreeFilters()
TreeList_NodesStructured(ProcessTreeListHandle);
}
+VOID PhpPopulateTableWithProcessNodes(
+ __in HWND TreeListHandle,
+ __in PPH_PROCESS_NODE Node,
+ __in ULONG Level,
+ __in PPH_STRING **Table,
+ __inout PULONG Index,
+ __in PULONG DisplayToId,
+ __in ULONG Columns
+ )
+{
+ ULONG i;
+
+ for (i = 0; i < Columns; i++)
+ {
+ PH_TL_GETNODETEXT getNodeText;
+ PPH_STRING text;
+
+ getNodeText.Node = &Node->Node;
+ getNodeText.Id = DisplayToId[i];
+ PhInitializeEmptyStringRef(&getNodeText.Text);
+ TreeList_GetNodeText(TreeListHandle, &getNodeText);
+
+ if (i != 0)
+ {
+ text = PhaCreateStringEx(getNodeText.Text.Buffer, getNodeText.Text.Length);
+ }
+ else
+ {
+ // If this is the first column in the row, add some indentation.
+ text = PhaCreateStringEx(
+ NULL,
+ getNodeText.Text.Length + Level * 2 * sizeof(WCHAR)
+ );
+ wmemset(text->Buffer, ' ', Level * 2);
+ memcpy(&text->Buffer[Level * 2], getNodeText.Text.Buffer, getNodeText.Text.Length);
+ }
+
+ Table[*Index][i] = text;
+ }
+
+ (*Index)++;
+
+ // Process the children.
+ for (i = 0; i < Node->Children->Count; i++)
+ {
+ PhpPopulateTableWithProcessNodes(
+ TreeListHandle,
+ Node->Children->Items[i],
+ Level + 1,
+ Table,
+ Index,
+ DisplayToId,
+ Columns
+ );
+ }
+}
+
+PPH_LIST PhGetProcessTreeListLines(
+ __in HWND TreeListHandle,
+ __in ULONG NumberOfNodes,
+ __in PPH_LIST RootNodes,
+ __in ULONG Mode
+ )
+{
+ PH_AUTO_POOL autoPool;
+ PPH_LIST lines;
+ // The number of rows in the table (including +1 for the column headers).
+ ULONG rows;
+ // The number of columns.
+ ULONG columns;
+ // A column display index to ID map.
+ ULONG displayToId[PHPRTLC_MAXIMUM];
+ // A column display index to text map.
+ PWSTR displayToText[PHPRTLC_MAXIMUM];
+ // The actual string table.
+ PPH_STRING **table;
+ ULONG i;
+ ULONG j;
+
+ // Use a local auto-pool to make memory mangement a bit less painful.
+ PhInitializeAutoPool(&autoPool);
+
+ rows = NumberOfNodes + 1;
+
+ // Create the display index to ID map.
+ PhMapDisplayIndexTreeList(TreeListHandle, PHPRTLC_MAXIMUM, displayToId, displayToText, &columns);
+
+ PhaCreateTextTable(&table, rows, columns);
+
+ // Populate the first row with the column headers.
+ for (i = 0; i < columns; i++)
+ {
+ table[0][i] = PhaCreateString(displayToText[i]);
+ }
+
+ // Go through the nodes in the process tree and populate each cell of the table.
+
+ j = 1; // index starts at one because the first row contains the column headers.
+
+ for (i = 0; i < RootNodes->Count; i++)
+ {
+ PhpPopulateTableWithProcessNodes(
+ TreeListHandle,
+ RootNodes->Items[i],
+ 0,
+ table,
+ &j,
+ displayToId,
+ columns
+ );
+ }
+
+ lines = PhaFormatTextTable(table, rows, columns, Mode);
+
+ PhDeleteAutoPool(&autoPool);
+
+ return lines;
+}
+
VOID PhCopyProcessTree()
{
PPH_FULL_STRING text;
diff --git a/2.x/trunk/ProcessHacker/sdk/phdk.h b/2.x/trunk/ProcessHacker/sdk/phdk.h
index 53a997b63..12da6aad8 100644
--- a/2.x/trunk/ProcessHacker/sdk/phdk.h
+++ b/2.x/trunk/ProcessHacker/sdk/phdk.h
@@ -14,6 +14,7 @@
#include "treelist.h"
#include "emenu.h"
+#include "cpysave.h"
#include "phapppub.h"
#include "phplug.h"
diff --git a/2.x/trunk/ProcessHacker/srvlist.c b/2.x/trunk/ProcessHacker/srvlist.c
index f934e4e1f..64cd6aad8 100644
--- a/2.x/trunk/ProcessHacker/srvlist.c
+++ b/2.x/trunk/ProcessHacker/srvlist.c
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
BOOLEAN PhpServiceNodeHashtableCompareFunction(
__in PVOID Entry1,
diff --git a/2.x/trunk/ProcessHacker/cpysave.c b/2.x/trunk/phlib/cpysave.c
similarity index 71%
rename from 2.x/trunk/ProcessHacker/cpysave.c
rename to 2.x/trunk/phlib/cpysave.c
index 51b1ef300..17c1278f9 100644
--- a/2.x/trunk/ProcessHacker/cpysave.c
+++ b/2.x/trunk/phlib/cpysave.c
@@ -2,7 +2,7 @@
* Process Hacker -
* copy/save code for listviews and treelists
*
- * Copyright (C) 2010 wj32
+ * Copyright (C) 2010-2011 wj32
*
* This file is part of Process Hacker.
*
@@ -20,436 +20,12 @@
* along with Process Hacker. If not, see .
*/
-#include
+#include
+#include
+#include
#define TAB_SIZE 8
-VOID PhapCreateTextTable(
- __out PPH_STRING ***Table,
- __in ULONG Rows,
- __in ULONG Columns
- );
-
-PPH_LIST PhapFormatTextTable(
- __in PPH_STRING **Table,
- __in ULONG Rows,
- __in ULONG Columns,
- __in ULONG Mode
- );
-
-VOID PhpMapDisplayIndexTreeList(
- __in HWND TreeListHandle,
- __in ULONG MaximumNumberOfColumns,
- __out_ecount(MaximumNumberOfColumns) PULONG DisplayToId,
- __out_ecount_opt(MaximumNumberOfColumns) PWSTR *DisplayToText,
- __out PULONG NumberOfColumns
- )
-{
- PH_TREELIST_COLUMN column;
- ULONG i;
- ULONG count;
-
- count = 0;
-
- for (i = 0; i < MaximumNumberOfColumns; i++)
- {
- column.Id = i;
-
- if (TreeList_GetColumn(TreeListHandle, &column))
- {
- if (column.Visible)
- {
- if (column.DisplayIndex < MaximumNumberOfColumns)
- {
- DisplayToId[column.DisplayIndex] = i;
-
- if (DisplayToText)
- DisplayToText[column.DisplayIndex] = column.Text;
-
- count++;
- }
- }
- }
- }
-
- *NumberOfColumns = count;
-}
-
-PPH_FULL_STRING PhGetTreeListText(
- __in HWND TreeListHandle,
- __in ULONG MaximumNumberOfColumns
- )
-{
- PPH_FULL_STRING string;
- PULONG displayToId;
- ULONG rows;
- ULONG columns;
- ULONG i;
- ULONG j;
-
- displayToId = PhAllocate(MaximumNumberOfColumns * sizeof(ULONG));
-
- PhpMapDisplayIndexTreeList(TreeListHandle, MaximumNumberOfColumns, displayToId, NULL, &columns);
- rows = TreeList_GetVisibleNodeCount(TreeListHandle);
-
- string = PhCreateFullString2(0x100);
-
- for (i = 0; i < rows; i++)
- {
- PH_TL_GETNODETEXT getNodeText;
-
- getNodeText.Node = TreeList_GetVisibleNode(TreeListHandle, i);
- assert(getNodeText.Node);
-
- if (!getNodeText.Node->Selected)
- continue;
-
- for (j = 0; j < columns; j++)
- {
- getNodeText.Id = displayToId[j];
- PhInitializeEmptyStringRef(&getNodeText.Text);
- TreeList_GetNodeText(TreeListHandle, &getNodeText);
-
- PhAppendFullStringEx(string, getNodeText.Text.Buffer, getNodeText.Text.Length);
- PhAppendFullString2(string, L", ");
- }
-
- // Remove the trailing comma and space.
- if (string->Length != 0)
- PhRemoveFullString(string, string->Length / 2 - 2, 2);
-
- PhAppendFullString2(string, L"\r\n");
- }
-
- PhFree(displayToId);
-
- return string;
-}
-
-VOID PhpPopulateTableWithProcessNodes(
- __in HWND TreeListHandle,
- __in PPH_PROCESS_NODE Node,
- __in ULONG Level,
- __in PPH_STRING **Table,
- __inout PULONG Index,
- __in PULONG DisplayToId,
- __in ULONG Columns
- )
-{
- ULONG i;
-
- for (i = 0; i < Columns; i++)
- {
- PH_TL_GETNODETEXT getNodeText;
- PPH_STRING text;
-
- getNodeText.Node = &Node->Node;
- getNodeText.Id = DisplayToId[i];
- PhInitializeEmptyStringRef(&getNodeText.Text);
- TreeList_GetNodeText(TreeListHandle, &getNodeText);
-
- if (i != 0)
- {
- text = PhaCreateStringEx(getNodeText.Text.Buffer, getNodeText.Text.Length);
- }
- else
- {
- // If this is the first column in the row, add some indentation.
- text = PhaCreateStringEx(
- NULL,
- getNodeText.Text.Length + Level * 2 * sizeof(WCHAR)
- );
- wmemset(text->Buffer, ' ', Level * 2);
- memcpy(&text->Buffer[Level * 2], getNodeText.Text.Buffer, getNodeText.Text.Length);
- }
-
- Table[*Index][i] = text;
- }
-
- (*Index)++;
-
- // Process the children.
- for (i = 0; i < Node->Children->Count; i++)
- {
- PhpPopulateTableWithProcessNodes(
- TreeListHandle,
- Node->Children->Items[i],
- Level + 1,
- Table,
- Index,
- DisplayToId,
- Columns
- );
- }
-}
-
-PPH_LIST PhGetProcessTreeListLines(
- __in HWND TreeListHandle,
- __in ULONG NumberOfNodes,
- __in PPH_LIST RootNodes,
- __in ULONG Mode
- )
-{
- PH_AUTO_POOL autoPool;
- PPH_LIST lines;
- // The number of rows in the table (including +1 for the column headers).
- ULONG rows;
- // The number of columns.
- ULONG columns;
- // A column display index to ID map.
- ULONG displayToId[PHPRTLC_MAXIMUM];
- // A column display index to text map.
- PWSTR displayToText[PHPRTLC_MAXIMUM];
- // The actual string table.
- PPH_STRING **table;
- ULONG i;
- ULONG j;
-
- // Use a local auto-pool to make memory mangement a bit less painful.
- PhInitializeAutoPool(&autoPool);
-
- rows = NumberOfNodes + 1;
-
- // Create the display index to ID map.
- PhpMapDisplayIndexTreeList(TreeListHandle, PHPRTLC_MAXIMUM, displayToId, displayToText, &columns);
-
- PhapCreateTextTable(&table, rows, columns);
-
- // Populate the first row with the column headers.
- for (i = 0; i < columns; i++)
- {
- table[0][i] = PhaCreateString(displayToText[i]);
- }
-
- // Go through the nodes in the process tree and populate each cell of the table.
-
- j = 1; // index starts at one because the first row contains the column headers.
-
- for (i = 0; i < RootNodes->Count; i++)
- {
- PhpPopulateTableWithProcessNodes(
- TreeListHandle,
- RootNodes->Items[i],
- 0,
- table,
- &j,
- displayToId,
- columns
- );
- }
-
- lines = PhapFormatTextTable(table, rows, columns, Mode);
-
- PhDeleteAutoPool(&autoPool);
-
- return lines;
-}
-
-PPH_LIST PhGetGenericTreeListLines(
- __in HWND TreeListHandle,
- __in ULONG Mode
- )
-{
- PH_AUTO_POOL autoPool;
- PPH_LIST lines;
- ULONG rows;
- ULONG columns;
- ULONG numberOfNodes;
- ULONG maxId;
- PULONG displayToId;
- PWSTR *displayToText;
- PPH_STRING **table;
- ULONG i;
- ULONG j;
-
- PhInitializeAutoPool(&autoPool);
-
- numberOfNodes = TreeList_GetVisibleNodeCount(TreeListHandle);
- maxId = TreeList_GetMaxId(TreeListHandle) + 1;
- displayToId = PhAllocate(sizeof(ULONG) * maxId);
- displayToText = PhAllocate(sizeof(PWSTR) * maxId);
-
- rows = numberOfNodes + 1;
- PhpMapDisplayIndexTreeList(TreeListHandle, maxId, displayToId, displayToText, &columns);
-
- PhapCreateTextTable(&table, rows, columns);
-
- for (i = 0; i < columns; i++)
- table[0][i] = PhaCreateString(displayToText[i]);
-
- for (i = 0; i < numberOfNodes; i++)
- {
- PPH_TREELIST_NODE node;
-
- node = TreeList_GetVisibleNode(TreeListHandle, i);
-
- if (node)
- {
- for (j = 0; j < columns; j++)
- {
- PH_TL_GETNODETEXT getNodeText;
-
- getNodeText.Node = node;
- getNodeText.Id = displayToId[j];
- PhInitializeEmptyStringRef(&getNodeText.Text);
- TreeList_GetNodeText(TreeListHandle, &getNodeText);
-
- table[i + 1][j] = PhaCreateStringEx(getNodeText.Text.Buffer, getNodeText.Text.Length);
- }
- }
- else
- {
- for (j = 0; j < columns; j++)
- {
- table[i + 1][j] = PHA_DEREFERENCE(PhReferenceEmptyString());
- }
- }
- }
-
- PhFree(displayToText);
- PhFree(displayToId);
-
- lines = PhapFormatTextTable(table, rows, columns, Mode);
-
- PhDeleteAutoPool(&autoPool);
-
- return lines;
-}
-
-VOID PhapMapDisplayIndexListView(
- __in HWND ListViewHandle,
- __out_ecount(Count) PULONG DisplayToId,
- __out_ecount_opt(Count) PPH_STRING *DisplayToText,
- __in ULONG Count,
- __out PULONG NumberOfColumns
- )
-{
- LVCOLUMN lvColumn;
- ULONG i;
- ULONG count;
- WCHAR buffer[128];
-
- count = 0;
- lvColumn.mask = LVCF_ORDER | LVCF_TEXT;
- lvColumn.pszText = buffer;
- lvColumn.cchTextMax = sizeof(buffer) / sizeof(WCHAR);
-
- for (i = 0; i < Count; i++)
- {
- if (ListView_GetColumn(ListViewHandle, i, &lvColumn))
- {
- ULONG displayIndex;
-
- displayIndex = (ULONG)lvColumn.iOrder;
- assert(displayIndex < Count);
- DisplayToId[displayIndex] = i;
-
- if (DisplayToText)
- DisplayToText[displayIndex] = PhaCreateString(buffer);
-
- count++;
- }
- else
- {
- break;
- }
- }
-
- *NumberOfColumns = count;
-}
-
-PPH_FULL_STRING PhGetListViewText(
- __in HWND ListViewHandle
- )
-{
- PPH_FULL_STRING string;
- ULONG displayToId[100];
- ULONG rows;
- ULONG columns;
- ULONG i;
- ULONG j;
-
- PhapMapDisplayIndexListView(ListViewHandle, displayToId, NULL, 100, &columns);
- rows = ListView_GetItemCount(ListViewHandle);
-
- string = PhCreateFullString2(0x100);
-
- for (i = 0; i < rows; i++)
- {
- if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED))
- continue;
-
- for (j = 0; j < columns; j++)
- {
- WCHAR buffer[512];
-
- buffer[0] = 0;
- ListView_GetItemText(ListViewHandle, i, j, buffer, sizeof(buffer) / sizeof(WCHAR));
- PhAppendFullString2(string, buffer);
-
- PhAppendFullString2(string, L", ");
- }
-
- // Remove the trailing comma and space.
- if (string->Length != 0)
- PhRemoveFullString(string, string->Length / 2 - 2, 2);
-
- PhAppendFullString2(string, L"\r\n");
- }
-
- return string;
-}
-
-PPH_LIST PhGetListViewLines(
- __in HWND ListViewHandle,
- __in ULONG Mode
- )
-{
- PH_AUTO_POOL autoPool;
- PPH_LIST lines;
- ULONG rows;
- ULONG columns;
- ULONG displayToId[100];
- PPH_STRING displayToText[100];
- PPH_STRING **table;
- ULONG i;
- ULONG j;
-
- PhInitializeAutoPool(&autoPool);
-
- rows = ListView_GetItemCount(ListViewHandle) + 1; // +1 for column headers
-
- // Create the display index/text to ID map.
- PhapMapDisplayIndexListView(ListViewHandle, displayToId, displayToText, 100, &columns);
-
- PhapCreateTextTable(&table, rows, columns);
-
- // Populate the first row with the column headers.
- for (i = 0; i < columns; i++)
- table[0][i] = displayToText[i];
-
- // Populate the other rows with text.
- for (i = 1; i < rows; i++)
- {
- for (j = 0; j < columns; j++)
- {
- WCHAR buffer[512];
-
- // Important: use this to bypass extlv's hooking.
- // extlv only hooks LVM_GETITEM, not LVM_GETITEMTEXT.
- buffer[0] = 0;
- ListView_GetItemText(ListViewHandle, i - 1, j, buffer, sizeof(buffer) / sizeof(WCHAR));
- table[i][j] = PhaCreateString(buffer);
- }
- }
-
- lines = PhapFormatTextTable(table, rows, columns, Mode);
-
- PhDeleteAutoPool(&autoPool);
-
- return lines;
-}
-
VOID PhpEscapeStringForCsv(
__inout PPH_STRING_BUILDER StringBuilder,
__in PPH_STRING String
@@ -496,7 +72,7 @@ VOID PhpEscapeStringForCsv(
PhAppendStringBuilderEx(StringBuilder, runStart, runLength * sizeof(WCHAR));
}
-VOID PhapCreateTextTable(
+VOID PhaCreateTextTable(
__out PPH_STRING ***Table,
__in ULONG Rows,
__in ULONG Columns
@@ -517,7 +93,7 @@ VOID PhapCreateTextTable(
*Table = table;
}
-PPH_LIST PhapFormatTextTable(
+PPH_LIST PhaFormatTextTable(
__in PPH_STRING **Table,
__in ULONG Rows,
__in ULONG Columns,
@@ -616,3 +192,297 @@ PPH_LIST PhapFormatTextTable(
return lines;
}
+
+VOID PhMapDisplayIndexTreeList(
+ __in HWND TreeListHandle,
+ __in ULONG MaximumNumberOfColumns,
+ __out_ecount(MaximumNumberOfColumns) PULONG DisplayToId,
+ __out_ecount_opt(MaximumNumberOfColumns) PWSTR *DisplayToText,
+ __out PULONG NumberOfColumns
+ )
+{
+ PH_TREELIST_COLUMN column;
+ ULONG i;
+ ULONG count;
+
+ count = 0;
+
+ for (i = 0; i < MaximumNumberOfColumns; i++)
+ {
+ column.Id = i;
+
+ if (TreeList_GetColumn(TreeListHandle, &column))
+ {
+ if (column.Visible)
+ {
+ if (column.DisplayIndex < MaximumNumberOfColumns)
+ {
+ DisplayToId[column.DisplayIndex] = i;
+
+ if (DisplayToText)
+ DisplayToText[column.DisplayIndex] = column.Text;
+
+ count++;
+ }
+ }
+ }
+ }
+
+ *NumberOfColumns = count;
+}
+
+PPH_FULL_STRING PhGetTreeListText(
+ __in HWND TreeListHandle,
+ __in ULONG MaximumNumberOfColumns
+ )
+{
+ PPH_FULL_STRING string;
+ PULONG displayToId;
+ ULONG rows;
+ ULONG columns;
+ ULONG i;
+ ULONG j;
+
+ displayToId = PhAllocate(MaximumNumberOfColumns * sizeof(ULONG));
+
+ PhMapDisplayIndexTreeList(TreeListHandle, MaximumNumberOfColumns, displayToId, NULL, &columns);
+ rows = TreeList_GetVisibleNodeCount(TreeListHandle);
+
+ string = PhCreateFullString2(0x100);
+
+ for (i = 0; i < rows; i++)
+ {
+ PH_TL_GETNODETEXT getNodeText;
+
+ getNodeText.Node = TreeList_GetVisibleNode(TreeListHandle, i);
+ assert(getNodeText.Node);
+
+ if (!getNodeText.Node->Selected)
+ continue;
+
+ for (j = 0; j < columns; j++)
+ {
+ getNodeText.Id = displayToId[j];
+ PhInitializeEmptyStringRef(&getNodeText.Text);
+ TreeList_GetNodeText(TreeListHandle, &getNodeText);
+
+ PhAppendFullStringEx(string, getNodeText.Text.Buffer, getNodeText.Text.Length);
+ PhAppendFullString2(string, L", ");
+ }
+
+ // Remove the trailing comma and space.
+ if (string->Length != 0)
+ PhRemoveFullString(string, string->Length / 2 - 2, 2);
+
+ PhAppendFullString2(string, L"\r\n");
+ }
+
+ PhFree(displayToId);
+
+ return string;
+}
+
+PPH_LIST PhGetGenericTreeListLines(
+ __in HWND TreeListHandle,
+ __in ULONG Mode
+ )
+{
+ PH_AUTO_POOL autoPool;
+ PPH_LIST lines;
+ ULONG rows;
+ ULONG columns;
+ ULONG numberOfNodes;
+ ULONG maxId;
+ PULONG displayToId;
+ PWSTR *displayToText;
+ PPH_STRING **table;
+ ULONG i;
+ ULONG j;
+
+ PhInitializeAutoPool(&autoPool);
+
+ numberOfNodes = TreeList_GetVisibleNodeCount(TreeListHandle);
+ maxId = TreeList_GetMaxId(TreeListHandle) + 1;
+ displayToId = PhAllocate(sizeof(ULONG) * maxId);
+ displayToText = PhAllocate(sizeof(PWSTR) * maxId);
+
+ rows = numberOfNodes + 1;
+ PhMapDisplayIndexTreeList(TreeListHandle, maxId, displayToId, displayToText, &columns);
+
+ PhaCreateTextTable(&table, rows, columns);
+
+ for (i = 0; i < columns; i++)
+ table[0][i] = PhaCreateString(displayToText[i]);
+
+ for (i = 0; i < numberOfNodes; i++)
+ {
+ PPH_TREELIST_NODE node;
+
+ node = TreeList_GetVisibleNode(TreeListHandle, i);
+
+ if (node)
+ {
+ for (j = 0; j < columns; j++)
+ {
+ PH_TL_GETNODETEXT getNodeText;
+
+ getNodeText.Node = node;
+ getNodeText.Id = displayToId[j];
+ PhInitializeEmptyStringRef(&getNodeText.Text);
+ TreeList_GetNodeText(TreeListHandle, &getNodeText);
+
+ table[i + 1][j] = PhaCreateStringEx(getNodeText.Text.Buffer, getNodeText.Text.Length);
+ }
+ }
+ else
+ {
+ for (j = 0; j < columns; j++)
+ {
+ table[i + 1][j] = PHA_DEREFERENCE(PhReferenceEmptyString());
+ }
+ }
+ }
+
+ PhFree(displayToText);
+ PhFree(displayToId);
+
+ lines = PhaFormatTextTable(table, rows, columns, Mode);
+
+ PhDeleteAutoPool(&autoPool);
+
+ return lines;
+}
+
+VOID PhaMapDisplayIndexListView(
+ __in HWND ListViewHandle,
+ __out_ecount(Count) PULONG DisplayToId,
+ __out_ecount_opt(Count) PPH_STRING *DisplayToText,
+ __in ULONG Count,
+ __out PULONG NumberOfColumns
+ )
+{
+ LVCOLUMN lvColumn;
+ ULONG i;
+ ULONG count;
+ WCHAR buffer[128];
+
+ count = 0;
+ lvColumn.mask = LVCF_ORDER | LVCF_TEXT;
+ lvColumn.pszText = buffer;
+ lvColumn.cchTextMax = sizeof(buffer) / sizeof(WCHAR);
+
+ for (i = 0; i < Count; i++)
+ {
+ if (ListView_GetColumn(ListViewHandle, i, &lvColumn))
+ {
+ ULONG displayIndex;
+
+ displayIndex = (ULONG)lvColumn.iOrder;
+ assert(displayIndex < Count);
+ DisplayToId[displayIndex] = i;
+
+ if (DisplayToText)
+ DisplayToText[displayIndex] = PhaCreateString(buffer);
+
+ count++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ *NumberOfColumns = count;
+}
+
+PPH_FULL_STRING PhGetListViewText(
+ __in HWND ListViewHandle
+ )
+{
+ PPH_FULL_STRING string;
+ ULONG displayToId[100];
+ ULONG rows;
+ ULONG columns;
+ ULONG i;
+ ULONG j;
+
+ PhaMapDisplayIndexListView(ListViewHandle, displayToId, NULL, 100, &columns);
+ rows = ListView_GetItemCount(ListViewHandle);
+
+ string = PhCreateFullString2(0x100);
+
+ for (i = 0; i < rows; i++)
+ {
+ if (!(ListView_GetItemState(ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED))
+ continue;
+
+ for (j = 0; j < columns; j++)
+ {
+ WCHAR buffer[512];
+
+ buffer[0] = 0;
+ ListView_GetItemText(ListViewHandle, i, j, buffer, sizeof(buffer) / sizeof(WCHAR));
+ PhAppendFullString2(string, buffer);
+
+ PhAppendFullString2(string, L", ");
+ }
+
+ // Remove the trailing comma and space.
+ if (string->Length != 0)
+ PhRemoveFullString(string, string->Length / 2 - 2, 2);
+
+ PhAppendFullString2(string, L"\r\n");
+ }
+
+ return string;
+}
+
+PPH_LIST PhGetListViewLines(
+ __in HWND ListViewHandle,
+ __in ULONG Mode
+ )
+{
+ PH_AUTO_POOL autoPool;
+ PPH_LIST lines;
+ ULONG rows;
+ ULONG columns;
+ ULONG displayToId[100];
+ PPH_STRING displayToText[100];
+ PPH_STRING **table;
+ ULONG i;
+ ULONG j;
+
+ PhInitializeAutoPool(&autoPool);
+
+ rows = ListView_GetItemCount(ListViewHandle) + 1; // +1 for column headers
+
+ // Create the display index/text to ID map.
+ PhaMapDisplayIndexListView(ListViewHandle, displayToId, displayToText, 100, &columns);
+
+ PhaCreateTextTable(&table, rows, columns);
+
+ // Populate the first row with the column headers.
+ for (i = 0; i < columns; i++)
+ table[0][i] = displayToText[i];
+
+ // Populate the other rows with text.
+ for (i = 1; i < rows; i++)
+ {
+ for (j = 0; j < columns; j++)
+ {
+ WCHAR buffer[512];
+
+ // Important: use this to bypass extlv's hooking.
+ // extlv only hooks LVM_GETITEM, not LVM_GETITEMTEXT.
+ buffer[0] = 0;
+ ListView_GetItemText(ListViewHandle, i - 1, j, buffer, sizeof(buffer) / sizeof(WCHAR));
+ table[i][j] = PhaCreateString(buffer);
+ }
+ }
+
+ lines = PhaFormatTextTable(table, rows, columns, Mode);
+
+ PhDeleteAutoPool(&autoPool);
+
+ return lines;
+}
diff --git a/2.x/trunk/phlib/include/cpysave.h b/2.x/trunk/phlib/include/cpysave.h
new file mode 100644
index 000000000..73ccf3b07
--- /dev/null
+++ b/2.x/trunk/phlib/include/cpysave.h
@@ -0,0 +1,57 @@
+#ifndef _PH_CPYSAVE_H
+#define _PH_CPYSAVE_H
+
+#define PH_EXPORT_MODE_TABS 0
+#define PH_EXPORT_MODE_SPACES 1
+#define PH_EXPORT_MODE_CSV 2
+
+VOID PhaCreateTextTable(
+ __out PPH_STRING ***Table,
+ __in ULONG Rows,
+ __in ULONG Columns
+ );
+
+PPH_LIST PhaFormatTextTable(
+ __in PPH_STRING **Table,
+ __in ULONG Rows,
+ __in ULONG Columns,
+ __in ULONG Mode
+ );
+
+VOID PhMapDisplayIndexTreeList(
+ __in HWND TreeListHandle,
+ __in ULONG MaximumNumberOfColumns,
+ __out_ecount(MaximumNumberOfColumns) PULONG DisplayToId,
+ __out_ecount_opt(MaximumNumberOfColumns) PWSTR *DisplayToText,
+ __out PULONG NumberOfColumns
+ );
+
+PHLIBAPI
+PPH_FULL_STRING PhGetTreeListText(
+ __in HWND TreeListHandle,
+ __in ULONG MaximumNumberOfColumns
+ );
+
+PPH_LIST PhGetGenericTreeListLines(
+ __in HWND TreeListHandle,
+ __in ULONG Mode
+ );
+
+VOID PhaMapDisplayIndexListView(
+ __in HWND ListViewHandle,
+ __out_ecount(Count) PULONG DisplayToId,
+ __out_ecount_opt(Count) PPH_STRING *DisplayToText,
+ __in ULONG Count,
+ __out PULONG NumberOfColumns
+ );
+
+PPH_FULL_STRING PhGetListViewText(
+ __in HWND ListViewHandle
+ );
+
+PPH_LIST PhGetListViewLines(
+ __in HWND ListViewHandle,
+ __in ULONG Mode
+ );
+
+#endif
diff --git a/2.x/trunk/phlib/include/treelist.h b/2.x/trunk/phlib/include/treelist.h
index 69c254c42..3103b0cfb 100644
--- a/2.x/trunk/phlib/include/treelist.h
+++ b/2.x/trunk/phlib/include/treelist.h
@@ -359,6 +359,14 @@ HWND PhCreateTreeListControlEx(
__in ULONG Style
);
+__callback BOOLEAN NTAPI PhTreeListNullCallback(
+ __in HWND hwnd,
+ __in PH_TREELIST_MESSAGE Message,
+ __in_opt PVOID Parameter1,
+ __in_opt PVOID Parameter2,
+ __in_opt PVOID Context
+ );
+
PHLIBAPI
VOID PhInitializeTreeListNode(
__in PPH_TREELIST_NODE Node
@@ -410,12 +418,4 @@ PPH_STRING PhSaveTreeListColumnSettings(
__in HWND TreeListHandle
);
-__callback BOOLEAN NTAPI PhTreeListNullCallback(
- __in HWND hwnd,
- __in PH_TREELIST_MESSAGE Message,
- __in_opt PVOID Parameter1,
- __in_opt PVOID Parameter2,
- __in_opt PVOID Context
- );
-
#endif
diff --git a/2.x/trunk/phlib/phlib.vcxproj b/2.x/trunk/phlib/phlib.vcxproj
index eb4650212..e40d69f7e 100644
--- a/2.x/trunk/phlib/phlib.vcxproj
+++ b/2.x/trunk/phlib/phlib.vcxproj
@@ -166,6 +166,7 @@
+
@@ -224,6 +225,7 @@
+
diff --git a/2.x/trunk/phlib/phlib.vcxproj.filters b/2.x/trunk/phlib/phlib.vcxproj.filters
index 5ff0c5c89..40a8f30af 100644
--- a/2.x/trunk/phlib/phlib.vcxproj.filters
+++ b/2.x/trunk/phlib/phlib.vcxproj.filters
@@ -201,6 +201,9 @@
Source Files
+
+ Source Files
+
@@ -425,6 +428,9 @@
Header Files
+
+ Header Files
+
diff --git a/2.x/trunk/phlib/treelist.c b/2.x/trunk/phlib/treelist.c
index 1086085da..905334fe1 100644
--- a/2.x/trunk/phlib/treelist.c
+++ b/2.x/trunk/phlib/treelist.c
@@ -2277,6 +2277,17 @@ static VOID PhpReloadThemeData(
}
}
+__callback BOOLEAN NTAPI PhTreeListNullCallback(
+ __in HWND hwnd,
+ __in PH_TREELIST_MESSAGE Message,
+ __in_opt PVOID Parameter1,
+ __in_opt PVOID Parameter2,
+ __in_opt PVOID Context
+ )
+{
+ return FALSE;
+}
+
VOID PhInitializeTreeListNode(
__in PPH_TREELIST_NODE Node
)
@@ -2559,14 +2570,3 @@ PPH_STRING PhSaveTreeListColumnSettings(
return PhFinalStringBuilderString(&stringBuilder);
}
-
-__callback BOOLEAN NTAPI PhTreeListNullCallback(
- __in HWND hwnd,
- __in PH_TREELIST_MESSAGE Message,
- __in_opt PVOID Parameter1,
- __in_opt PVOID Parameter2,
- __in_opt PVOID Context
- )
-{
- return FALSE;
-}
diff --git a/2.x/trunk/tools/peview/include/peview.h b/2.x/trunk/tools/peview/include/peview.h
index 196c40c50..5a548a643 100644
--- a/2.x/trunk/tools/peview/include/peview.h
+++ b/2.x/trunk/tools/peview/include/peview.h
@@ -9,8 +9,23 @@
extern PPH_STRING PvFileName;
#endif
+// peprp
+
VOID PvPeProperties();
+// libprp
+
VOID PvLibProperties();
+// misc
+
+VOID PvCopyListView(
+ __in HWND ListViewHandle
+ );
+
+VOID PvHandleListViewNotifyForCopy(
+ __in LPARAM lParam,
+ __in HWND ListViewHandle
+ );
+
#endif
diff --git a/2.x/trunk/tools/peview/libprp.c b/2.x/trunk/tools/peview/libprp.c
index 99b76c68d..3884d0e88 100644
--- a/2.x/trunk/tools/peview/libprp.c
+++ b/2.x/trunk/tools/peview/libprp.c
@@ -164,6 +164,11 @@ INT_PTR CALLBACK PvpLibExportsDlgProc(
ExtendedListView_SortItems(lvHandle);
}
break;
+ case WM_NOTIFY:
+ {
+ PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST));
+ }
+ break;
}
return FALSE;
diff --git a/2.x/trunk/tools/peview/misc.c b/2.x/trunk/tools/peview/misc.c
new file mode 100644
index 000000000..a4134c113
--- /dev/null
+++ b/2.x/trunk/tools/peview/misc.c
@@ -0,0 +1,56 @@
+/*
+ * Process Hacker -
+ * PE viewer
+ *
+ * Copyright (C) 2011 wj32
+ *
+ * This file is part of Process Hacker.
+ *
+ * Process Hacker is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Process Hacker is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Process Hacker. If not, see .
+ */
+
+#include
+#include
+
+// Copied from appsup.c
+
+VOID PvCopyListView(
+ __in HWND ListViewHandle
+ )
+{
+ PPH_FULL_STRING text;
+
+ text = PhGetListViewText(ListViewHandle);
+ PhSetClipboardStringEx(ListViewHandle, text->Buffer, text->Length);
+ PhDereferenceObject(text);
+}
+
+VOID PvHandleListViewNotifyForCopy(
+ __in LPARAM lParam,
+ __in HWND ListViewHandle
+ )
+{
+ if (((LPNMHDR)lParam)->hwndFrom == ListViewHandle)
+ {
+ LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)lParam;
+
+ switch (keyDown->wVKey)
+ {
+ case 'C':
+ if (GetKeyState(VK_CONTROL) < 0)
+ PvCopyListView(ListViewHandle);
+ break;
+ }
+ }
+}
diff --git a/2.x/trunk/tools/peview/peprp.c b/2.x/trunk/tools/peview/peprp.c
index 0ba56cb00..4756e973b 100644
--- a/2.x/trunk/tools/peview/peprp.c
+++ b/2.x/trunk/tools/peview/peprp.c
@@ -21,6 +21,7 @@
*/
#include
+#include
#define PVM_CHECKSUM_DONE (WM_APP + 1)
@@ -353,6 +354,11 @@ INT_PTR CALLBACK PvpPeGeneralDlgProc(
}
}
break;
+ case WM_NOTIFY:
+ {
+ PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST));
+ }
+ break;
}
return FALSE;
@@ -428,6 +434,11 @@ INT_PTR CALLBACK PvpPeImportsDlgProc(
ExtendedListView_SortItems(lvHandle);
}
break;
+ case WM_NOTIFY:
+ {
+ PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST));
+ }
+ break;
}
return FALSE;
@@ -504,6 +515,11 @@ INT_PTR CALLBACK PvpPeExportsDlgProc(
ExtendedListView_SortItems(lvHandle);
}
break;
+ case WM_NOTIFY:
+ {
+ PvHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST));
+ }
+ break;
}
return FALSE;
diff --git a/2.x/trunk/tools/peview/peview.vcxproj b/2.x/trunk/tools/peview/peview.vcxproj
index fa34745c7..516efe758 100644
--- a/2.x/trunk/tools/peview/peview.vcxproj
+++ b/2.x/trunk/tools/peview/peview.vcxproj
@@ -182,6 +182,7 @@
+
diff --git a/2.x/trunk/tools/peview/peview.vcxproj.filters b/2.x/trunk/tools/peview/peview.vcxproj.filters
index 73bc8f830..285ebfe64 100644
--- a/2.x/trunk/tools/peview/peview.vcxproj.filters
+++ b/2.x/trunk/tools/peview/peview.vcxproj.filters
@@ -24,6 +24,9 @@
Source Files
+
+ Source Files
+