Skip to content
Home > Programming > C# Paltalk Class (library)

C# Paltalk Class (library)

Viewing 15 posts - 1 through 15 (of 48 total)
  • Author
    Posts
  • #191057
    TWiZA
    Member

    Hi Folks, This is a Lite version of the class I use in my programs rewritten in C#. Notes: 1) There is no exceptions nor errors handling in this example whatsoever. (sorry) 2) I have not test it much so there maybe some bugs. 3) Still need some tweaks 4) heads up: this class has events 5) I have included a test program, give it time when you go though it before asking questions. 6) I tried to comment a lot, but I may have zapped some spots. 7) I did not bother to add the function that closes the bounce dialog. (sorry I run out of time) 8) I rarely have free time, and I used it to write this code. So it would be nice of you to it give me credit/ shout out if you use it or a part of it. That would encourage me to share more.

    /*************************************************************************************************************/
    /* Paltalk Class by TWiZA */
    /*************************************************************************************************************/
    
    using System;
    using System.Runtime.InteropServices;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Diagnostics;
    
    namespace twzPaltalkClass
    {
    class twzPaltalkClass
    {
    
    #region winAPI
    
    private delegate int EnumWin(IntPtr hWnd, IntPtr lparam);
    
    [DllImport("user32.dll")]
    private static extern int EnumWindows(EnumWin FuncCall, IntPtr lParam);
    
    [DllImport("user32.dll")]
    private static extern IntPtr EnumChildWindows(IntPtr hWndParent, EnumWin FuncCall, IntPtr lParam);
    
    [DllImport("User32.dll")]
    private static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
    
    [DllImport("User32.dll")]
    private static extern IntPtr FindWindowEx(IntPtr hWnd1, IntPtr hWnd2, String lpszClsName, String lpszWndTitle);
    
    [DllImport("user32.dll")]
    public static extern bool SetWindowText(IntPtr hwnd, StringBuilder lpString);
    
    [DllImport("User32.dll")]
    private static extern int GetWindowText(IntPtr hWnd, StringBuilder str, int nMaxCount);
    
    [DllImport("User32.dll")]
    private static extern int GetWindowTextLength(IntPtr hWnd);
    
    [DllImport("user32.dll")]
    private static extern IntPtr GetDesktopWindow();
    
    [DllImport("user32.dll")]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
    
    [DllImport("user32.dll")]
    private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
    
    [DllImport("user32.dll")]
    private static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, IntPtr lParam);
    
    [DllImport("user32.dll")]
    private static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);
    
    [DllImport("user32.dll")]
    private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, String lParam);
    
    [DllImport("user32.dll")]
    private static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, StringBuilder lParam);
    
    [DllImport("user32.dll")]
    private static extern int PostMessage(IntPtr hWnd, int wMsg, int wParam, IntPtr lParam);
    
    //sendmessage consts
    private const int WM_SYSCOMMAND = 0x0112;
    private const int WM_COMMAND = 0x0111;
    private const int WM_SETTEXT = 0x000C;
    private const int WM_KEYDOWN = 0x0100;
    private const int WM_KEYUP = 0x0101;
    private const int WM_GETTEXT = 0x000D;
    private const int WM_GETTEXTLENGTH = 0x000E;
    private const int BM_CLICK = 0x00F5;
    private const int BM_GETCHECK = 0x00F0;
    
    [DllImport("user32.dll")]
    private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
    
    [DllImport("kernel32.dll")]
    private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    
    [DllImport("kernel32.dll")]
    private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, int flAllocType, int flProtect);
    
    [DllImport("kernel32.dll")]
    private static extern int VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, int dwFreeType);
    
    [DllImport("kernel32.dll")]
    private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
    
    [DllImport("kernel32.dll")]
    private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref LVITEM lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
    
    [DllImport("kernel32.dll")]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref LVITEM buffer, int size, out IntPtr lpNumberOfBytesRead);
    
    [DllImport("kernel32.dll")]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, StringBuilder buffer,int size, out IntPtr lpNumberOfBytesRead);
    
    [DllImport("kernel32.dll")]
    private static extern bool CloseHandle(IntPtr hObject);
    
    //process memory consts
    private const int PROCESS_VM_OPERATION = 0x0008;
    private const int PROCESS_VM_READ = 0x0010;
    private const int PROCESS_VM_WRITE = 0x0020;
    private const int MAX_LVMSTRING = 0x00FF;
    private const int MEM_COMMIT = 0x1000;
    private const int MEM_DECOMMIT = 0x4000;
    private const int MEM_RELEASE = 0x8000;
    private const int PAGE_READWRITE = 0x0004;
    
    //SysListView32 consts
    private const int LVIF_TEXT = 0x0001;
    private const int LVIF_IMAGE = 0x0002;
    private const int LVIF_STATE = 0x0008;
    private const int LVIF_ALLFLAGS = 0xFFFF;
    
    private const int LVM_FIRST = 0x1000;
    private const int LVM_FINDITEM = 0x100D;
    private const int LVM_GETITEMPOSITION = 0x1010;
    private const int LVM_GETITEM = (LVM_FIRST + 75);
    private const int LVM_GETITEMTEXT = (LVM_FIRST + 45);
    private const int LVM_GETITEMCOUNT = (LVM_FIRST + 4);
    private const int LVM_SETITEMSTATE = (LVM_FIRST + 43);
    private const int LVM_GETITEMSTATE = (LVM_FIRST + 44);
    private const int LVM_GETNEXTITEM = (LVM_FIRST + 12);
    
    private const int LVIS_SELECTED = 0x0002;
    private const int LVIS_FOCUSED = 0x0001;
    private const int LVIS_STATEIMAGEMASK = 0xF000;
    private const int LVIS_UNCHECKED = 0x1000;
    private const int LVIS_CHECKED = 0x2000;
    
    private const int LVFI_PARTIAL = 0x0008;
    private const int LVFI_STRING = 0x0002;
    
    [StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
    private struct LVITEM
    {
    public int mask;
    public int iItem;
    public int iSubItem;
    public int state;
    public int stateMask;
    public IntPtr pszText;
    public int cchTextMax;
    public int iImage;
    public IntPtr lParam;
    }
    
    #endregion
    
    #region Local consts and variables
    
    /***********************************************************************************************************************/
    private const int SEND_RICHEDIT_INDEX = 1; //since paltalk keeps updating and changing the order of the richedit's
    private const int RECV_RICHEDIT_INDEX = 2; // using const makes updates easy
    private const int SYSVIEWLIST_SUBITEM = 0; //the SystListView32 subitem that has the username string
    /************************************************************************************************************************/
    
    public enum PaltalkCmd : int // some of these values may be obsolete, I got em from paltalk 9.x
    { // also you can user ressource hacker to add more
    REMOVE_HANDS = 32995,
    REMOVE_MICS = 32996,
    GIVE_MICS = 32997,
    ADMIN_CONSOLE = 32998,
    BOUNCE = 32947,
    REDDOT = 32946,
    LOWER_HAND = 32950,
    VOICE_ACTIVATED = 33344,
    PUSH_TALK = 33343,
    LOCK_MIC = 33340,
    FREEZE_TEXT = 210,
    ROOM_IGNORE = 33003,
    ROOM_START_PM = 32901,
    ROOM_ADD_USER = 32898,
    ROOM_BLOCK_USER = 33381,
    INVIT_USERS = 32989,
    INSERT_NICK = 33379,
    EXIT_ROOM = 32849
    }
    
    public enum PaltalkUserStat : int
    {
    NONE = 0,
    REDDOT = 5,
    CAM_ON = 1,
    ON_MIC = 10,
    R_HAND = 20,
    ERROR = 255 // added by me to use in case of error, not from paltalk
    }
    
    private static List _roomNameList = new List();
    private static List _roomHwndList = new List();
    
    private List _richEditHandles = new List();
    
    private IntPtr _roomHwnd = IntPtr.Zero;
    private IntPtr _listHwnd = IntPtr.Zero;
    private IntPtr _sendHwnd = IntPtr.Zero;
    private IntPtr _recvHwnd = IntPtr.Zero;
    
    private Timer _textTimer = new Timer(); // Text timer
    private List oldText = new List(); // to store old chat text
    
    #endregion
    
    #region Events
    
    public event EventHandler OnText; // TODO: add events here if you wish
    public event EventHandler OnUserJoined;
    public event EventHandler OnUserLeft;
    public event EventHandler OnAlert;
    public event EventHandler OnWhisper;
    
    #endregion
    
    #region Public Static functions + Constructor
    
    public static void refreshRooms()
    {
    _roomHwndList.Clear();
    _roomNameList.Clear();
    EnumWindows(new EnumWin(dlgFindRooms),IntPtr.Zero); //all the good stuff is happening in "dlgFindRooms" callback
    
    }
    
    public static string[] getRooms()
    {
    return _roomNameList.ToArray();
    }
    
    public twzPaltalkClass(string roomName) // constructor
    {
    refreshRooms();
    
    if (_roomNameList.Count > 0)
    {
    _roomHwnd = _roomHwndList[_roomNameList.IndexOf(roomName)];
    _richEditHandles.Clear();
    EnumChildWindows(_roomHwnd, new EnumWin(dlgFindControls), IntPtr.Zero);
    
    _sendHwnd = _richEditHandles[SEND_RICHEDIT_INDEX]; //<<<<<< test here
    _recvHwnd = _richEditHandles[RECV_RICHEDIT_INDEX];
    
    _textTimer.Interval = 500;
    _textTimer.Enabled = true;
    _textTimer.Tick += new System.EventHandler(parseText);
    
    //SendMessage(_sendHwnd, WM_SETTEXT, IntPtr.Zero, " send");
    //SendMessage(_recvHwnd, WM_SETTEXT, IntPtr.Zero, " recv");
    //postTextToTheRoom("wuzzup");
    //sendCommand(PaltalkCmd.ADMIN_CONSOLE);
    
    }
    }
    
    #endregion
    
    #region Public functions: send text/ send command
    
    public void postTextToTheRoom(string txt)
    {
    SendMessage(_sendHwnd, WM_SETTEXT, IntPtr.Zero, txt);
    PostMessage(_sendHwnd, WM_KEYDOWN, 13, IntPtr.Zero);
    PostMessage(_sendHwnd, WM_KEYUP, 13, IntPtr.Zero);
    
    }
    
    public void sendCommand(PaltalkCmd cmd)
    {
    SendMessage(_roomHwnd, WM_COMMAND, (int)cmd, IntPtr.Zero);
    
    }
    
    #endregion
    
    #region Public functions: UserNames related
    
    public string[] getUserNames()
    
    {
    int lvCount = SendMessage(_listHwnd, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
    
    if (lvCount == 0) return null;
    
    int ProcessID = 0;
    int strLength = 0;
    
    StringBuilder strBuffer;
    
    string[] userNameArray = new string[lvCount];
    LVITEM lvLocalItem = new LVITEM();
    
    GetWindowThreadProcessId(_listHwnd, out ProcessID);
    
    IntPtr processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, ProcessID);
    
    //ListViewItem
    lvLocalItem.mask = LVIF_TEXT;
    lvLocalItem.iSubItem = SYSVIEWLIST_SUBITEM;
    lvLocalItem.pszText = VirtualAllocEx(processHandle, IntPtr.Zero, MAX_LVMSTRING, MEM_COMMIT, PAGE_READWRITE); // alloc memory for the username string
    lvLocalItem.cchTextMax = MAX_LVMSTRING;
    
    IntPtr lvMemItem = VirtualAllocEx(processHandle, IntPtr.Zero, Marshal.SizeOf(lvLocalItem), MEM_COMMIT, PAGE_READWRITE); // alloc memory for my whole ListviewItem
    
    IntPtr tmpOut = (IntPtr)0; // null pointer to use with Read/Write process memory (last parameter)
    
    WriteProcessMemory(processHandle, lvMemItem, ref lvLocalItem, Marshal.SizeOf(lvLocalItem), out tmpOut);
    
    for( int i = 0; i < lvCount; i++)
    {
    strLength = SendMessage(_listHwnd, LVM_GETITEMTEXT, i, lvMemItem);
    
    strBuffer = new StringBuilder(strLength-1);
    
    ReadProcessMemory(processHandle, lvLocalItem.pszText, strBuffer, strLength, out tmpOut);
    
    userNameArray[i] = strBuffer.ToString();
    strBuffer.Clear();
    
    }
    
    VirtualFreeEx(processHandle, lvLocalItem.pszText, 0, MEM_RELEASE);
    VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
    CloseHandle(processHandle);
    
    return userNameArray;
    }
    
    public string getHighLightedUserName()
    {
    int lvCount = SendMessage(_listHwnd, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
    
    if (lvCount == 0) return String.Empty;
    
    for (int i = 0; i < lvCount; i++)
    {
    if(SendMessage(_listHwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED) != 0) // if the username is selected
    {
    int ProcessID = 0;
    int strLength = 0;
    
    StringBuilder strBuffer;
    
    string[] userNameArray = new string[lvCount];
    LVITEM lvLocalItem = new LVITEM();
    
    GetWindowThreadProcessId(_listHwnd, out ProcessID);
    
    IntPtr processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, ProcessID);
    
    //ListViewItem
    lvLocalItem.mask = LVIF_TEXT;
    lvLocalItem.iSubItem = SYSVIEWLIST_SUBITEM;
    lvLocalItem.pszText = VirtualAllocEx(processHandle, IntPtr.Zero, MAX_LVMSTRING, MEM_COMMIT, PAGE_READWRITE); // alloc memory for the username string
    lvLocalItem.cchTextMax = MAX_LVMSTRING;
    
    IntPtr lvMemItem = VirtualAllocEx(processHandle, IntPtr.Zero, Marshal.SizeOf(lvLocalItem), MEM_COMMIT, PAGE_READWRITE); // alloc memory for my whole ListviewItem
    
    IntPtr tmpOut = (IntPtr)0; // null pointer to use with Read/Write process memory (last parameter)
    
    WriteProcessMemory(processHandle, lvMemItem, ref lvLocalItem, Marshal.SizeOf(lvLocalItem), out tmpOut);
    
    strLength = SendMessage(_listHwnd, LVM_GETITEMTEXT, i, lvMemItem);
    
    strBuffer = new StringBuilder(strLength - 1);
    
    ReadProcessMemory(processHandle, lvLocalItem.pszText, strBuffer, strLength, out tmpOut);
    
    VirtualFreeEx(processHandle, lvLocalItem.pszText, 0, MEM_RELEASE);
    VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
    CloseHandle(processHandle);
    
    return strBuffer.ToString();
    
    }//end if
    
    }//end for
    
    return String.Empty;
    }
    
    public void highLightUserName(string strUserName)
    {
    int lvCount = SendMessage(_listHwnd, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
    
    if (lvCount != 0)
    {
    UnHighLightAllUserNames();
    
    int ItemIndex = getUserNameIndex(strUserName);
    
    if (ItemIndex != -1)
    {
    
    int ProcessID = 0;
    
    LVITEM lvLocalItem = new LVITEM();
    
    GetWindowThreadProcessId(_listHwnd, out ProcessID);
    
    IntPtr processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, ProcessID);
    
    //ListViewItem
    lvLocalItem.mask = LVIF_STATE;
    lvLocalItem.state = LVIS_SELECTED;
    lvLocalItem.stateMask = LVIS_SELECTED;
    
    IntPtr lvMemItem = VirtualAllocEx(processHandle, IntPtr.Zero, Marshal.SizeOf(lvLocalItem), MEM_COMMIT, PAGE_READWRITE); // alloc memory for my whole ListviewItem
    
    IntPtr tmpOut = (IntPtr)0; // null pointer to use with Read/Write process memory (last parameter)
    
    WriteProcessMemory(processHandle, lvMemItem, ref lvLocalItem, Marshal.SizeOf(lvLocalItem), out tmpOut);
    
    SendMessage(_listHwnd, LVM_SETITEMSTATE, ItemIndex, lvMemItem);
    
    VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
    CloseHandle(processHandle);
    
    }//end if itemIndex
    
    }//end if lvCount
    
    }
    
    public int getUserNameStatus(string strUser) //reddot onmic raisehand
    {
    int lvCount = SendMessage(_listHwnd, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
    int ret = 255;
    
    if (lvCount != 0)
    {
    
    int ProcessID = 0;
    LVITEM lvLocalItem = new LVITEM();
    int itemIndex = getUserNameIndex(strUser);
    
    GetWindowThreadProcessId(_listHwnd, out ProcessID);
    
    IntPtr processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, ProcessID);
    
    //ListViewItem
    lvLocalItem.mask = LVIF_IMAGE;
    lvLocalItem.iItem = itemIndex;
    lvLocalItem.iSubItem = 0;
    
    IntPtr lvMemItem = VirtualAllocEx(processHandle, IntPtr.Zero, Marshal.SizeOf(lvLocalItem), MEM_COMMIT, PAGE_READWRITE); // alloc memory for my whole ListviewItem
    
    IntPtr tmpOut = (IntPtr)0; // null pointer to use with Read/Write process memory (last parameter)
    
    WriteProcessMemory(processHandle, lvMemItem, ref lvLocalItem, Marshal.SizeOf(lvLocalItem), out tmpOut);
    
    SendMessage(_listHwnd, LVM_GETITEM, itemIndex, lvMemItem);
    
    if (ReadProcessMemory(processHandle, lvMemItem, ref lvLocalItem, Marshal.SizeOf(lvLocalItem), out tmpOut))
    ret = lvLocalItem.iImage;
    
    VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
    CloseHandle(processHandle);
    
    return ret;
    
    }//end if lvCount
    
    return ret; //error
    }
    
    #endregion
    
    #region private mixed functions
    
    private static int dlgFindRooms(IntPtr hWnd, IntPtr lparam) //callback (parameter of EnumWindows) function to find rooms' windows handles
    {
    
    StringBuilder tmp = new StringBuilder(255);
    
    GetClassName(hWnd, tmp, 255);
    
    if (tmp.ToString().Contains("DlgGroupChat Window Class"))
    {
    tmp.EnsureCapacity(255);
    GetWindowText(hWnd, tmp, 255);
    
    if (tmp.ToString().Contains(" Voice Room"))
    {
    _roomNameList.Add(tmp.ToString().Substring(0, tmp.ToString().IndexOf(" - Voice Room")));
    _roomHwndList.Add(hWnd);
    }
    
    }
    
    return 1;
    }
    
    private int dlgFindControls(IntPtr hWnd, IntPtr lparam) // callback function (parameter of EnumChildWindows) to find
    { // handles of richedits and sysviewlist
    
    StringBuilder tmp = new StringBuilder(255);
    
    GetClassName(hWnd, tmp, 255);
    
    if (tmp.ToString().Contains("SysListView32"))
    {
    _listHwnd = hWnd;
    }
    
    if ((tmp.ToString().Contains("RichEdit20W"))) // using lparam to return handles won't make any sense in this example
    { // since I'm assigning the results to my class's private variables
    _richEditHandles.Add(hWnd); //storing all richedit's handles in a list
    }
    
    return 1;
    }
    
    private int getUserNameIndex(string strUser)
    {
    
    int lvCount = SendMessage(_listHwnd, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
    
    if (lvCount == 0) return -1;
    
    int ProcessID = 0;
    int strLength = 0;
    
    StringBuilder strBuffer;
    
    LVITEM lvLocalItem = new LVITEM();
    
    GetWindowThreadProcessId(_listHwnd, out ProcessID);
    
    IntPtr processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, ProcessID);
    
    //ListViewItem
    lvLocalItem.mask = LVIF_TEXT;
    lvLocalItem.iSubItem = SYSVIEWLIST_SUBITEM;
    lvLocalItem.pszText = VirtualAllocEx(processHandle, IntPtr.Zero, MAX_LVMSTRING, MEM_COMMIT, PAGE_READWRITE); // alloc memory for the username string
    lvLocalItem.cchTextMax = MAX_LVMSTRING;
    
    IntPtr lvMemItem = VirtualAllocEx(processHandle, IntPtr.Zero, Marshal.SizeOf(lvLocalItem), MEM_COMMIT, PAGE_READWRITE); // alloc memory for my whole ListviewItem
    
    IntPtr tmpOut = (IntPtr)0; // null pointer to use with Read/Write process memory (last parameter)
    
    WriteProcessMemory(processHandle, lvMemItem, ref lvLocalItem, Marshal.SizeOf(lvLocalItem), out tmpOut);
    
    for (int i = 0; i < lvCount; i++)
    {
    strLength = SendMessage(_listHwnd, LVM_GETITEMTEXT, i, lvMemItem);
    
    strBuffer = new StringBuilder(strLength - 1);
    
    ReadProcessMemory(processHandle, lvLocalItem.pszText, strBuffer, strLength, out tmpOut);
    
    if (strUser == strBuffer.ToString()) return i; //match -> return item index
    strBuffer.Clear();
    
    }
    
    VirtualFreeEx(processHandle, lvLocalItem.pszText, 0, MEM_RELEASE);
    VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
    CloseHandle(processHandle);
    
    return -1; //no match
    }
    
    private void UnHighLightAllUserNames()
    {
    int lvCount = SendMessage(_listHwnd, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
    
    if (lvCount != 0)
    {
    
    int ProcessID = 0;
    
    LVITEM lvLocalItem = new LVITEM();
    
    GetWindowThreadProcessId(_listHwnd, out ProcessID);
    
    IntPtr processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, ProcessID);
    
    //ListViewItem
    lvLocalItem.mask = LVIF_STATE;
    lvLocalItem.state = 0;
    lvLocalItem.stateMask = LVIS_SELECTED;
    
    IntPtr lvMemItem = VirtualAllocEx(processHandle, IntPtr.Zero, Marshal.SizeOf(lvLocalItem), MEM_COMMIT, PAGE_READWRITE); // alloc memory for my whole ListviewItem
    
    IntPtr tmpOut = (IntPtr)0; // null pointer to use with Read/Write process memory (last parameter)
    
    WriteProcessMemory(processHandle, lvMemItem, ref lvLocalItem, Marshal.SizeOf(lvLocalItem), out tmpOut);
    
    for( int i = 0; i < lvCount; i++)
    {
    SendMessage(_listHwnd, LVM_SETITEMSTATE, i, lvMemItem);
    }
    
    VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
    CloseHandle(processHandle);
    
    }//end if lvCount
    
    }
    
    private void parseText(object sender, EventArgs e)
    {
    
    List newText = new List();
    
    int len = SendMessage(_recvHwnd, WM_GETTEXTLENGTH, 0, 0);
    
    StringBuilder tmp = new StringBuilder(len);
    
    SendMessage(_recvHwnd, WM_GETTEXT, len, tmp);
    
    newText.AddRange(tmp.ToString().Split(new char[1] { 'n' }));
    
    if (oldText.Count == 0) // getting chatroom text for the first time
    {
    oldText.AddRange(newText.ToArray());
    }
    else
    {
    
    int lastIndex = 0;
    
    for (int i = 0; i < newText.Count; i++)
    {
    if (newText[i].TrimEnd(new char[1] { 'r' }) == oldText[oldText.Count - 1]) lastIndex = i;
    }
    
    string tmpStr = String.Empty;
    string tmpStr2 = String.Empty;
    
    for (int i = lastIndex + 1; i < newText.Count; i++)
    {
    
    tmpStr = newText[i].TrimEnd(new char[1] { 'r' }).Trim();
    
    if (tmpStr.StartsWith("(")) // in case the timestamp is enabled
    {
    tmpStr = tmpStr.Replace(tmpStr.Substring(0, tmpStr.IndexOf(")") + 2), "");
    }
    
    if (tmpStr.StartsWith("*** ") && tmpStr.Contains(" has left the room ***"))
    {
    tmpStr2 = tmpStr.Substring(tmpStr.IndexOf(" ")).Substring(1, tmpStr.IndexOf(" has left the room ***") - 4);
    this.OnUserLeft(">" + tmpStr2 + "<", new EventArgs());
    }
    else if ((tmpStr.StartsWith("*** ")) && (tmpStr.Contains(" has joined the room ***")))
    {
    tmpStr2 = tmpStr.Substring(tmpStr.IndexOf(" ")).Substring(1, tmpStr.IndexOf(" has joined the room ***") - 4);
    this.OnUserJoined(">" + tmpStr2 + "<", new EventArgs());
    }
    else if (tmpStr.StartsWith("Whispering "))
    {
    //blah, no use
    }
    
    else if (tmpStr.StartsWith("*** End"))
    {
    //blah, no use
    }
    
    else if (tmpStr.StartsWith(">>> "))
    {
    // when user starts or turns off camera. TODO: create events for it.
    }
    
    else if (tmpStr.StartsWith("***** Private Whisper from: "))
    {
    //raise event OnWhisper
    tmpStr = tmpStr.Split(new char[] { ':' })[1].Trim();
    tmpStr2 = newText[++i];
    
    OnWhisper(tmpStr + ":" + tmpStr2, new EventArgs());
    }
    
    else if (tmpStr.StartsWith("Alert: "))
    {
    //raise event OnAlert
    OnAlert(tmpStr, new EventArgs());
    }
    else
    {
    //raising the event OnText
    if( tmpStr.Trim() != "" )
    this.OnText(tmpStr, new EventArgs());
    
    }
    
    }
    
    }
    
    oldText.Clear();
    oldText.AddRange(newText.ToArray());
    // updating the old room text
    
    }
    
    #endregion
    
    }//end class

     

    >>> the regions are there to help you navigating through the code.
    twzPtkBaseClass

    #191104
    String
    Member

    Nice share..

    #191103
    ChiNa
    Administrator

    Awesome Share.. Thanks A Lot… And keep up your amazing programming …

    I really like your simple Admin Boards, I am trying hard to make one myself, with MouseOver Effect and so on!
    Wish me good luck 😀

    #191102
    TWiZA
    Member

    Thanks. I will wish good persistence instead because coding has nothing to do with luck :))

    #191101
    TWiZA
    Member

    alright, this function is working, but I forgot the clean up:

    private int getUserNameIndex(string strUser)

    these lines must be executed before the function returns the username’s index and exits:

    VirtualFreeEx(processHandle, lvLocalItem.pszText, 0, MEM_RELEASE);
    VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
    CloseHandle(processHandle);

    I randomly noticed this, but my code may have more. Also, not planing to update it, so DIY 😉

    #191100
    ChiNa
    Administrator

    @TWiZA wrote:
    alright, this function is working, but I forgot the clean up:

    private int getUserNameIndex(string strUser)

    these lines must be executed before the function returns the username’s index and exits:

    VirtualFreeEx(processHandle, lvLocalItem.pszText, 0, MEM_RELEASE);
     VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
     CloseHandle(processHandle);

    I randomly noticed this, but my code may have more. Also, not planing to update it, so DIY 😉

    Hi Twiz… Thank you for the reply / Good Persistance / and for cleanup code. 😀

    #191099
    AhFox
    Member

    looks good … I need it … thanks.

    #191098
    Chike
    Member

    Better practice is to have the return value as local variable initialized with -1, and break the loop on success.
    Also, however unlikely it to be, OpenHandle, VirtualAllocEx, and Even SendMessage callas may fail, so ifs are nesessary, for both execution and cleanup.

    #191097
    TWiZA
    Member

    I agree. As I stated in the notes, there is no exception or error management in this code. it’s meant to be an example of OOP and some paltalk functions. It is kind of Take ‘n Bake code lol. The class written in VB used in my programs is written with better practices. Thanks for your remarks 🙂

    #191096
    Chike
    Member

    And BTW why “strBuffer = new StringBuilder(strLength – 1);” If afterwards you read strLength?
    The only way it works is if the C# strings are inplemented as null-terminated strings and allocated memory is actually larger than requested.
    If the result of LVM_GETITEMTEXT includes the nullterminating character than it souldn’t be copied, otherwise strLength must be allocated.

    Another thing is the use of strBuffer.Clear, there is simply no need for it if a new one is always created, and for better efficiency, create the StringBuilder with MAX_LVMSTRING outside the loop, and set it’s length in each loop.

    #191095
    TWiZA
    Member

    (Chike you are making me revise my code after I decides that I’m done with it. nd with this method of paltalk programming in general 🙂 )

    @TWiZA wrote:

    Another thing is the use of strBuffer.Clear, there is simply no need for it if a new one is always created, and for better efficiency, create the StringBuilder with MAX_LVMSTRING outside the loop, and set it’s length in each loop.

    strBuffer should be declared outside the loop indeed.
    aAso (strLength – 1) was a makeshift to avoid getting garbage at the end of my string. But I kind of omitted that since everything was working. I’ve done quite a bit of debugging since this my first C# code. In fact, the whole thing is a sort of draft and I know there are more flaws.

    Thanks for pointing them out to me and to others who are reading.

    This looks better I think:

    public string[] getUserNames()
    
    {
    int lvCount = SendMessage(_listHwnd, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
    
    if (lvCount == 0) return null;
    
    int ProcessID = 0;
    
    string[] userNameArray = new string[lvCount];
    LVITEM lvLocalItem = new LVITEM();
    
    GetWindowThreadProcessId(_listHwnd, out ProcessID);
    
    IntPtr processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, ProcessID);
    
    //ListViewItem
    lvLocalItem.mask = LVIF_TEXT;
    lvLocalItem.iSubItem = SYSVIEWLIST_SUBITEM;
    lvLocalItem.pszText = VirtualAllocEx(processHandle, IntPtr.Zero, MAX_LVMSTRING, MEM_COMMIT, PAGE_READWRITE); // alloc memory for the username string
    lvLocalItem.cchTextMax = MAX_LVMSTRING;
    
    IntPtr lvMemItem = VirtualAllocEx(processHandle, IntPtr.Zero, Marshal.SizeOf(lvLocalItem), MEM_COMMIT, PAGE_READWRITE); // alloc memory for my whole ListviewItem
    
    IntPtr tmpOut = (IntPtr)0; // null pointer to use with Read/Write process memory (last parameter)
    
    WriteProcessMemory(processHandle, lvMemItem, ref lvLocalItem, Marshal.SizeOf(lvLocalItem), out tmpOut);
    
    StringBuilder strBuffer = new StringBuilder();
    
    for( int i = 0; i < lvCount; i++)
    {
    strBuffer.Length = SendMessage(_listHwnd, LVM_GETITEMTEXT, i, lvMemItem);
    
    ReadProcessMemory(processHandle, lvLocalItem.pszText, strBuffer, strBuffer.Length, out tmpOut);
    
    userNameArray = strBuffer.ToString();
    
    }
    
    VirtualFreeEx(processHandle, lvLocalItem.pszText, 0, MEM_RELEASE);
    VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
    CloseHandle(processHandle);
    
    return userNameArray;
    }

     

    #191094
    Chike
    Member

    Well you maybe done with it, but others are just starting, best show them how good code should be written.
    A few more changes and it’s near perfect, providing I don’t have any syntax errors, I don’t have C# installed

    public string[] getUserNames()
    {
    int lvCount = SendMessage(_listHwnd, LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
    if (lvCount == 0) return null;
    int ProcessID = 0;
    GetWindowThreadProcessId(_listHwnd, out ProcessID);
    IntPtr processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, ProcessID);
    uf (processHandle == IntPtr.Zero) return null; // error, no match
    //ListViewItem
    LVITEM lvLocalItem = new LVITEM();
    lvLocalItem.mask = LVIF_TEXT;
    lvLocalItem.iSubItem = SYSVIEWLIST_SUBITEM;
    lvLocalItem.pszText = VirtualAllocEx(processHandle, IntPtr.Zero, MAX_LVMSTRING, MEM_COMMIT, PAGE_READWRITE); // alloc memory for the username string
    lvLocalItem.cchTextMax = MAX_LVMSTRING;
    string[] userNameArray = null;
    if (lvLocalItem.pszText != IntPtr.Zero) {
    IntPtr lvMemItem = VirtualAllocEx(processHandle, IntPtr.Zero, Marshal.SizeOf(lvLocalItem), MEM_COMMIT, PAGE_READWRITE); // alloc memory for my whole ListviewItem
    if (lvMemItem != IntPtr.Zero) {
    userNameArray = new string[lvCount];
    IntPtr tmpOut = IntPtr.Zero; // null pointer to use with Read/Write process memory (last parameter)
    WriteProcessMemory(processHandle, lvMemItem, ref lvLocalItem, Marshal.SizeOf(lvLocalItem), out tmpOut);
    StringBuilder strBuffer = new StringBuilder(MAX_LVMSTRING);
    for( int i = 0; i &lt; lvCount; i++)
    {
    strBuffer.Length = SendMessage(_listHwnd, LVM_GETITEMTEXT, i, lvMemItem);
    ReadProcessMemory(processHandle, lvLocalItem.pszText, strBuffer, strBuffer.Length, out tmpOut);
    userNameArray<i> = strBuffer.ToString();</i>
    }
    VirtualFreeEx(processHandle, lvMemItem, 0, MEM_RELEASE);
    }
    VirtualFreeEx(processHandle, lvLocalItem.pszText, 0, MEM_RELEASE);
    }
    CloseHandle(processHandle);
    return userNameArray;
    }
    #191093
    TWiZA
    Member

    I agree that is proper coding. However, one of the reasons (other than being lazy lol) that I omitted handling exceptions in this example is to help others understand. I Didn’t want surcharge the code. if there are too many “IFs” and conditions some people may get lost. In fact, that is a true story, when I started looking online for examples of how to steal another process’s memory, I got lost and confused.
    Thanks for time 🙂
    ps: there is just one typo here :

    uf (processHandle == IntPtr.Zero) return null; // error, no match
    #191092
    Chike
    Member

    What can we do, error handling is part of programming as errors are expected for various reasons.
    The code could be made look better for example by making wrapper functions to the windows API that throw exceptions on error.
    Another ,ethos that I’ve used a lot in the past is to make classes to do the alloc/cleanup which let you exit the function at any point and minimize the need for “if”s.
    There will still be a need for at least one “try” block with either of the methids.

    #191091
    AhFox
    Member

    I’m currently looking at the function … since the return type is string[]

    if (lvCount == 0) return null; I think to make the programming easier ... instead of return null should return.
    
    if (lvCount == 0) return new string[] { }; // this returns an empty array;
    
    This way the programmer doesn't check for null ... still work if he / she has
    
    foreach (string username in usernames) {
    /// since the list is empty ... doesn't call it .. and doesn't blow up.
    }

    beside that looks good.

Viewing 15 posts - 1 through 15 (of 48 total)
  • You must be logged in to reply to this topic.