Click here to Skip to main content
14,879,723 members
Home / Discussions / Managed C++/CLI
   

Managed C++/CLI

 
GeneralRe: LNK2019: unresolved external Pin
af0000124-Oct-13 6:35
Memberaf0000124-Oct-13 6:35 
AnswerRe: LNK2019: unresolved external Pin
Freak3023-Oct-13 23:07
MemberFreak3023-Oct-13 23:07 
GeneralRe: LNK2019: unresolved external Pin
Richard MacCutchan23-Oct-13 23:32
mveRichard MacCutchan23-Oct-13 23:32 
GeneralRe: LNK2019: unresolved external Pin
af0000124-Oct-13 6:34
Memberaf0000124-Oct-13 6:34 
GeneralRe: LNK2019: unresolved external Pin
af0000124-Oct-13 6:33
Memberaf0000124-Oct-13 6:33 
AnswerRe: LNK2019: unresolved external Pin
WuRunZhe22-Nov-13 15:23
MemberWuRunZhe22-Nov-13 15:23 
GeneralRe: LNK2019: unresolved external Pin
af0000123-Nov-13 2:35
Memberaf0000123-Nov-13 2:35 
QuestionAnyone can help me ? Pin
gecko2k121-Oct-13 18:34
Membergecko2k121-Oct-13 18:34 
The below is GList.H
#ifndef __GLIST_H
#define __GLIST_H

#include <assert.h>
#include <STDIO.H>
#include <STDLIB.H>
#include <STRING.H>
#include <STRNG.H>
#include <MALLOC.H>

typedef enum bool { false, true};

/* -------------------- Define class GList ----------------- */
class GList
{
   private:
     char    **arr;
     int     length;
     void    FillEmptyAll(int);
     void    ResizeList(int);
     void    SetArr(char **);
     void    SetLen(size_t);
     char    **GetArr() { return arr; }

   public:
     size_t  GetLen();
     void    Add(const char*);
     void    Add(String);
     void    SetValue(size_t, const char*);
     void    SetValue(size_t, String);
     char*   GetValue(size_t);
     void    InsertValue(size_t, const char*);
     void    InsertValue(size_t, String);
     void    FillEmptyRange(size_t, size_t);
     void    CreateMemList(size_t);
    // void    ResizeMemList(int);
     void    RemoveAt(size_t);
     void    RemoveRange(size_t, size_t);
     void    RemoveValue(const char *);
     void    RemoveValue(String);
     void    RemoveAllValue(const char *);
     void    RemoveAllValue(String);

	     GList();
	     GList(const GList& L); //Copy constructor
	     //GList(const GList* &L);
	     GList&  operator=(const GList& L); //assignment operator =
	     //GList&  operator=(const GList* &L);
     virtual ~GList();
};

/* Constructor */
inline GList::GList(void)
{
   length = 1;
   arr    = (char**) malloc(sizeof(char*) * length);
   //arr    = NULL;
}

/* Define Copy Constructor */
inline GList::GList(const GList& L): length(L.length),
				     arr((char**)malloc(sizeof(char*) * L.length))
{
   int idx = L.length - 1;
   for(int i = 0; i < idx; i++){
      *(arr + i) = *(L.arr + i);
   }
   *(arr + idx) = 0;
}

/* Define operator = */
inline GList& GList::operator=(const GList& L)
{
   if (this == &L) return *this;
   else
   {
      length = L.length;
      if (arr != 0)
      {
	 free(arr);
	 arr = 0;
      }
      arr     = (char**)malloc(sizeof(char*) * L.length);
      int idx =  L.length - 1;
      for(int i = 0; i < idx; i++)
	 *(arr + i) = *(L.arr + i);

      *(arr + idx) = 0;
   }
   return *this;
}

/* Destructor */
inline GList::~GList()
{
   if (arr != 0)
   {
      free(arr);
      //arr = NULL;
   }
    printf("Destructor GList");
}

/* -------------- Define Property for GList ------------*/

/* Fill All Value in arr = "" ----------- */
void GList::FillEmptyAll(int len)
{
   for(int i = 0; i < len; i++)
      *(arr + i) = strdup("");
   *(arr + len) = 0;
}

