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 +