I've installed a Haste Mod, although - azerothcore

So I'm using AzerothCore, and I recently just installed a Haste Mod, it's working, but not functioning properly, the Haste Mod I had to install manually due to times changing and codes changing, although now.
My issue is that even though I get 0.00 after I reached a certain amount of haste, it is too fast & proccs don't work, example: Shadowmourne weapon effect...
Sometimes I'm hitting up to 80 times pr game tick, and it varies for 50-80, I want to ask you guys, is it possible to make it locked to a certain amount of attack counts? Both Melee and Ranged, due to sound glitching out also, sometimes sound disappears until I stop attacking, This is unlike any haste mod I ever tested, whether it be a live server or a test server...
The Hastemod is the following:
PLAYER.CPP
hasteMod = 2.9;
/* hastemod
if (haveOffhandWeapon())
if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
*/
/* hastemod
if (getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY)
setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY);
*/
// hastemod begins
void Player::SetAttackTime(WeaponAttackType att, uint32 val) {
switch(att) {
case BASE_ATTACK:
ApplyHasteMod(m_baseRatingValue[CR_HASTE_MELEE],BASE_ATTACK,CR_HASTE_MELEE, val);
break;
case OFF_ATTACK:
ApplyHasteMod(m_baseRatingValue[CR_HASTE_MELEE],OFF_ATTACK,CR_HASTE_MELEE, val);
break;
case RANGED_ATTACK:
ApplyHasteMod(m_baseRatingValue[CR_HASTE_RANGED],RANGED_ATTACK,CR_HASTE_RANGED, val);
break;
default:
SetFloatValue(UNIT_FIELD_BASEATTACKTIME+att,val*m_modAttackSpeedPct[att]);
}
}
void Player::ApplyHasteMod(int16 val, uint32 att, CombatRating cr, float speed) {
float atkSpd = speed * (( 100.0f - ((val / 32.789989f) * hasteMod) ) / 100.0f );
if (atkSpd < 0) atkSpd = 0;
SetFloatValue(UNIT_FIELD_BASEATTACKTIME+att, atkSpd);
}
// hastemod ends
void Player::ApplyRatingMod(CombatRating cr, int32 value, bool apply)
{
m_baseRatingValue[cr]+=(apply ? value : -value);
// explicit affected values
switch (cr)
{
case CR_HASTE_MELEE:
{
Item * mainhand = m_items[EQUIPMENT_SLOT_MAINHAND];
Item * offhand = m_items[EQUIPMENT_SLOT_OFFHAND];
float speed1 = mainhand ? (float)mainhand->GetTemplate()->Delay : 2000.0f;
float speed2 = offhand ? (float)offhand->GetTemplate()->Delay : 2000.0f;
ApplyHasteMod(m_baseRatingValue[cr], BASE_ATTACK, cr, speed1);
ApplyHasteMod(m_baseRatingValue[cr], OFF_ATTACK, cr, speed2);
float RatingChange = value / value;
(RatingChange = 0) ? ApplyPercentModFloatVar(m_modAttackSpeedPct[BASE_ATTACK], RatingChange, !apply) : ApplyPercentModFloatVar(m_modAttackSpeedPct[BASE_ATTACK], -RatingChange, apply);
(RatingChange = 0) ? ApplyPercentModFloatVar(m_modAttackSpeedPct[OFF_ATTACK], RatingChange, !apply) : ApplyPercentModFloatVar(m_modAttackSpeedPct[OFF_ATTACK], -RatingChange, apply);
break;
}
case CR_HASTE_RANGED:
{
Item * ranged = m_items[EQUIPMENT_SLOT_RANGED];
float speed = ranged ? (float)ranged->GetTemplate()->Delay : 2000.0f;
ApplyHasteMod(m_baseRatingValue[cr], RANGED_ATTACK, cr, speed);
float RatingChange = value / value;
(RatingChange = 0) ? ApplyPercentModFloatVar(m_modAttackSpeedPct[RANGED_ATTACK], RatingChange, !apply) : ApplyPercentModFloatVar(m_modAttackSpeedPct[RANGED_ATTACK], -RatingChange, apply);
break;
}
case CR_HASTE_SPELL:
{
ApplyHasteMod(m_baseRatingValue[cr], CR_HASTE_SPELL-1, cr, 1.0f);
break;
}
default:
PLAYER.H
float hasteMod;
public:
float GetHasteMod() const { return hasteMod; }
void SetHasteMod(float val) { hasteMod = val; }
void ApplyHasteMod(int16 val, uint32 att, CombatRating cr, float speed);
void SetAttackTime(WeaponAttackType att, uint32 val);
STATSYSTEM.CPP
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& min_damage, float& max_damage)
{
UnitMods unitMod;
Item *Weapon = NULL;
switch (attType)
{
case BASE_ATTACK:
default:
Weapon = m_items[EQUIPMENT_SLOT_MAINHAND];
unitMod = UNIT_MOD_DAMAGE_MAINHAND;
break;
case OFF_ATTACK:
Weapon = m_items[EQUIPMENT_SLOT_OFFHAND];
unitMod = UNIT_MOD_DAMAGE_OFFHAND;
break;
case RANGED_ATTACK:
Weapon = m_items[EQUIPMENT_SLOT_RANGED];
unitMod = UNIT_MOD_DAMAGE_RANGED;
break;
}
float wep_speed =(!Weapon) ? 2200.00f : Weapon->GetTemplate()->Delay;
float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f (wep_speed/1000.00f);
float att_speed = GetAPMultiplier(attType,normalized);
float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
if (lvl > 60)
lvl = 60;
weapon_mindamage = lvl*3.0f*wep_speed/1000;
weapon_maxdamage = lvl*5.0f*wep_speed/1000;
}
else if (!CanUseAttackType(attType)) //check if player not in form but still can't use (disarm case)
{
I would love if you guys have heard or seen anything like this before, and know what to do, I've spent the last 3 days, trying to figure it out... I know it's possible, just don't know how, or if it's even possible with this hastemod.

You should avoid modifying the main core's files (e.g. Player.cpp, Player.h, etc..) but create a real (separate) module for your custom changes:
http://www.azerothcore.org/wiki/Create-a-Module
If you need to implement new hooks, then you should send a PR to the main repo. So your core codebase will always be clean (without custom changes).

Related

How to decrypt data that is encrypted by OpenSSL with RSA_PKCS1_OAEP_PADDING using NCryptDecrypt?

I have difficulty to decrypt data being encrypted using OpenSSL and RSA_PKCS1_OAEP_PADDING padding option.
What I am doing is:
BCRYPT_ALG_HANDLE hCryptAlg = NULL;
BCRYPT_OAEP_PADDING_INFO paddingInfo = { 0 };
DWORD cbDecryptedMessage;
BYTE* pbDecryptedMessage = NULL;
paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
// Open an algorithm handle.
BCryptOpenAlgorithmProvider(&hCryptAlg, BCRYPT_RSA_ALGORITHM, NULL, 0);
// Calculate the required buffer
NCryptDecrypt(m_hKeyContextFull, (LPBYTE)pEncrypted, encryptedLenInBytes, &paddingInfo, NULL, cbDecryptedMessage, &outputDataLen, NCRYPT_PAD_OAEP_FLAG | NCRYPT_SILENT_FLAG);
// After required buffer is allocated...
NCryptDecrypt(m_hKeyContextFull, (LPBYTE)pEncrypted, encryptedLenInBytes, &paddingInfo, pbDecryptedMessage, cbDecryptedMessage, &outputDataLen, NCRYPT_PAD_OAEP_FLAG | NCRYPT_SILENT_FLAG);
It fails with NTE_INVALID_PARAMETER (0x80090027). I tried different flags but none of them works.
Note: m_hKeyContextFull has already been retrieved using CryptAcquireCertificatePrivateKey function call:
m_hSystemStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, m_storeName.c_str());
m_pCertWithKeys = CertFindCertificateInStore(m_hSystemStore, SupportedEncodings, 0, CERT_FIND_SUBJECT_STR, m_certName.c_str(), NULL);
// Obtain the private key from the certificate.
DWORD m_KeyContextSpec = 0;
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE m_hKeyContextFull;
CryptAcquireCertificatePrivateKey(m_pCertWithKeys, CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG, NULL, &m_hKeyContextFull, &m_KeyContextSpec, &m_KeyContextMustBeReleased);
Note: All error checkings have been removed from code for readability.
Is there any idea what am I doing wrong?
Thanks.
I'd start by making paddingInfo valid:
BCRYPT_OAEP_PADDING_INFO paddingInfo;
paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
paddingInfo.pbLabel = NULL;
paddingInfo.cbLabel = 0;
The current standard has the empty string label (see RFC 3447).
Moreover, as to pbDecryptedMessage:
If this parameter is NULL, this function will calculate the size needed for the decrypted data and return the size in the location pointed to by the pcbResult parameter.
So it won't decrypt anyway. You need to allocate the buffer first to the right size; a lot of Windows API's work that way: first call it with output buffer NULL and you get back the needed size somehow, in this case in outputDataLen (which you should declare!). Then allocate the outbufbuffer to that size, and call the function again with the fresh buffer, and the correct length in cbDecryptedMessage. After use, free the buffer again of course. But your comment claims to have done so?
Another suspicious fact: You use NCryptDecrypt so the first argument, should
be a hKey of the right type, while m_hKeyContextFull does not seem to have that type. CryptAcquireCertificatePrivateKey will get you an old style key handle.
You cannot mix these different Windows CryptoAPI's.
Maybe look at the NcryptImportKey function, to transfer it.
I'm not familiar with the NCrypt series of interfaces, but we implemented something similar recently in a library using the BCrypt series of interfaces. Here is the function in question, which can be seen in greater context here.
In our case prvblbtyp is LEGACY_RSAPRIVATE_BLOB and prvblbbuf and prvblbblen are described here.
static
int
asymmetric_decrypt(
const wchar_t * const prvblbtyp,
const void * const prvblbbuf, const size_t prvblblen,
const void * const ctbuf, const size_t ctlen,
void ** const ptbuf, size_t * const ptlen)
{
BCRYPT_ALG_HANDLE halg;
int res;
res = INT_MIN;
if (BCryptOpenAlgorithmProvider(
&halg, BCRYPT_RSA_ALGORITHM, NULL, 0) == STATUS_SUCCESS) {
BCRYPT_KEY_HANDLE hkey;
if (BCryptImportKeyPair(
halg,
NULL, prvblbtyp, &hkey,
(void *)prvblbbuf, prvblblen,
0) == STATUS_SUCCESS) {
BCRYPT_OAEP_PADDING_INFO inf;
ULONG len;
inf.pszAlgId = BCRYPT_SHA1_ALGORITHM;
inf.pbLabel = NULL;
inf.cbLabel = 0;
/*
* decrypt first with a NULL output buffer.
* this returns the size necessary for the buffer.
*/
if (BCryptDecrypt(
hkey,
(void *)ctbuf, ctlen,
&inf,
NULL, 0,
NULL, 0, &len,
BCRYPT_PAD_OAEP) == STATUS_SUCCESS) {
void * buf;
/*
* allocate the required buffer
* and decrypt again
*/
res = -ENOMEM;
buf = malloc(len);
if (buf) {
res = INT_MIN;
if (BCryptDecrypt(
hkey,
(void *)ctbuf, ctlen,
&inf,
NULL, 0,
buf, len, &len,
BCRYPT_PAD_OAEP) == STATUS_SUCCESS) {
*ptbuf = buf;
*ptlen = len;
res = 0;
} else {
free(buf);
}
}
}
BCryptDestroyKey(hkey);
}
BCryptCloseAlgorithmProvider(halg, 0);
}
return res;
}

Return a result of type error in a Method

Im working on the collision detection in my 2D Processing 2.2.1 game. Basically what I did was write a class which creates a box by defining the coordinates of its endpoints and which has a method to check if two of these boxes overlap. I did this by introducing a boolean which is set to true as soon two of these boxes overlap. Then basically implementing a get method which creates these boxes, I run into a return a result of type error. It says that the method is not returning the correct type of Box1. I dont really understand since the box which I am returning does fit the constructor. I am pretty sure it is due to the fact that the objects colliding are in an array which generates more and more objects with time, but I sadly do not know how I would have to change my Collider ( Box1) class.
here is the code im getting the error on:
//returning collider info
public Box1 getBox1() {
for (int i =frameCount/600; i >0; i--) {
return new Box1( block[i].x - Blockpic.width/2, block[i].y-Blockpic.height/2, block[i].x+Blockpic.height/2, block[i].y+Blockpic.height/2);
}
}
this is my collider (Box1) class:
public class Box1 {
float x1, x2;
float y1, y2;
Box1( float x1, float y1, float x2, float y2 ) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
boolean isOverlap( Box1 b ) {
if ((( x1 <= b.x1 && b.x1 <= x2 ) || ( x1 <= b.x2 && b.x2 <= x2 ))
&& (( y1 <= b.y1 && b.y1 <= y2 ) || ( y1 <= b.y2 && b.y2 <= y2 ))) {
return true;
}
return false;
}
}
just for complete info my spawning objects class ( where the error is situated) :
public class Blockfield {
private int Blockcount;
private PImage Blockpic;
private Block block[];
//Constructor
public Blockfield (int Blockcount) {
this.Blockcount = Blockcount;
Blockpic = loadImage("block2.png");
//new array
block = new Block [Blockcount];
for ( int i=0; i < Blockcount; i++) {
block[i] = new Block( width+Blockpic.width, random (height),7);
}
}
//Draw method for this class
public void draw () {
for (int i =frameCount/600; i >0; i--) {
pushMatrix();
translate ( block[i].x,block[i].y );
image ( Blockpic, block[i].x, block[i].y);
popMatrix();
}
}
public void update() {
for (int i =frameCount/600; i >0; i--) {
//moves blocks right to left
block[i].x -=(6 * (frameCount/200));
//spawns block when they leave the screen
if (block[i].x < 0 - Blockpic.width) {
block[i] = new Block( width+Blockpic.width, random (height),7);
}
}
}
//returning collider info
public Box1 getBox1() {
for (int i =frameCount/600; i >0; i--) {
return new Box1( block[i].x - Blockpic.width/2, block[i].y-Blockpic.height/2, block[i].x+Blockpic.height/2, block[i].y+Blockpic.height/2);
}
}
}
class Block {
float x, y;
int speed;
Block ( float x, float y, int speed) {
this.x= x;
this.y= y;
this.speed = speed;
}
}
Thanks alot!!!
The problem, as you say, is with this method:
public Box1 getBox1() {
for (int i =frameCount/600; i >0; i--) {
return new Box1( block[i].x - Blockpic.width/2, block[i].y-Blockpic.height/2, block[i].x+Blockpic.height/2, block[i].y+Blockpic.height/2);
}
}
Ignoring for a second that it doesn't make sense to have a return statement inside a for loop like this, the whole problem is that computers are too stupid to know what the value of frameCount is before they run the code. What if frameCount is 0? Or negative?
If frameCount is 0 or negative, then the body of the for loop will never be executed, and this method will never return anything. That's the error.
You might know that frameCount will always be positive, but the computer doesn't.
Edit: Continuing in response to your below comment:
If you want help, you have to provide an MCVE. Note that this should be as few lines as possible, just to get the basics across. We don't need any collision detection, just a function you call. Here's an example:
void setup(){
String s = getString(true);
println(s);
}
String getString(boolean b){
if(b){
return "testing";
}
}
If you try to run this code, you'll get an error telling you that "This method must return a result of type String".
The reason you get this error is because: what will the getString() function return if I pass in a value of false? It won't return anything! This is exactly like what your code is complaining about. We can see that getString() is only ever called with a value of true, but the computer isn't smart enough to figure that out.
You seem to misunderstand the power that a compiler has. It can't see what will happen at runtime. Even if it's obvious to you that the boolean will always be true (or in your case, that frameCount is always positive), the compiler can't know that. And since it can't know that, it's telling you that you might not return a value from a method with a return type, and that's a compiler error.
You need to refactor your code so that it always returns something from methods that have a return type. However, I'm skeptical that the for loop does what you think it does- but you haven't really explained what you think it does, so that's just a guess.
And the reason you didn't encounter this error in your other methods is because none of them contain this logical error. The only other function that has a return type is this one:
boolean isOverlap( Box1 b ) {
if (lotsOfLogic) {
return true;
}
return false;
}
Notice how even if the if statement evaluates to false, you still return something from this function. That's what you need to do with your getBox1() function.

STL Vector Exception on Erase in unmanaged code

This is a static function which is an unmanaged function which I am trying to call from a managed CLR project. But everytime I add the erase an exception happens. Both classes are inside the same project
I keep getting an exception on the erase,
#pragma managed(push, off)
void MessageContainer::ParseByteStream(UINT8 *buf, int length)
{
s_RxBufVector.insert(s_RxBufVector.end(), buf, buf + length);
if (s_RxBufVector.size() >= sizeof(Msg_Struct) * 2)
{
int BytesConsumed = 0;
s_RxBufIterator = s_RxBufVector.begin();
while (BytesConsumed < (int)s_RxBufVector.size() - sizeof(Msg_Struct))
{
if (ntohl(*((UINT32 *)&s_RxBufVector[BytesConsumed + __PREAMBLE_OFFSET])) == PreambleVal)
{
switch (ntohl(*((UINT32 *)&s_RxBufVector[BytesConsumed + __COMMAND_ID_OFFSET])))
{
case eCommandIdRxMsg:
if (MsgRx != nullptr)
(*MsgRx)(ntohl(*((UINT32*)&s_RxBufVector[BytesConsumed + __ID_OFFSET])), ntohs(*((UINT16*)(&s_RxBufVector[BytesConsumed + __CHANNEL_OFFSET]))),
ntohs(*((UINT16*)&s_RxBufVector[BytesConsumed + __LENGTH_OFFSET])), &s_RxBufVector[BytesConsumed + __BUFFER_OFFSET]);
break;
case eCommandIdCmdAck:
if (CmdAck != nullptr)
//(*CmdAck())
break;
case eCommandIdSendAck:
if (TxConf != nullptr)
//(*TxConf())
break;
default:
break;
}
BytesConsumed += sizeof(Msg_Struct);
}
else
{
BytesConsumed++;
}
}
s_RxBufVector.erase(s_RxBufIterator, s_RxBufIterator + BytesConsumed);
}
}
private:
static std::vector<UINT8, std::allocator<UINT8>> s_RxBufVector;
static std::vector<UINT8>::iterator s_RxBufIterator;
Init()
{
s_RxBufVector.reserve(4096);
}
Is there something wrong with the Vector accessing.
An unhandled exception of type 'System.AccessViolationException' occurred
Break stops here
_Adopt(_Right._Myproxy->_Mycont);
Worse is that I was trying to delete 24 Bytes at the beginning when the size is already 48
EDIT:
Ok, I found commenting out the code for the callback to the managed code solves the Exception but does not help me either
(*MsgRx)(ntohl(*((UINT32*)&s_RxBufVector[BytesConsumed + __ID_OFFSET])), ntohs(* (UINT16*)(&s_RxBufVector[BytesConsumed + __CHANNEL_OFFSET]))), ntohs(*((UINT16*)&s_RxBufVector[BytesConsumed + __LENGTH_OFFSET])), &s_RxBufVector[BytesConsumed + __BUFFER_OFFSET]);
The Callback is declared here
delegate void MessageReceivedCallbackDelegate(UInt32 Id, UInt16 Channel, UInt16 len, Byte *data);
MessageContainer::SetMessageRxCB((void*)Marshal::GetFunctionPointerForDelegate(gcnew MessageReceivedCallbackDelegate(MessageReceived)));
unmanaged
void MessageContainer::SetMessageRxCB(void *fn)
{
MsgRx = (RxCbFn)fn;
}
Seems like the managed code is causing some problems to the vector. Probably something wrong with how I try to call the managed code, I need some hints :)
SOLVED:
Ok, I forgot to decorate the delegates
[UnmanagedFunctionPointerAttribute(CallingConvention::Cdecl)]
delegate void MessageReceivedCallbackDelegate(UInt32 Id, UInt16 Channel, UInt16 Dlc, Byte *data)