/* -------- Fill Empty Value from startAt, to startEnd ----------- */
void GList::FillEmptyRange(size_t startAt, size_t startEnd)
{
   if (startEnd - startAt <= 0) return;
   //for(int i = startAt; i < startEnd-1; i++)
   for(int i = startAt; i < startEnd; i++)
       //*(arr + i) = strdup("");
      SetValue(i, "");
}

/* --------- Create List with numData Value and Fill it empty ----- */
/* example GList(3), create 4 blocks : 3 contains data, 1 pointer NULL */
void GList::CreateMemList(size_t numData)
{
   if (numData == 0 || numData == 1)
   {
      length = 1;
      if (arr != 0)
	 free(arr);
      arr    = (char**) malloc(sizeof(char*) * length);

   }
   else
   {
      //if (this->arr) free(this->arr);
      //length = numData + 1;
      length = numData;
      if (arr != 0)
      {
	 free(arr);
	 arr = 0;
      }
      arr = (char**) malloc(sizeof(char*) * length);
      if (arr == 0)
      {
	  printf("Create new memory for List failed! Not enough memory");
	  abort();
      }
      /* Fill empty value to array */
      FillEmptyAll(length - 1);
   }
}

/* ----------- Return length of GList ------------ */
size_t GList::GetLen(void)
{
   if (length == 0)
      return 0;

   return length-1;
}

/* ------------ Replace new value at Index ------------- */
void GList::SetValue(size_t index, const char *value)
{
  //if ((index < 0) || (index >= GetLen()))
  if (index >= GetLen())
     return;
  else
     *(arr + index) = strdup(value);
}

void GList::SetValue(size_t index, String value)
{
  char *string = strdup(value);
  SetValue(index, string);

  if (string != NULL)
     delete string;
}

/* ---------------- Set new length for pointer array ------------ */
/* Warning : new length may be effect by GetValue --------------- */
void GList::SetLen(size_t newlength)
{
  if (newlength <= 1)
    length = 1;

  length = newlength;
}

/* ---------- Set pointer array to GList ---------- */
/* Warning : new pointer array must same size old pointer array */
void GList::SetArr(char **array)
{
   arr = array;
}

/* ---------- Return value at Index ------------ */
char* GList::GetValue(size_t index)
{
   if (index >= GetLen() || index < 0)
      return NULL;
   else
      return *(arr + index);
}

/* ---------- Insert new value at index to GList ------------- */
void GList::InsertValue(size_t index, const char *value)
{
   char **newarr   = 0;
   int  i;
   int  newLen     = 0;
   int  idx        = 0;
   int  oldLen     = length - 1;

   if (index > oldLen || index < 0)
      return;

   length = length + 1; /* new real length assignment */
   idx    = length - 1;
   /* assign new array with new length */
   newarr = (char**) malloc(sizeof(char*) * length);
   if (newarr == 0)
   {
      printf("Insert new value to List failed! Not enought memory.");
      abort();
   }
   for(i = 0; i < index; i++)
       *(newarr + i) = *(arr + i);

   for(i = idx - 1; i > index; i--)
       *(newarr + i) = *(arr + (i-1));
   /* Insert new value to index */
   *(newarr + index) = strdup(value);
   /* assign NULL to last newarr */
   assert(idx = length - 1);
   *(newarr + idx) = 0;

   /* Free memory on old arr */
   if (arr != 0)
   {
      free(arr);
      arr  =  0;
   }
   arr     =  newarr;
   newarr  =  0;
   if (newarr == 0)
      delete newarr;
}

/* ---------- Insert new value at index to GList ------------- */
void GList::InsertValue(size_t index, String value)
{
   char *str = strdup(value);
   InsertValue(index, str);

   if (str != NULL)
      delete str;
}


