C# Paltalk Class (library)

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

47 thoughts on “C# Paltalk Class (library)

  1. @Chike wrote:

    or are you just looking for the answer to be fed to you?

    Chike is the keeper of the Gerber, and he does not part with it easilly! you must pry it out of his hands ands feed your self 😈

  2. 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.

  3. @Chike wrote:

    This should never happen though, if you are not in the room it means the window is closed, if you are in the room the count cannot be zero.

    ameen

    and yeah NVYE, in general it depends on how you would use the function.
    fun fact, since C# is new to me, I’m still influenced by VB’s sloppiness and C/C++’s rigidity 😀

  4. sounds good and makes sense … I’ll make the changes on the next version … still trying to figure out how to make xml document to html help document so I can provide the API through website.

  5. 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.

  6. 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 🙂

  7. @NVYE wrote:

    TWiZA … I’ll use your library to make a Video Tutorial … I hope you don’t mind … I will give you full credit toward it.

    of course. It would be good if someone shows how to use it or even improve it since I lack time to do it 😉
    Thanks.

  8. Errors fall into twocategories, errors that you expect as part of nornal exceution, and errors that signify something went terribly wrong and there is no point continue excecution.
    For the first “if”s should be used. for the second exceptions are apropriate.

    The exceptions code in normal flow of the program doesn’t or ahould not have any overhead but that make their execution when raised very slow, something that is not desireable as part of normal execution, and therefore they are not a substitute for “if”s.

    In fact all of the “if”s in this particular example(getUserNames) fall into the second category and should throw an exception.

  9. 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 😀

  10. 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.

  11. ‘@Locohacker, I was worried why this Topic were so crouded hahah, everyone beside me has commented 🙁

    @Chike, I agree with you. Thats why I respect my Teachers in school hahah

    @Antigeek, Its allright mate, and as Locohacker said Chike is Straight Person! I dont think he wanted to be rude, but just says things directly! I dont think that in this forum there is a person who is more *DUMBER* than me when It comes to C# or using the SEARCH in this case.. But yet tho I asked for help in the forums, and CHIKE as the only person who kept up with me and my stupid questions for a whole week EVERYDAY.

    😀 I might have been very lucky that Chike has NEVER been rude to me or said anything to be rude, but instead he been straight up a head when he has to say something! Thanks for that I have become more interested in Chike 😀 In a way of a Student and a Teacher ofcourse.

    Here is a bit of my Headaches where Chike helped me with to the finish line: https://www.imfiles.com/how-to-get-a-reaction-on-a-recieved-pm-t43484/

    Even when I was done, he Did not stop lool here https://www.imfiles.com/auto-reply-for-paltalk-messenger-t43493/

    BIG THANKS TO CHIKE AND TO EVERYONE WHO ARE PROVIDING HELP ON HERE ! (FOR FREE)

  12. @antigeek wrote:

    I notice on the newer build get users not working… Given error… Anyone else getting this error?

    Have you realized there is a search feature on the forum or that you can actually debug it yourself or are you just looking for the answer to be fed to you?

  13. Honestly you don’t have to be a dick about it… Since I Figure it out But I figure it out with a little bit of ready on how to use spy++ Thanks for your none help… Have a nice day…

  14. @Chike wrote:

    @antigeek wrote:

    I notice on the newer build get users not working… Given error… Anyone else getting this error?

    Have you realized there is a search feature on the forum or that you can actually debug it yourself or are you just looking for the answer to be fed to you?

    You’ve ask me if I realized if there a search feature yes of course I do… I’m not so good with api… Is all I’m saying I’ve search the forum I seen nothing about it I seen someone asking for grabbing room list but not the userlist

  15. @locohacker wrote:

    OMG you r so rude lol but you straight up I like that 🙂
    And antigeek if you here long enough you gonna learn to love chike he is a cool dude he just have a funny way of telling people things including me hehehe but I still love him 😀

    I really wouldn’t consider him as a cool person… First all he thinking he some kind of coder god when it coming to API… I drop the API, Now I’m just logging into Paltalk using a bot No need for API. Paltalk service was pretty easy to crack… Have fun guys using API…

  16. Ouch 🙂 can we all just get alone, and you both are correct, its better to do search before asking, but Chike you was kindna rude lol and you always so nice 🙂

  17. OMG you r so rude lol but you straight up I like that 🙂
    And antigeek if you here long enough you gonna learn to love chike he is a cool dude he just have a funny way of telling people things including me hehehe but I still love him 😀

  18. @antigeek wrote:

    @locohacker wrote:

    OMG you r so rude lol but you straight up I like that 🙂
    And antigeek if you here long enough you gonna learn to love chike he is a cool dude he just have a funny way of telling people things including me hehehe but I still love him 😀

    I really wouldn’t consider him as a cool person… First all he thinking he some kind of coder god when it coming to API… I drop the API, Now I’m just logging into Paltalk using a bot No need for API. Paltalk service was pretty easy to crack… Have fun guys using API…

    I dont think the API is to crack paltalk..

  19. @deeva2 wrote:

    I dont think the API is to crack paltalk..

    The Windows API can be used to try to crack applications, but that is not the only use. The Windows API is what programs use to function. When you add a control or object (such as a text box) to your program, you do not code how that control or object works as that has already been done, you just use it. But that control has been built using windows APIs.

    @antigeek wrote:

    I drop the API, Now I’m just logging into Paltalk using a bot No need for API

    This is just laughable. They try to claim that they dropped using the Windows API and instead used a bot and were able to hack the pal servers. A bot is a program and not a replacement for API. Basicly when they say that they gave up API for bot, they are saying that they let others do the programming for them and they are just using someone elses coding work. But that still would not allow them to hack the pal servers.

    It is idiots like this that I try to just ignore because it is so obvious that they have no clue about what they are doing.

  20. Antigeek, the “non” Api code you just wrote does indeed use Api, while not directly in your code but functions from the framework calls Api functions, intact you can almost think of most programming languageu as one large wrapper for calling Ali functions and procedures. All high level languages do. Maybe if your coded it in assembly your claim might be valid. Even coding in assembly some times requireapi functions

  21. @autopilot wrote:

    @antigeek wrote:

    I had some kiddie try to comment on my post.. To make me look stupid… I should had just left it be..

    yep you should have. first i’m not a kiddie and your own post makes you look stupid all on its own. no one else needed to post to make you look stupid.

    LAWL yea I’m making my self look stupid if I do it so well why you keep posting toward me? Can you explain to me where in any of my comment made me look stupid?

  22. every time you post you show the whole world so I’m not gonna repost all your posts… just read up instead of continuing to beg to be spoon feed…

  23. Ah yeah you’re not using “API” you are using a framework, big difference.

    The fact one knows how to write a line of code does not negat the possibility of him being an idiot.

  24. @Chike wrote:

    Ah yeah you’re not using “API” you are using a framework, big difference.

    The fact one knows how to write a line of code does not negat the possibility of him being an idiot.

    Honestly bro not really worried about it… I had some kiddie try to comment on my post.. To make me look stupid… I should had just left it be..

  25. @antigeek wrote:

    I had some kiddie try to comment on my post.. To make me look stupid… I should had just left it be..

    yep you should have. first i’m not a kiddie and your own post makes you look stupid all on its own. no one else needed to post to make you look stupid.

  26. 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;
    }
  27. (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;
    }

     

  28. Ahehe. Your avatar makes me feel awkward 😀

    @autopilot can you help me with something? I seem to be getting ONLY the last line from the chatrom instead of the person’s whole message.

    Public Function GetLastLineTextChat(ByVal hwnd As IntPtr, ByRef iLastLine As Integer) As String()
    Dim iLineCount As Integer
    Dim strBuffer As New StringBuilder(255)
    Dim sText() As String = Nothing
    'Get Line count
    iLineCount = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0)
    ' if first time run, ignore previous chat
    If iLastLine = 0 Then iLastLine = iLineCount
    ' Only process if new lines are present
    If iLineCount > iLastLine Then
    ' Process till no new lines are left
    Do While iLastLine <= iLineCount
    ' Increase Last Line Count
    iLastLine = iLastLine + 1
    ' Check string array
    If sText Is Nothing Then
    'set up string array with 1 element
    ReDim sText(0)
    Else
    ' redim array with 1 extra element
    ReDim Preserve sText(sText.Length)
    End If
    'get line text in last element of string array
    sText(sText.Length - 1) = ReadLine(hwnd, iLastLine - 2)
    If iLastLine = iLineCount Then
    Exit Do
    End If
    Loop
    ' If last line is greater then line count,
    ' set last line = line count and then
    ' process last line
    ElseIf iLineCount < iLastLine Then
    iLastLine = iLineCount
    ReDim sText(0)
    'get line text
    sText(sText.Length - 1) = ReadLine(hwnd, iLastLine - 2)
    End If
    Return sText
    End Function

    Example:

    Deeva2: hello all and have
    a good day

    (will only return “a good day”)
    I’ll troubleshoot while I wait for a reply.

  29. @autopilot wrote:

    @deeva2 wrote:

    I dont think the API is to crack paltalk..

    The Windows API can be used to try to crack applications, but that is not the only use. The Windows API is what programs use to function. When you add a control or object (such as a text box) to your program, you do not code how that control or object works as that has already been done, you just use it. But that control has been built using windows APIs.

    @antigeek wrote:

    I drop the API, Now I’m just logging into Paltalk using a bot No need for API

    This is just laughable. They try to claim that they dropped using the Windows API and instead used a bot and were able to hack the pal servers. A bot is a program and not a replacement for API. Basicly when they say that they gave up API for bot, they are saying that they let others do the programming for them and they are just using someone elses coding work. But that still would not allow them to hack the pal servers.

    It is idiots like this that I try to just ignore because it is so obvious that they have no clue about what they are doing.

    I’m a idiot? lmao Yea I have no clue what I’m doing Your right, why pal service header is 6 bytes long? Haha Trust me kiddie I’m not using api to do shit with paltalk…Here just a small little pm packet to show I don’t know what I’m doing and that I’m a idiot..

    private static string pmUser(userId as string, message as string)
    {
    string len = Encoding.Default.GetString(new byte[] { (byte)(message.Length / 0x100), (byte)(message.Length % 0x100) });
    StringBuilder packetBuilder = new StringBuilder();
    packetBuilder.Append("/xFF/xEC/0/x76"); //Header = FF Payload type = EC Version = 76
    packetBuilder.Append(len); //Pm Payload Length
    packetBuilder.Append(userid); //user uid
    packetbuilder.Append(message); //message of the pm
    string str = packetBuilder.ToString();
    return str;
    }
  30. Yes, nice idea.
    and about this:

    public string[] getAllRoomsAndPms()
    {
    // Confusing static method ... hmm... but okay for now
    TwzPaltalkClass.refreshRooms();
    return TwzPaltalkClass.getRooms();
    }

    refreshRooms() indeed this has no business being outside. You can call it inside getRooms() and make a private static instead of public static.

  31. 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.

  32. 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 😉

  33. 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
  34. @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. 😀

  35. Another thing, If you want to use rich text box to send. You have to change..

    [DllImport("user32.dll")]
    private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, string lParam);

    To

    [DllImport("user32.dll", EntryPoint = "SendMessageW")]
    private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, string lParam);

    So it will send the Rtb raw code right….

Leave a Reply

You must Register or Login to comment on C# Paltalk Class (library)