How to determine via UIAutomation, whether a button is pressed or not?

I want to find out whether a button is pressed or not. This seems not to be an official property of a button (not a button-style checkbox!), but seems accessible, there is the BM_GETSTATE message for example that should get the desired result.
Problem is, frequently, I dont get window-handles for my buttons (they are just part of another Toolbar, though they can be distinguihed by the AutomationElement). And I would need such a handle for the SendMessage function.
So.. is there a way for me to access that property? I know it is accessible, since I have seen it in other automation-programmes, I just dont konw how to get at it.
I am going to use C#, but any C code would be fine.
Many thanks
(edit: so I finally managed to make the code format properly here - just insert 4 spaces at the beginning.)
Enjoy it, it took me quite a long time to get it to work.. but now I feel like having reached a new level. :)
(please tell me how to make it format properly - both quote and code failed on me)
int res;
#region direct method
int hwnd = ae.Current.NativeWindowHandle;
if (hwnd != 0)
{
const UInt32 BM_GETSTATE = 0x00F2;
res = SendMessage(hwnd, BM_GETSTATE, 0, 0);
}
#endregion
else
#region method via toolbar
{
AutomationElement parent = TreeWalker.RawViewWalker.GetParent(ae);
while ((parent != null) && (parent.Current.ControlType != ControlType.ToolBar))
parent = TreeWalker.RawViewWalker.GetParent(ae);
if (parent != null)
{
int toolBarHandle = parent.Current.NativeWindowHandle;
#region defines
const int WM_USER = 0x400;
const int TB_GETSTATE = (WM_USER + 18);
const int TB_GETBUTTON = (WM_USER + 23);
const int TB_BUTTONCOUNT = (WM_USER + 24);
#endregion
#region get correct child number
int numButtons = SendMessage(toolBarHandle, TB_BUTTONCOUNT, 0, 0);
AutomationElement sibling = ae;
int cnt = -1;
while (sibling != null)
{
sibling = TreeWalker.RawViewWalker.GetPreviousSibling(sibling);
++cnt;
}
if (cnt >= numButtons)
cnt = 0; // nonsense value, but pass a valid one
#endregion
#region get command id
TBBUTTON butInfo = new TBBUTTON();
butInfo.idCommand = 1234;
uint pid;
GetWindowThreadProcessId((IntPtr)toolBarHandle, out pid);
IntPtr process = OpenProcess(ProcessAccessFlags.VMOperation | ProcessAccessFlags.VMRead |
ProcessAccessFlags.VMWrite | ProcessAccessFlags.QueryInformation, false, pid);
IntPtr p = VirtualAllocEx(process, IntPtr.Zero, (uint)Marshal.SizeOf(typeof(TBBUTTON)), AllocationType.Commit
, MemoryProtection.ReadWrite);
int _res = SendMessage(toolBarHandle, TB_GETBUTTON, cnt, p.ToInt32());
#region getresult
int read;
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TBBUTTON)));
Marshal.StructureToPtr(butInfo, ptr, true);
bool __res = ReadProcessMemory(process, p, ptr, Marshal.SizeOf(typeof(TBBUTTON)), out read);
System.Diagnostics.Debug.Assert(read == Marshal.SizeOf(typeof(TBBUTTON)));
butInfo = (TBBUTTON)Marshal.PtrToStructure(ptr, typeof(TBBUTTON));
#endregion
int commandId = butInfo.idCommand;
VirtualFreeEx(process, p, 0, FreeType.Release);
#endregion
//!define BST_UNCHECKED 0
//!define BST_CHECKED 1
//!define BST_INDETERMINATE 2
//!define BST_PUSHED 4
//!define BST_FOCUS 8
#region get state
res = SendMessage(toolBarHandle, TB_GETSTATE, commandId, 0);
#endregion
}
}
#endregion
EDIT:
Here http://www.andreas-reiff.de/2011/06/c-speicher-anderen-prozess-befullen-lassen-checken-ob-ein-button-gedruckt/ with readable code and explanations in a strange, foreign language.. code comments are english, though. hope you find it useful.
Also, I would not have been able to solve this without the info here How come some controls don't have a windows handle?.