/* -------- Add new value to GList at last position ---------*/
void GList::Add(const char *value)
{
   int idx  = length - 1;
   if (idx <= 0)
   {
      length = 2;
      if (arr != 0)
      {
	 free(arr);
	 arr = 0;
      }
      arr = (char**) malloc(sizeof(char*) * length);
      if (arr == 0)
      {
	 printf("Add new value to List failed!");
	 abort();
      }
      *(arr + 0) = strdup(value);
      *(arr + (length -1)) = 0;
   }
   else if (idx >= 1)
   {
      length++;
      char **newarr = 0;
      newarr = (char**) malloc(sizeof(char*) * length);
      if (newarr == 0)
      {
	printf("Add new value to List failed!\n");
	abort();
      }
      /* Copy data from old array to new array */
      for(int i = 0; i < idx; i++)
	 *(newarr + i) = *(arr + i);

      *(newarr + idx++) = strdup(value);
      assert(idx = length - 1);
      *(newarr + idx)   = 0;

   /* Free-up old array */
      if (arr != 0)
      {
	 free(arr);
	 arr = 0;
      }
      arr    = newarr;
      newarr = 0;

      if (newarr == 0)
	delete newarr;
   }
}

void GList::Add(String value)
{
   char *str = strdup(value);
   Add(str);

   if (str != NULL)
      delete str;
      //str = NULL;

}

/* ---------- Remove value at Index --------------- */
void GList::RemoveAt(size_t index)
{
   int i, idx;
   int len       = length - 1;


   idx = length - 1; /* Take old GetLen of old array arr */
   if (index >= len || idx == 0)
      return;

   /* Move data */
   for(i = index; i < idx - 1; i++)
   {
      *(arr + i) = *(arr + (i+1));
   }
   length = length - 1;
   char **newarr;
   /* Create new pointer array */
   newarr = (char**) malloc(sizeof(char*) * length);
   if (newarr == NULL)
   {
      printf("Remove at index %i in List failed!", index);
      abort();
   }
   /* Copy data from old arr to new arr */
   idx = idx - 1; /* Take new GetLen() for new array */
   for(i = 0; i < idx; i++)
      *(newarr + i) = *(arr + i);

   assert(idx = length - 1);
   *(newarr + idx) = 0;

   /*Free-up old array */
   if (arr != 0)
   {
      free(arr);
      arr = 0;
   }
   arr    = newarr;
   newarr = 0;
   if (newarr == 0)
      delete newarr;
}

/* ----------- Remove Range at startAt to startEnd from List ------- */
void GList::RemoveRange(size_t startAt, size_t startEnd)
{
   int  oldLen        = length - 1;
   int  numRemoveData = startEnd - startAt + 1;  /* Number of value Remove */
   int  numMoveData   = oldLen - numRemoveData - startAt; /* Number of value will be move */
   int  index         = 0;
   int  lock          = 0; /* key take NULL */

   if ((numRemoveData < 0) || startEnd > oldLen -1)
       return;

    /* Move oldLen - StartEnd value to Index startAt */
   for(index = 0; index < numMoveData; index++)
       *(arr + (index + startAt)) = *(arr + (startEnd + index + 1));

   if (startEnd == oldLen - 1)
       lock = startAt;
   else if (startEnd < oldLen - 1)
       lock = startAt + numMoveData;

   length = length - numRemoveData;
   if (length <= 1)
   {
       free(arr);
       arr    = 0;
       length = 1;
   }
   else if (length > 1)
   {
      char** newarr= 0;
      /* Create new array */
      newarr = (char**) malloc(sizeof(char*) * length);
      if (newarr == 0)
      {
	 printf("Remove range %i to %i  from List failed!",startAt, startEnd);
	 abort();
      }
      /* Copy value from old array to new array */
      for(index = 0; index < lock; index++)
	 *(newarr + index) = *(arr + index);

      assert(lock = length - 1);
      *(newarr + lock) = 0;

      /* Free-up old array */
      if (arr != 0)
      {
	 free(arr);
	 arr   =  0;
      }
      arr      =  newarr;
      newarr   =  0;
      if (newarr == 0)
	 delete newarr;
   }
}

/* ----------- Remove value in GList ------------- */
void GList::RemoveValue(const char *value)
{
   int pos    = 0;
   int index  = 0;
   bool found = false;
   int len    = length - 1;

   if ((value == NULL) || (len == 0)) return;
   while ((index < len) && !found)
   {
      pos = strcmp(arr[index],value);
      if (pos == 0)
	 found = true;
      else
	 index++;
   }
   if (found)
      RemoveAt(index);
}

void GList::RemoveValue(String value)
{
   char *str = strdup(value);
   RemoveValue(str);

   if (str != NULL)
      delete str;
}

