x64: fixed memory-related functionality

git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1688 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
wj32
2009-08-10 09:31:34 +00:00
parent 345bc8ec14
commit 79e13cbb7b
20 changed files with 132 additions and 113 deletions
@@ -53,16 +53,16 @@ namespace ProcessHacker.Common.Ui
public int Compare(ListViewItem x, ListViewItem y, int column)
{
string sx, sy;
int ix, iy;
long ix, iy;
IComparable cx, cy;
sx = x.SubItems[column].Text.Replace(",", "");
sy = y.SubItems[column].Text.Replace(",", "");
if (!int.TryParse(sx.StartsWith("0x") ? sx.Substring(2) : sx,
if (!long.TryParse(sx.StartsWith("0x") ? sx.Substring(2) : sx,
sx.StartsWith("0x") ? NumberStyles.AllowHexSpecifier : 0,
null, out ix) ||
!int.TryParse(sy.StartsWith("0x") ? sy.Substring(2) : sy,
!long.TryParse(sy.StartsWith("0x") ? sy.Substring(2) : sy,
sy.StartsWith("0x") ? NumberStyles.AllowHexSpecifier : 0,
null, out iy))
{
@@ -1511,6 +1511,8 @@ namespace ProcessHacker.Native.Api
Marshal.OffsetOf(typeof(RtlUserProcessParameters), "ImagePathName").ToInt32();
public static readonly int CommandLineOffset =
Marshal.OffsetOf(typeof(RtlUserProcessParameters), "CommandLine").ToInt32();
public static readonly int EnvironmentOffset =
Marshal.OffsetOf(typeof(RtlUserProcessParameters), "Environment").ToInt32();
public static readonly int WindowTitleOffset =
Marshal.OffsetOf(typeof(RtlUserProcessParameters), "WindowTitle").ToInt32();
public static readonly int DesktopInfoOffset =
@@ -1768,7 +1770,7 @@ namespace ProcessHacker.Native.Api
[StructLayout(LayoutKind.Sequential)]
public struct SystemHandleInformation
{
public static readonly int HandlesOffset =
public static readonly int HandlesOffset =
Marshal.OffsetOf(typeof(SystemHandleInformation), "Handles").ToInt32();
public int NumberOfHandles;
+4 -4
View File
@@ -183,7 +183,7 @@ namespace ProcessHacker.Native.Api
public IntPtr BaseAddress;
public IntPtr AllocationBase;
public MemoryProtection AllocationProtect;
public int RegionSize;
public IntPtr RegionSize;
public MemoryState State;
public MemoryProtection Protect;
public MemoryType Type;
@@ -271,7 +271,7 @@ namespace ProcessHacker.Native.Api
public int NumEntries;
public MibUdpRow[] Table;
}
[StructLayout(LayoutKind.Sequential)]
public struct MibUdpRowOwnerPid
{
@@ -289,7 +289,7 @@ namespace ProcessHacker.Native.Api
public int OutDatagrams;
public int NumAddrs;
}
[StructLayout(LayoutKind.Sequential)]
public struct MibUdpTableOwnerPid
{
@@ -602,7 +602,7 @@ namespace ProcessHacker.Native.Api
public int NameLen;
public int MaxNameLen;
public char Name;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct ThreadEntry32
@@ -139,6 +139,26 @@ namespace ProcessHacker.Native
return ptr.Increment(Marshal.SizeOf(typeof(T)));
}
public static bool IsGreaterThanOrEqualTo(this IntPtr ptr, IntPtr ptr2)
{
int result = ptr.CompareTo(ptr2);
if (result == 0 || result == 1)
return true;
return false;
}
public static bool IsLessThanOrEqualTo(this IntPtr ptr, IntPtr ptr2)
{
int result = ptr.CompareTo(ptr2);
if (result == -1 || result == 0)
return true;
return false;
}
public static uint ToUInt32(this IntPtr ptr)
{
// Avoid sign-extending the pointer - we want it zero-extended.
@@ -85,7 +85,7 @@ namespace ProcessHacker.Native.Objects
FileCreationDisposition.OpenAlways
))
{
using (var shandle =
using (var shandle =
SectionHandle.Create(
SectionAccess.All,
SectionAttributes.Image,
@@ -381,10 +381,10 @@ namespace ProcessHacker.Native.Objects
/// <param name="clientId">A Client ID structure describing the process.</param>
/// <param name="access">The desired access to the process.</param>
public ProcessHandle(
string name,
ObjectFlags objectFlags,
DirectoryHandle rootDirectory,
ClientId clientId,
string name,
ObjectFlags objectFlags,
DirectoryHandle rootDirectory,
ClientId clientId,
ProcessAccess access
)
{
@@ -1021,29 +1021,12 @@ namespace ProcessHacker.Native.Objects
IntPtr pebBaseAddress = this.GetBasicInformation().PebBaseAddress;
byte* buffer = stackalloc byte[IntPtr.Size];
this.ReadMemory(pebBaseAddress.Increment(0x10), buffer, IntPtr.Size);
// Get a pointer to the process parameters block.
this.ReadMemory(pebBaseAddress.Increment(Win32.PebProcessParametersOffset), buffer, IntPtr.Size);
IntPtr processParameters = *(IntPtr*)buffer;
/*
* RTL_USER_PROCESS_PARAMETERS
* off field
* +00 ULONG MaximumLength
* +04 ULONG Length
* +08 ULONG Flags
* +0c ULONG DebugFlags
* +10 PVOID ConsoleHandle
* +14 ULONG ConsoleFlags
* +18 HANDLE StdInputHandle
* +1c HANDLE StdOutputHandle
* +20 HANDLE StdErrorHandle
* +24 UNICODE_STRING CurrentDirectoryPath
* +2c HANDLE CurrentDirectoryHandle
* +30 UNICODE_STRING DllPath
* +38 UNICODE_STRING ImagePathName
* +40 UNICODE_STRING CommandLine
* +48 PVOID Environment
*/
this.ReadMemory(processParameters.Increment(0x48), buffer, IntPtr.Size);
// Get a pointer to the environment block.
this.ReadMemory(processParameters.Increment(RtlUserProcessParameters.EnvironmentOffset), buffer, IntPtr.Size);
IntPtr envBase = *(IntPtr*)buffer;
int length = 0;
@@ -1053,7 +1036,7 @@ namespace ProcessHacker.Native.Objects
if (mbi.Protect == MemoryProtection.NoAccess)
throw new WindowsException();
length = mbi.RegionSize - envBase.Decrement(mbi.BaseAddress).ToInt32();
length = mbi.RegionSize.Decrement(envBase.Decrement(mbi.BaseAddress)).ToInt32();
}
// Now we read in the entire region of memory
@@ -1321,7 +1304,7 @@ namespace ProcessHacker.Native.Objects
Win32.ThrowLastError(status);
return value;
}
}
/// <summary>
/// Gets the process' I/O priority, ranging from 0-7.
@@ -1422,10 +1405,10 @@ namespace ProcessHacker.Native.Objects
ProcessModule mainModule = null;
this.EnumModules((module) =>
{
mainModule = module;
return false;
});
{
mainModule = module;
return false;
});
return mainModule;
}
@@ -1628,9 +1611,15 @@ namespace ProcessHacker.Native.Objects
this.ReadMemory(pebBaseAddress.Increment(Win32.PebProcessParametersOffset), buffer, IntPtr.Size);
IntPtr processParameters = *(IntPtr*)buffer;
// read address of string
this.ReadMemory(processParameters.Increment((int)PebOffset.CommandLine + 0x4), buffer, IntPtr.Size);
IntPtr stringAddr = *(IntPtr*)buffer;
// Read the command line UNICODE_STRING structure.
UnicodeString commandLineUs;
this.ReadMemory(
processParameters.Increment(GetPebOffset(PebOffset.CommandLine)),
&commandLineUs,
Marshal.SizeOf(typeof(UnicodeString))
);
IntPtr stringAddr = commandLineUs.Buffer;
/*
* In the POSIX subsystem the command line is actually split up into bits, as in
+1 -2
View File
@@ -223,8 +223,7 @@ namespace ProcessHacker.Native.Security
protected override void DisposeObject(bool disposing)
{
if (_memory != null)
_memory.Dispose(disposing);
_memory.Dispose(disposing);
}
public SidAttributes Attributes
+8 -8
View File
@@ -138,8 +138,8 @@ namespace ProcessHacker.Native
if (!enumCallback(
new KernelModule(
imageBases[i],
name.ToString(),
imageBases[i],
name.ToString(),
FileUtils.FixPath(fileName.ToString())
)))
break;
@@ -185,8 +185,8 @@ namespace ProcessHacker.Native
// tries repeatedly to call the function, doubling the buffer size each time it fails.
while ((status = Win32.NtQuerySystemInformation(
SystemInformationClass.SystemHandleInformation,
data,
data.Size,
data,
data.Size,
out retLength)
) == NtStatus.InfoLengthMismatch)
{
@@ -294,10 +294,10 @@ namespace ProcessHacker.Native
List<KernelModule> kernelModules = new List<KernelModule>();
EnumKernelModules((kernelModule) =>
{
kernelModules.Add(kernelModule);
return true;
});
{
kernelModules.Add(kernelModule);
return true;
});
return kernelModules.ToArray();
}
+10 -9
View File
@@ -353,7 +353,8 @@ namespace ProcessHacker.Components
{
ListViewItem litem = listMemory.Items[newItem.Address.ToString()];
this.FillMemoryListViewItem(litem, newItem);
if (litem != null)
this.FillMemoryListViewItem(litem, newItem);
}
}));
}
@@ -440,7 +441,7 @@ namespace ProcessHacker.Components
MemoryItem item = (MemoryItem)listMemory.SelectedItems[0].Tag;
MemoryEditor.ReadWriteMemory(_pid, item.Address, item.Size, false);
MemoryEditor.ReadWriteMemory(_pid, item.Address, (int)item.Size, false);
}
private void dumpMemoryMenuItem_Click(object sender, EventArgs e)
@@ -461,14 +462,14 @@ namespace ProcessHacker.Components
{
MemoryItem item = (MemoryItem)litem.Tag;
using (MemoryAlloc alloc = new MemoryAlloc(item.Size))
using (MemoryAlloc alloc = new MemoryAlloc((int)item.Size))
{
try
{
unsafe
{
phandle.ReadMemory(item.Address, alloc, item.Size);
fhandle.Write(alloc, item.Size);
phandle.ReadMemory(item.Address, alloc, (int)item.Size);
fhandle.Write(alloc, (int)item.Size);
}
}
catch (WindowsException)
@@ -492,7 +493,7 @@ namespace ProcessHacker.Components
{
IntPtr address = new IntPtr(-1);
IntPtr regionAddress = IntPtr.Zero;
int regionSize = 0;
long regionSize = 0;
bool found = false;
try
@@ -542,7 +543,7 @@ namespace ProcessHacker.Components
return;
}
MemoryEditor m_e = MemoryEditor.ReadWriteMemory(_pid, regionAddress, regionSize, false,
MemoryEditor m_e = MemoryEditor.ReadWriteMemory(_pid, regionAddress, (int)regionSize, false,
new Program.MemoryEditorInvokeAction(delegate(MemoryEditor f) { f.Select(address.Decrement(regionAddress).ToInt64(), 1); }));
}
}
@@ -568,7 +569,7 @@ namespace ProcessHacker.Components
{
MemoryItem item = (MemoryItem)listMemory.SelectedItems[0].Tag;
phandle.FreeMemory(item.Address, item.Size, false);
phandle.FreeMemory(item.Address, (int)item.Size, false);
}
}
catch (Exception ex)
@@ -594,7 +595,7 @@ namespace ProcessHacker.Components
{
MemoryItem item = (MemoryItem)listMemory.SelectedItems[0].Tag;
phandle.FreeMemory(item.Address, item.Size, true);
phandle.FreeMemory(item.Address, (int)item.Size, true);
}
}
catch (Exception ex)
+4 -3
View File
@@ -65,7 +65,8 @@ namespace ProcessHacker
}
}
private int _pid, _length;
private int _pid;
private long _length;
private IntPtr _address;
private byte[] _data;
@@ -74,7 +75,7 @@ namespace ProcessHacker
get { return _pid.ToString() + "-" + _address.ToString() + "-" + _length.ToString(); }
}
public MemoryEditor(int PID, IntPtr Address, int Length)
public MemoryEditor(int PID, IntPtr Address, long Length)
{
InitializeComponent();
this.AddEscapeToClose();
@@ -166,7 +167,7 @@ namespace ProcessHacker
{
_data = new byte[_length];
if (phandle.ReadMemory(_address, _data, _length) == 0)
if (phandle.ReadMemory(_address, _data, (int)_length) == 0)
throw new Exception("Unknown error.");
hexBoxMemory.ByteProvider = new Be.Windows.Forms.DynamicByteProvider(_data);
+22 -20
View File
@@ -297,8 +297,8 @@ namespace ProcessHacker
try
{
int s_a = (int)BaseConverter.ToNumberParse(_so.Searcher.Results[listResults.SelectedIndices[0]][0]) +
(int)BaseConverter.ToNumberParse(_so.Searcher.Results[listResults.SelectedIndices[0]][1]);
long s_a = (long)BaseConverter.ToNumberParse(_so.Searcher.Results[listResults.SelectedIndices[0]][0]) +
(long)BaseConverter.ToNumberParse(_so.Searcher.Results[listResults.SelectedIndices[0]][1]);
var lastInfo = new MemoryBasicInformation();
ProcessHandle phandle;
@@ -315,23 +315,25 @@ namespace ProcessHacker
phandle.EnumMemory((info) =>
{
if (info.BaseAddress.ToInt32() > s_a)
if (info.BaseAddress.ToInt64() > s_a)
{
int selectlength =
(int)BaseConverter.ToNumberParse(_so.Searcher.Results[listResults.SelectedIndices[0]][2]);
long selectlength =
(long)BaseConverter.ToNumberParse(_so.Searcher.Results[listResults.SelectedIndices[0]][2]);
MemoryEditor ed = Program.GetMemoryEditor(_pid, lastInfo.BaseAddress, lastInfo.RegionSize,
MemoryEditor ed = Program.GetMemoryEditor(_pid,
lastInfo.BaseAddress,
lastInfo.RegionSize.ToInt64(),
new Program.MemoryEditorInvokeAction(delegate(MemoryEditor f)
{
try
{
f.ReadOnly = false;
f.Activate();
f.Select(s_a - lastInfo.BaseAddress.ToInt64(), selectlength);
}
catch
{ }
}));
try
{
f.ReadOnly = false;
f.Activate();
f.Select(s_a - lastInfo.BaseAddress.ToInt64(), selectlength);
}
catch
{ }
}));
return false;
}
@@ -349,7 +351,7 @@ namespace ProcessHacker
private void intersectItemClicked(object sender, EventArgs e)
{
List<ListViewItem> newitems = new List<ListViewItem>();
List<int> windowitems = new List<int>();
List<long> windowitems = new List<long>();
string id = ((MenuItem)sender).Tag.ToString();
ResultsWindow window = Program.ResultsWindows[id];
@@ -357,8 +359,8 @@ namespace ProcessHacker
foreach (string[] s in window.Results)
{
windowitems.Add((int)BaseConverter.ToNumberParse(s[0]) +
(int)BaseConverter.ToNumberParse(s[1]));
windowitems.Add((long)BaseConverter.ToNumberParse(s[0]) +
(long)BaseConverter.ToNumberParse(s[1]));
}
ResultsWindow rw = Program.GetResultsWindow(_pid, new Program.ResultsWindowInvokeAction(delegate(ResultsWindow f)
@@ -367,8 +369,8 @@ namespace ProcessHacker
foreach (string[] s in Results)
{
int location = (int)BaseConverter.ToNumberParse(s[0]) +
(int)BaseConverter.ToNumberParse(s[1]);
long location = (long)BaseConverter.ToNumberParse(s[0]) +
(long)BaseConverter.ToNumberParse(s[1]);
if (windowitems.Contains(location))
{
@@ -168,7 +168,7 @@ namespace ProcessHacker
{
phandle.EnumMemory((info) =>
{
for (int i = 0; i < info.RegionSize; i += 0x1000)
for (int i = 0; i < info.RegionSize.ToInt32(); i += 0x1000)
{
try
{
@@ -191,7 +191,7 @@ namespace ProcessHacker
{
phandle.EnumMemory((info) =>
{
phandle.ProtectMemory(info.BaseAddress, info.RegionSize, MemoryProtection.NoAccess);
phandle.ProtectMemory(info.BaseAddress, info.RegionSize.ToInt32(), MemoryProtection.NoAccess);
return true;
});
}
@@ -31,10 +31,11 @@ namespace ProcessHacker
{
public partial class VirtualProtectWindow : Form
{
private int _pid, _size;
private int _pid;
private long _size;
private IntPtr _address;
public VirtualProtectWindow(int pid, IntPtr address, int size)
public VirtualProtectWindow(int pid, IntPtr address, long size)
{
InitializeComponent();
this.AddEscapeToClose();
@@ -74,7 +75,7 @@ namespace ProcessHacker
{
try
{
phandle.ProtectMemory(_address, _size, (MemoryProtection)newprotect);
phandle.ProtectMemory(_address, (int)_size, (MemoryProtection)newprotect);
}
catch (Exception ex)
{
+2 -2
View File
@@ -910,7 +910,7 @@ namespace ProcessHacker
/// <param name="PID">The PID of the process to edit</param>
/// <param name="address">The address to start editing at</param>
/// <param name="length">The length to edit</param>
public static MemoryEditor GetMemoryEditor(int PID, IntPtr address, int length)
public static MemoryEditor GetMemoryEditor(int PID, IntPtr address, long length)
{
return GetMemoryEditor(PID, address, length, new MemoryEditorInvokeAction(delegate {}));
}
@@ -923,7 +923,7 @@ namespace ProcessHacker
/// <param name="length">The length to edit</param>
/// <param name="action">The action to be invoked on the memory editor's thread</param>
/// <returns>Memory editor form</returns>
public static MemoryEditor GetMemoryEditor(int PID, IntPtr address, int length, MemoryEditorInvokeAction action)
public static MemoryEditor GetMemoryEditor(int PID, IntPtr address, long length, MemoryEditorInvokeAction action)
{
MemoryEditor ed = null;
string id = PID.ToString() + "-" + address.ToString() + "-" + length.ToString();
@@ -22,7 +22,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ProcessHacker.Native;
using ProcessHacker.Native.Api;
using ProcessHacker.Native.Objects;
using ProcessHacker.Native.Security;
@@ -39,7 +39,7 @@ namespace ProcessHacker
public int RunId;
public IntPtr Address;
public string ModuleName;
public int Size;
public long Size;
public MemoryType Type;
public MemoryState State;
public MemoryProtection Protection;
@@ -117,7 +117,7 @@ namespace ProcessHacker
item.RunId = this.RunCount;
item.Address = address;
item.Size = info.RegionSize;
item.Size = info.RegionSize.ToInt64();
item.Type = info.Type;
item.State = info.State;
item.Protection = info.Protect;
@@ -129,7 +129,10 @@ namespace ProcessHacker
lastModuleSize = modules[item.Address].Size;
}
if (item.Address.ToInt32() >= lastModuleAddress.ToInt32() && item.Address.ToInt32() < lastModuleAddress.ToInt32() + lastModuleSize)
if (
item.Address.IsGreaterThanOrEqualTo(lastModuleAddress) &&
item.Address.CompareTo(lastModuleAddress.Increment(lastModuleSize)) == -1
)
item.ModuleName = lastModuleName;
else
item.ModuleName = null;
@@ -142,7 +145,7 @@ namespace ProcessHacker
MemoryItem item = this.Dictionary[address];
if (
info.RegionSize != item.Size ||
info.RegionSize.ToInt64() != item.Size ||
info.Type != item.Type ||
info.State != item.State ||
info.Protect != item.Protection
@@ -150,7 +153,7 @@ namespace ProcessHacker
{
MemoryItem newitem = item.Clone() as MemoryItem;
newitem.Size = info.RegionSize;
newitem.Size = info.RegionSize.ToInt64();
newitem.Type = info.Type;
newitem.State = info.State;
newitem.Protection = info.Protect;
@@ -186,7 +186,7 @@ namespace ProcessHacker
modules.Add(info.BaseAddress,
new ProcessModule(
info.BaseAddress,
info.RegionSize,
info.RegionSize.ToInt32(),
IntPtr.Zero,
0,
fi.Name, fi.FullName));
@@ -57,12 +57,12 @@ namespace ProcessHacker
do
{
CallSearchProgressChanged(
String.Format("Searching 0x{0:x} ({1} found)...", heap.dwAddress, count));
String.Format("Searching 0x{0} ({1} found)...", heap.dwAddress.ToString("x"), count));
if (heap.dwBlockSize <= minsize)
continue;
Results.Add(new string[] { String.Format("0x{0:x}", heap.dwAddress),
Results.Add(new string[] { Utils.FormatAddress(heap.dwAddress),
"0x0", heap.dwBlockSize.ToString(), heap.dwFlags.ToString().Replace("LF32_", "") });
count++;
@@ -22,6 +22,7 @@
using System;
using System.Runtime.InteropServices;
using ProcessHacker.Common;
using ProcessHacker.Native.Api;
using ProcessHacker.Native.Objects;
using ProcessHacker.Native.Security;
@@ -81,11 +82,11 @@ namespace ProcessHacker
if ((!opt_map) && (info.Type == MemoryType.Mapped))
return true;
byte[] data = new byte[info.RegionSize];
byte[] data = new byte[info.RegionSize.ToInt32()];
int bytesRead = 0;
CallSearchProgressChanged(
String.Format("Searching 0x{0:x} ({1} found)...", info.BaseAddress, count));
String.Format("Searching 0x{0} ({1} found)...", info.BaseAddress.ToString("x"), count));
try
{
@@ -117,7 +118,7 @@ namespace ProcessHacker
if (good)
{
Results.Add(new string[] { String.Format("0x{0:x}", info.BaseAddress),
Results.Add(new string[] { Utils.FormatAddress(info.BaseAddress),
String.Format("0x{0:x}", i), text.Length.ToString(), "" });
count++;
@@ -97,11 +97,11 @@ namespace ProcessHacker
if ((!opt_map) && (info.Type == MemoryType.Mapped))
return true;
byte[] data = new byte[info.RegionSize];
byte[] data = new byte[info.RegionSize.ToInt32()];
int bytesRead = 0;
CallSearchProgressChanged(
String.Format("Searching 0x{0:x} ({1} found)...", info.BaseAddress, count));
String.Format("Searching 0x{0} ({1} found)...", info.BaseAddress.ToString("x"), count));
try
{
@@ -128,7 +128,7 @@ namespace ProcessHacker
foreach (Match m in mc)
{
Results.Add(new string[] { String.Format("0x{0:x}", info.BaseAddress),
Results.Add(new string[] { Utils.FormatAddress(info.BaseAddress),
String.Format("0x{0:x}", m.Index), m.Length.ToString(),
Utils.MakePrintable(m.Value) });
@@ -82,11 +82,11 @@ namespace ProcessHacker
if ((!opt_map) && (info.Type == MemoryType.Mapped))
return true;
byte[] data = new byte[info.RegionSize];
byte[] data = new byte[info.RegionSize.ToInt32()];
int bytesRead = 0;
CallSearchProgressChanged(
String.Format("Searching 0x{0:x} ({1} found)...", info.BaseAddress, count));
String.Format("Searching 0x{0} ({1} found)...", info.BaseAddress.ToString("x"), count));
try
{
@@ -145,7 +145,7 @@ namespace ProcessHacker
if (isUnicode)
length *= 2;
Results.Add(new string[] { String.Format("0x{0:x}", info.BaseAddress),
Results.Add(new string[] { Utils.FormatAddress(info.BaseAddress),
String.Format("0x{0:x}", i - length), length.ToString(),
curstr.ToString() });
@@ -86,9 +86,9 @@ namespace ProcessHacker
return true;
CallSearchProgressChanged(
String.Format("Searching 0x{0:x} ({1} found)...", info.BaseAddress, count));
String.Format("Searching 0x{0} ({1} found)...", info.BaseAddress.ToString("x"), count));
for (int i = 0; i < info.RegionSize; i += align)
for (int i = 0; i < info.RegionSize.ToInt32(); i += align)
{
try
{
@@ -96,7 +96,7 @@ namespace ProcessHacker
structDef.Read();
// read succeeded, add it to the results
Results.Add(new string[] { String.Format("0x{0:x}", info.BaseAddress),
Results.Add(new string[] { Utils.FormatAddress(info.BaseAddress),
String.Format("0x{0:x}", i), structLen, "" });
count++;
}