Can someone explain this bit manipulation code?

I have a tree control with checkboxes next to each node that allows for checked, unchecked and middle checked states on the nodes. When clicking a node, the parent and children are updated. The code I found that does the trick uses bit shifting and I'm trying to understand what exactly is happening.
Can someone explain the following code? Or even better, rewrite this code so it is easier to understand?
// click event handler
private function eventMessageTree_itemCheckHandler(event:TreeEvent):void {
var node:ITreeNode = ITreeNode(event.item);
var checkState:uint = TreecheckboxItemRenderer(event.itemRenderer).checkBox.checkState;
updateParents(node, checkState);
updateChilds(node, checkState);
}
private function updateChilds(item:ITreeNode, value:uint):void {
var middle:Boolean = (value & 2 << 1) == (2 << 1);
var selected:Boolean = (value & 1 << 1) == (1 << 1);
if (item.children.length > 0 && !middle) {
for each (var childNode:ITreeNode in item.children) {
childNode.checked = value == (1 << 1 | 2 << 1) ? "2" : value == (1 << 1) ? "1" : "0";
updateChilds(childNode, value);
}
}
}
private function updateParents(item:ITreeNode, value:uint): void {
var checkValue:String = (value == (1 << 1 | 2 << 1) ? "2" : value == (1 << 1) ? "1" : "0");
var parentNode:ITreeNode = item.parent;
if (parentNode) {
for each (var childNode:ITreeNode in parentNode.children) {
if (childNode.checked != checkValue) {
checkValue = "2";
}
}
parentNode.checked = checkValue;
updateParents(parentNode, value);
}
}
It looks like the checkState value in the control can be either 1, 2, or 4 (or possibly 0, 2, and 4?):
public static const CONTROL_UNCHECKED:uint = 1; // not checked, and some descendants are
public static const CONTROL_CHECKED:uint = 2; // checked, and all descendants are
public static const CONTROL_MIDDLE:uint = 4; // not checked, but some descendants are
while the checked value in the nodes can be either 0, 1, or 2:
public static const UNCHECKED:uint = 0; // not checked, and some descendants are
public static const CHECKED:uint = 1; // checked, and all descendants are
public static const MIDDLE:uint = 2; // not checked, but some descendants are
That's really confusing. Ideally these would be the same set of constants.
To update:
private function controlStateToNodeState(value:uint):uint {
return value / 2;
}
...
updateParents(node, controlStateToNodeState(checkState));
updateChilds(node, controlStateToNodeState(checkState));
...
/** Updates the descendants of the node based on state:
* If value is CHECKED, all children are CHECKED
* If value is UNCHECKED, all children are UNCHECKED
* If value is MIDDLE, children are left alone
*/
private function updateChilds(item:ITreeNode, value:uint):void {
if (value == MIDDLE) {
return; // if value is MIDDLE, children are left alone
}
// not middle, so update all children to my state
for each (var childNode:ITreeNode in item.children) {
childNode.checked = value;
updateChilds(childNode, value);
}
}
}
/**
* Updates the ancestor nodes based on state:
* If value is CHECKED, ancestors are made MIDDLE if not already checked
* If value is MIDDLE, ancestors are made middle (they should not already be CHECKED)
*/
private function updateParents(item:ITreeNode, value:uint): void {
...
}
Basically, an expression like this:
var middle:Boolean = (value & 2 << 1) == (2 << 1);
Is counter-intuitive. You usually test bits by shifting the constant 1 to the left, since that lets the number of bits shifted be the same as the index of the bit, counting the LSB (rightmost) bit as bit number 0.
Also, there's no point in testing the result with a == comparison, since it's always going to be either 0 or non-zero, so you can at least test for something simpler if your language requires that.
In C and C++, which by default interpret a non-zero integer as "true", the comparison is totally unnecessary and just serves to introduce clutter, repetition, and increase the risk of bugs.
I'd write this like so:
var middle:Boolean = (value & (1 << 2)) != 0;
The extra parenthesis should help make it clearer how things are grouped. Note how "2 << 1" was rewritten as "1 << 2". This is not just a "switch", you need to compute the proper shift to get the same bit value, 4 in this case.
Of course you could put the bit-testing into subroutines and call them, to make the code more readable.

Resources