/* ------------ Remove All Value contain string ----------- */
void GList::RemoveAllValue(const char *string)
{
   int  index      = 0;
   int  pos        = 0;

   if (string == NULL) return;
   while (index < GetLen())
   {
      pos = strcmp(*(arr + index), string);
      if (pos == 0)
	 RemoveAt(index);
      else
	 index++;
   }
}

void GList::RemoveAllValue(String string)
{
   char *str = strdup(string);
   RemoveAllValue(str);
   if (str != NULL)
      delete str;
}

/* ------------------ End of GList ------------------- */
#endif


/* -------------------------------------------------------------- */
/* INIClass.H */
/* Author : Nguyen Hong Phuc */
/* Copyright c 2013 */
/* -------------------------------------------------------------- */

#ifndef __INICLASS_H
#define __INICLASS_H

#include "HPCLASS.H"
#include <stdio.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>

typedef enum ErrorCode {
Success = 0,
Invalid_PathFile = 1,
Invalid_Command = 2,
Invalid_Key = 4,
Invalid_Subkey = 6,
Invalid_CreateFile = 8,
Invalid_FileExisted = 10,
Invalid_FileName = 12,
Invalid_Parameters = 14,
Unknown_Error = 16
};

There is INIClass :
class INIClass : public GList
{
private:
GList fLines;
GList pList;

char *PathFileName;
char *cmdT;
ErrorCode error;
void InitStringProtocol();
void InitStringSystem();
int Initialize();
int CreateProtocol();
int CreateSystem();
int ReadFromFile();
int WriteToFile();
void CommandCreate(const char*);

public:
int Finaliaze();
//INIClass(char *[]);
INIClass(GList);
~INIClass();
};

inline INIClass::INIClass(GList mList)
{
error = Success;
PathFileName = "";
cmdT = "";

pList = mList;
pList.RemoveAt(0);
PathFileName = pList.GetValue(0);
pList.RemoveAt(0);
cmdT = pList.GetValue(0);
pList.RemoveAt(0);
//fLines.Add(" ");
//Initialize();
//fLines = NULL;
}

/* Deconstructor for INIClass */
inline INIClass::~INIClass(void)
{
//delete error;
//delete cmdT;
//delete PathFileName;
printf("\nDestructor INIClass.\n");
}

/* ------------- Define Property and Function for INIClass ----------------- */

int INIClass::Finaliaze(void)
{
int exit_code = 0;
return exit_code = Initialize();
}

int INIClass::Initialize()
{
int iType = -1;
char *cmdType[] = {"create", "remove", "read", "write", "edit"};

for(int i = 0; i < sizeof(cmdType) / sizeof(cmdType[0]); i++)
{
if (strcmp(cmdType[i], Trim(cmdT)) == 0)
{
iType = i;
break;
}
}
switch (iType)
{
case 0: //create
if (pList.GetLen() == 0)
error = Invalid_Parameters;
else
{
printf("Command Create is call.");
CommandCreate(pList.GetValue(0));
}
break;


default:
error = Invalid_Parameters;
break;
}
return error;
}

/* Initilize for Protocol */
void INIClass::InitStringProtocol()
{
fLines.Add("; Protocol.ini auto generated by NETCFG - File created by Hong Phuc");
fLines.Add("; ONLY SUPPORT FOR MYSELF, IF NEED TO USE PLEASE RE-EDIT");
fLines.Add("; PLEASE DO NOT REMOVE ANY LINE BELOW");
fLines.Add("[network.setup]");
fLines.Add("version=0x3110");
fLines.Add("netcard=hp2$nic,1,HP2$NIC,1");
fLines.Add("transport=hp2$ndishlp,HP2$NDISHLP");
fLines.Add("transport=hp2$netbeui,HP2$NETBEUI");
fLines.Add("lana0=hp2$nic,1,hp2$netbeui");
fLines.Add("lana1=hp2$nic,1,hp2$ndishlp");
//fLines.Add("\n");
fLines.Add("[HP2$NETBEUI]");
fLines.Add("NCBS=8");
fLines.Add("SESSIONS=3");
fLines.Add("DRIVERNAME=netbeui$");
fLines.Add("BINDINGS=HP2$NIC");
fLines.Add("LANABASE=0");
//fLines.Add("\n");
fLines.Add("[PROTMAN]");
fLines.Add("DriverName=PROTMAN$");
fLines.Add("PRIORITY=PKTDRV$");
//fLines.Add("\n");
fLines.Add("[PKTDRV]");
fLines.Add("DriverName=PKTDRV$");
fLines.Add("BINDINGS=HP2$NIC");
fLines.Add("intvec=0x60");
fLines.Add("chainvec=0x66");
//fLines.Add("\n");
fLines.Add("[HP2$NDISHLP]");
fLines.Add("DriverName=ndishlp$");
fLines.Add("BINDINGS=HP2$NIC");
//fLines.Add("\n");
fLines.Add("[HP2$NIC]");
}

/* Initialize for System */
void INIClass::InitStringSystem()
{
fLines.Add("; System.ini auto generated by NETCFG - File created by Hong Phuc");
fLines.Add("; ONLY SUPPORT FOR MYSELF, IF NEED TO USE PLEASE RE-EDIT.");
fLines.Add("; PLEASE DO NOT REMOVE ANY LINE BELOW");
fLines.Add("[386enh]");
fLines.Add("TimerCriticalSection=5000");
fLines.Add("UniqueDosPSP=TRUE");
fLines.Add("PSPIncrement=2");
//fLines.Add("\n");
fLines.Add("[network]");
fLines.Add("filesharing=no");
fLines.Add("printsharing=no");
fLines.Add("autologon=no");
fLines.Add("reconnect=yes");
fLines.Add("dospophotkey=N");
fLines.Add("lmlogon=<edit_by_netcfg>");
fLines.Add("preferredredir=<edit_by_netcfg>");
fLines.Add("autostart=<edit_by_netcfg>");
fLines.Add("maxconnections=8");
fLines.Add("sizworkbuff=1498");
//fLines.Add("\n");
fLines.Add("username=<edit_by_netcfg>");
fLines.Add("workgroup=<edit_by_netcfg>");
fLines.Add("computername=<edit_by_netcfg>");
fLines.Add("lanroot=<edit_by_netcfg>");
//fLines.Add("\n");
fLines.Add("[network drivers]");
fLines.Add("LoadRMDrivers=yes");
fLines.Add("transport=<edit_by_netcfg>");
fLines.Add("netcard=<edit_by_netcfg>");
fLines.Add("devdir=<edit_by_netcfg>");
}

//This function is create the Protocol.ini file
int INIClass::CreateProtocol(void)
{
printf("Creating Protocol.");
if (!Contains(PathFileName, "\\protocol.ini"))
{
if (!EndWith(PathFileName, "\\"))
PathFileName = strcat(PathFileName, "\\protocol.ini");
else
PathFileName = strcat(PathFileName, "protocol.ini");
}
if (FileExist(PathFileName))
error = Invalid_FileExisted;
else
{
InitStringProtocol();
error = WriteToFile();
}
return error;
}

//This function is create the System.ini file
int INIClass::CreateSystem(void)
{
//string strPathFile = PathFile;
if (!Contains(PathFileName, "\\system.ini"))
{
if (!EndWith(PathFileName, "\\"))
PathFileName = strcat(PathFileName, "\\system.ini");
else
PathFileName = strcat(PathFileName, "system.ini");
}
if (FileExist(PathFileName))
error = Invalid_FileExisted;
else
{
InitStringSystem();
error = WriteToFile();
}
return error;
}

int INIClass::ReadFromFile()
{
FILE *fname;
char data[256];

fname = fopen(PathFileName, "r");
if (fname != NULL)
{

while (!feof(fname))
{
fgets(data, 256, fname);
fLines.Add(Trim(data));
}
fclose(fname);
error = Success;
}
else
error = Invalid_PathFile;

return error;
}

int INIClass::WriteToFile()
{
FILE *stream;

printf("WTF call, PathFile = %s\n",PathFileName);
if (FileExist(PathFileName))
{
if (remove(PathFileName) == -1)
return error = Invalid_FileName;
}
stream = fopen(PathFileName, "wt");

if (stream != NULL)
{
for (int i = 0; i < fLines.GetLen(); i++)
{
char *value = fLines.GetValue(i);;
//write(handle, value, strlen(value));
fprintf(stream, value);
fprintf(stream, "\n");
}
fclose(stream);
error = Success;
}
else
error = Invalid_PathFile;

return error;
}


//This function is create an Protocol.ini/System.ini. Return : 0 - success
void INIClass::CommandCreate(const char *strType)
{
int iType = -1;

char *ctype[] = {"pro", "protocol", "sys", "system"};
for(int i = 0; i < sizeof(ctype) / sizeof(ctype[0]); i++)
{
if (strcmp(ctype[i], Trim(strType)) == 0)
{
iType = i;
break;
}
}
switch (iType)
{
case 0:
case 1:
printf("Create Protocol");
error = CreateProtocol();
break;

case 2:
case 3:
error = CreateSystem();
break;

default:
error = Invalid_Command;
break;
}
}
/* ----------------- End of INIClass --------------- */

#endif


#include <iniclass.h>
#include <hpclass.h>
#include <stdio.h>
#include <conio.h>

void main(int argc, char* argv[])
{
   //clrscr();
   int exit = 0;
   GList mList(Split(argv));
   INIClass ini(mList);
   exit = ini.Finaliaze();
   printf("\nEnd program - Exit code : %i",exit);
   //delete ini;
}


When Compile and Run with arguments :
c:\Testini.exe c:\obj create protocol

The file c:\obj\protocol.ini is created but Null pointer assignments is display. I don't know why.
AnswerRe: Anyone can help me ? Pin
Marco Bertschi21-Oct-13 22:15
professionalMarco Bertschi21-Oct-13 22:15 
Questionhow can I draw real-time curve in coordinate system? Pin
wuxuangle18-Oct-13 21:41
Memberwuxuangle18-Oct-13 21:41 
AnswerRe: how can I draw real-time curve in coordinate system? Pin
Richard MacCutchan19-Oct-13 2:38
mveRichard MacCutchan19-Oct-13 2:38 
GeneralRe: how can I draw real-time curve in coordinate system? Pin
wuxuangle22-Oct-13 3:47
Memberwuxuangle22-Oct-13 3:47 
GeneralRe: how can I draw real-time curve in coordinate system? Pin
Richard MacCutchan22-Oct-13 5:58
mveRichard MacCutchan22-Oct-13 5:58 
GeneralRe: how can I draw real-time curve in coordinate system? Pin
wuxuangle22-Oct-13 15:40
Memberwuxuangle22-Oct-13 15:40 
GeneralRe: how can I draw real-time curve in coordinate system? Pin
Richard MacCutchan22-Oct-13 21:02
mveRichard MacCutchan22-Oct-13 21:02 
GeneralRe: how can I draw real-time curve in coordinate system? Pin
wuxuangle22-Oct-13 22:47
Memberwuxuangle22-Oct-13 22:47 
AnswerRe: how can I draw real-time curve in coordinate system? Pin
Marco Bertschi21-Oct-13 22:16
professionalMarco Bertschi21-Oct-13 22:16 
GeneralRe: how can I draw real-time curve in coordinate system? Pin
wuxuangle22-Oct-13 3:50
Memberwuxuangle22-Oct-13 3:50 
Questionvisual studio 2008 QT project with c++ Pin
Mkhitar Sargsyan12-Oct-13 3:17
MemberMkhitar Sargsyan12-Oct-13 3:17 
AnswerRe: visual studio 2008 QT project with c++ Pin
Richard MacCutchan12-Oct-13 5:14
mveRichard MacCutchan12-Oct-13 5:14 
AnswerRe: visual studio 2008 QT project with c++ Pin
Albert Holguin15-Oct-13 8:02
professionalAlbert Holguin15-Oct-13 8:02 
QuestionWhy calling sort() crashes? Pin
Kumar Anitesh9-Oct-13 23:29
MemberKumar Anitesh9-Oct-13 23:29 
AnswerRe: Why calling sort() crashes? Pin
Richard MacCutchan10-Oct-13 0:32
mveRichard MacCutchan10-Oct-13 0:32 
QuestionNativeWindow? Win32?? Pin
Aidoru7511-Sep-13 0:17
MemberAidoru7511-Sep-13 0:17 
AnswerRe: NativeWindow? Win32?? Pin
Richard MacCutchan17-Sep-13 0:36
mveRichard MacCutchan17-Sep-13 0:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.