Solved

INSTALIZE ARRAY/STRUCTURE AT DECLARATION - EXTREMELY DIFFICULT

Posted on 2004-04-14
25
336 Views
Last Modified: 2006-11-17
hi.

working with these structures:

typedef struct tagINPUT {
  DWORD   type;
  union {
      MOUSEINPUT      mi;
      KEYBDINPUT      ki;
      HARDWAREINPUT   hi;
  };
} INPUT, *PINPUT;


typedef struct tagKEYBDINPUT {
  WORD      wVk;
  WORD      wScan;
  DWORD     dwFlags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT;


i want to get the following result:
type = INPUT_KEYBOARD
ki.wVk = VK_CAPITAL
ki.wScan = 0
ki.dwFlags = KEYEVENTF_EXTENDEDKEY
ki.time = 0
ki.dwExtraInfo = 0

But first union member is MOUSEINPUT mi, so this becomes very hard.

because i am using shared memory in a dll, i must assign the values  upon declaration.


if any1 has any solutions to this problem, then pls let me know

thanks in advance,

suma
0
Comment
Question by:da_mango_bros
  • 7
  • 6
  • 4
  • +2
25 Comments
 
LVL 12

Expert Comment

by:stefan73
ID: 10822487
Hi da_mango_bros,
> But first union member is MOUSEINPUT mi, so this becomes very hard.

do something like:

switch(type){
    case INPUT_MOUSE:
        /* Display mouse data mi.* */
        break;
    case INPUT_KEYBOARD:
        /* Display keyboard data ki.* */
        break;
    case INPUT_HARDWARE:
        /* Display hardware data hi.* */
        break;
    default:
        /* Error */
}

Cheers,
Stefan
0
 
LVL 86

Expert Comment

by:jkr
ID: 10822770
>>because i am using shared memory in a dll, i must assign the values  upon declaration.

You only need to initialize the values with arbitrary data. But, you can simply use

INPUT in = { INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0};
0
 

Author Comment

by:da_mango_bros
ID: 10823111
i originally tried to use:

INPUT input = {INPUT_KEYBOARD, {VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0}};

but because "mi" is first, i thought that {VK_CAPTIAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0} gets assigned to "mi", rather than to "ki" as required.

is there a way around this?

sefan73:
u misunderstood the question. i need to create a new instance of these structures, assign values to the variables, and then pass the new instances of the structures into functions as parameters.

because i am using shared memory in a dll, i cannot use:

int x;
x = 1;

but must use:

int x = 1;

this becomes difficult because of the union in one of the structures


 
0
 
LVL 86

Expert Comment

by:jkr
ID: 10823128
You can use either

INPUT in = { INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0};

or

INPUT in = { INPUT_KEYBOARD, {VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0}};
0
 

Author Comment

by:da_mango_bros
ID: 10823330
i gave that a try and it didnt completly work.

here is my code from the HookProc of a keyboard hook, designed to toggle the capslock key each time a key is pressed:

//instalized in the shared memory section:

INPUT input[2] =
{
      {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0},
      {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0, 0}
};

//in the HookProc:

SendInput(2, input, sizeof(INPUT));


it works the first time i press a key (regardless of the state of capslock), but after that it dosnt work for some reason

it must be something to do with the instalization, cuz when i tried creating new variables each time, it worked.
0
 
LVL 86

Expert Comment

by:jkr
ID: 10823414
>>//in the HookProc:
>>SendInput(2, input, sizeof(INPUT));

So, why would you need a global shared variable for that, you can simply make the array a local variable of your hooc proc...
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10823421
da_mango_bros,
> but because "mi" is first, i thought that {VK_CAPTIAL, 0, KEYEVENTF_EXTENDEDKEY,
> 0, 0} gets assigned to "mi", rather than to "ki" as required.
>
> is there a way around this?

Yes, move the "KEYBDINPUT      ki;" to the top of the union. Unions don't have an order, as every element starts at the same address, anyway.
Stefan
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10823431
da_mango_bros,
The probably cleanest way is to define INPUT_UNDEFINED as a fourth possible value for type, indicating that there is no real data in the union.

Stefan
0
 
LVL 86

Expert Comment

by:jkr
ID: 10823483
>>Yes, move the "KEYBDINPUT      ki;" to the top of the union

Might be a long way down the road. Do you thing mailing that request to Bill Gates directly could help speeding that up? :o)
0
 

Author Comment

by:da_mango_bros
ID: 10823521
jkr:

yea that works... but it is ineffecient to create new variables each time a key is pressed

this code works fine:

                                                                KEYBDINPUT keyDown;
                        keyDown.dwExtraInfo = 0;
                        keyDown.dwFlags = KEYEVENTF_EXTENDEDKEY;
                        keyDown.time = 0;
                        keyDown.wScan = 0;
                        keyDown.wVk = VK_CAPITAL;
                        
                        KEYBDINPUT keyUp;
                        keyUp.dwExtraInfo = 0;
                        keyUp.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
                        keyUp.time = 0;
                        keyUp.wScan = 0;
                        keyUp.wVk = VK_CAPITAL;

                        INPUT input[2];
                        input[0].type = input[1].type = INPUT_KEYBOARD;
                        input[0].ki = keyDown;
                        input[1].ki = keyUp;

                        SendInput(2, input, sizeof(INPUT));

but when i change the code, leaving it in the hook proc (i.e. local), to:

INPUT input[2] =
{
     {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0},
     {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0, 0}
};

it dosnt work. clearly the last implementation is cleaner, replacing about 15 lines of code with 5


stefan73:

>> unions dont have an order

omg i never realized that... but can u explain why the code dosnt work then??

0
 
LVL 86

Expert Comment

by:jkr
ID: 10823554
>>yea that works... but it is ineffecient to create new variables each time a key is pressed

No. Just create it as

static INPUT input[2] =
{
    {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0},
     {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0, 0}
};

Anyway, you can keep that as a global variable, but the bottom line is that it does not have to be in a shared memory section...
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10826312
static INPUT input[2] =
{
   {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0},
   {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0, 0}
};

That is wrong as the parameters 2 - 5  get assigned to struct MOUSEINPUT and not to KEYINPUT, thus values like KEYEVENTF_EXTENDEDKEY will not properly assigned to input[0].ki.dwFlags but to input[0].mi.mouseData which has the same storage as input[0].ki.time. Look at this code:

bool operator==(const KEYBDINPUT& k1, const KEYBDINPUT& k2)
{
    return (k1.dwExtraInfo == k2.dwExtraInfo) &&
           (k1.dwFlags == k2.dwFlags) &&
           (k1.time == k2.time) &&
           (k1.wScan == k2.wScan) &&
           (k1.wVk == k2.wVk);
}


bool operator==(const INPUT& i1, const INPUT& i2)
{
    return (i1.type == i2.type) && (i1.ki == i2.ki);
}

void g()
{

    KEYBDINPUT keyDown;
    keyDown.dwExtraInfo = 0;
    keyDown.dwFlags = KEYEVENTF_EXTENDEDKEY;
    keyDown.time = 0;
    keyDown.wScan = 0;
    keyDown.wVk = VK_CAPITAL;
   
    KEYBDINPUT keyUp;
    keyUp.dwExtraInfo = 0;
    keyUp.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
    keyUp.time = 0;
    keyUp.wScan = 0;
    keyUp.wVk = VK_CAPITAL;

    INPUT input[2];
    input[0].type = input[1].type = INPUT_KEYBOARD;
    input[0].ki = keyDown;
    input[1].ki = keyUp;
    INPUT inputx[2] =
    {
        {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0},
        {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0, 0}
    };

    bool b1 = (input[0] == inputx[0]);    // b1 = false;
    bool b2 = (input[1] == inputx[1]);    // b2 = false;
}

You may 'fix' the problem using this:

static INPUT input[2] =
{
   {INPUT_KEYBOARD, VK_CAPITAL, KEYEVENTF_EXTENDEDKEY, 0, 0, 0, 0},
   {INPUT_KEYBOARD, VK_CAPITAL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0, 0, 0, 0}
};

Now KEYBDINPUT is correct as the first two members of KEYBDINPUT have WORD type and third is a DWORD whereas MOUSEINPUT starts with two LONG members. The two WORD members get mapped to the first LONG, and the DWORD get mapped to second LONG.

However, i would use the assign method because that isn't less tricky.

static INPUT input[2] =
{
   {INPUT_KEYBOARD, 0, 0, 0, 0, 0, 0},
   {INPUT_KEYBOARD, 0, 0, 0, 0, 0, 0}
};

static bool init = true;

if (init)
{
    init = false;
    KEYBDINPUT keyDown;
    keyDown.dwExtraInfo = 0;
    keyDown.dwFlags = KEYEVENTF_EXTENDEDKEY;
    keyDown.time = 0;
    keyDown.wScan = 0;
    keyDown.wVk = VK_CAPITAL;
   
    KEYBDINPUT keyUp;
    keyUp.dwExtraInfo = 0;
    keyUp.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
    keyUp.time = 0;
    keyUp.wScan = 0;
    keyUp.wVk = VK_CAPITAL;

    input[0].ki = keyDown;
    input[1].ki = keyUp;

}

Regards, Alex


0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 

Author Comment

by:da_mango_bros
ID: 10829006
thanks alex... i see what is going on now.

unfortunately i have to have the declaration in the shared memory section if i want it to be global, because im using a GLOBAL windows hook. (i tested this out btw)

now i have 2 options:

1) putting the stuff in the shared memory section requires instalization at declaration, so i must assign the extra members of MOUSEINPUT to 0 (zero). This is nice and effecient, because the variables are only created and instalized once.

2) putting the stuff in the HookProc means i can use the assign method, but this will result in ineffeciency (due to creating and assigning new variables each time), and also expand 5 lines of code into about 15.


my final question is this:

does assigning the extra members of MOUSEINPUT to 0 (zero), decrease performance at all, or is it completly acceptable?

i.e. is this advisable to use with SendInput:

static INPUT input[2] =
{
   {INPUT_KEYBOARD, VK_CAPITAL, KEYEVENTF_EXTENDEDKEY, 0, 0, 0, 0},
   {INPUT_KEYBOARD, VK_CAPITAL, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0, 0, 0, 0}
};

cheers, suma


0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10830301
Suma,

static member assignments wil be done only once. So with

static bool init = true;
if (init)
{
    init = false;
    // do something but only once
}

you are doing nothing that will harm performance. If you need shared memory just copy the well-defined structs from local memory to shared memory using memcpy.

static INPUT input[2] =
{
   {INPUT_KEYBOARD, 0, 0, 0, 0, 0, 0},
   {INPUT_KEYBOARD, 0, 0, 0, 0, 0, 0}
};

static bool init = true;
if (init)
{
    init = false;
    KEYBDINPUT keyDown;
    keyDown.dwExtraInfo = 0;
    keyDown.dwFlags = KEYEVENTF_EXTENDEDKEY;
    keyDown.time = 0;
    keyDown.wScan = 0;
    keyDown.wVk = VK_CAPITAL;
   
    KEYBDINPUT keyUp;
    keyUp.dwExtraInfo = 0;
    keyUp.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
    keyUp.time = 0;
    keyUp.wScan = 0;
    keyUp.wVk = VK_CAPITAL;

    input[0].ki = keyDown;
    input[1].ki = keyUp;

    // Get the shared memory somehow
    char* sharedMemoryPtr = createSharedMemory(...);
    memcpy(sharedMemoryPtr, input, sizeof(input));
}

Hope, that helps

Alex
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10830974
da_mango_bros,
> >> unions dont have an order
>
> omg i never realized that... but can u explain why the code dosnt work then??

Just initialize it using an "undefined" state, as originally there is nothing in there and it's of no use to initialize your usion members with dummy data.

As soon as you get your first real data, you can set the values accordingly.

Stefan
0
 

Author Comment

by:da_mango_bros
ID: 10831141
so how do i instalize it undifined?
0
 
LVL 2

Accepted Solution

by:
sitbon earned 500 total points
ID: 10845711
Wow you people.. I am disappointed. There is a pretty simple solution... and there are other easy solutions, too...

First, use this function, anywhere in your cpp file:

static const INPUT &Initializer()
{
  static INPUT Init;
  static bool did_init = false;

  if ( !did_init )
  {
    did_init = true;
    Init.type = INPUT_KEYBOARD;
    Init.ki.wVk = VK_CAPITAL;
    Init.ki.wScan = 0;
    Init.ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
    Init.ki.time = 0;
    Init.ki.dwExtraInfo = 0;
  }

  return Init;
}

int main()
{
  // now do this
  INPUT I( Initializer() );

  // or this...
  INPUT I2 = Initializer();

  // ... whatever else ...
}

No, the function does not have to be static, you don't have to return a reference to the static variable (you can return an INPUT and have the var inside the function not be static), and you don't have to use did_init....

BUT - for performance and ease of use (understanding what that function does), it's best to leave it just as it is... no complicated crap and no 50 extra lines of code!
0
 
LVL 86

Expert Comment

by:jkr
ID: 10845757
>>Wow you people.. I am disappointed. There is a pretty simple solution...

Good that you came to save us. I thought some others have already been mentioned.
0
 
LVL 2

Expert Comment

by:sitbon
ID: 10846393
OK, here is another one, and the simplest yet:

change the stuct in the header file to

typedef struct tagINPUT {
  DWORD   type;
      KEYBDINPUT      ki;
} INPUT, *PINPUT;

Remove the union! The struct size/data is the same, it will NOT cause problems.
0
 

Author Comment

by:da_mango_bros
ID: 10846849
both of those solutions are exelent... ima use the class one because i prefer that.

sometimes there is an obvious solution but nobody can see it.

good stuff sitbon :)
0
 

Author Comment

by:da_mango_bros
ID: 10847178
just to help out any1 else who is reading this thread because they have the same problem:

using a function to perform the instilization does not work if u want to have a two-dimensional array

i used a class:

class Init
{
public:
      INPUT input[2];
      Init()
      {
            input[0].type = input[1].type = INPUT_KEYBOARD;
            input[0].ki.wVk = input[1].ki.wVk = VK_CAPITAL;
            input[0].ki.wScan = input[1].ki.wScan = VK_CAPITAL;
            input[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
            input[1].ki.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
            input[0].ki.time = input[1].ki.time = 0;
            input[0].ki.dwExtraInfo = input[1].ki.dwExtraInfo = 0;
      }
};

the actual instalization is performed here:

Init init;

then later on, in the HookProc:

SendInput(2, init.input, sizeof(INPUT));


thanks to every1 who participated in the thread, esp. alex (itsmeandnobodyelse) and sitbon
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10848694
>> typedef struct tagINPUT {
>>  DWORD   type;
>>      KEYBDINPUT      ki;
>>} INPUT, *PINPUT;

Redefining the struct tagINPUT to overcome initialisation problems is a brilliant idea ... at the first glance. If you change the original header file that came with your compiler you always have to think on that if you get any update or change the development platform. Even worse it is to make the changes to a copy that got first int include order. There will come a time where your program doesn't work although you didn't change anything and you have no idea (anymore) where it come from.

To save the brilliance of the idea, i would suggest the following:

Define a new type using the struct definition above. Define your variables using the new struct and cast the type when using it as an argument:

typedef struct tagINPUTX {
  DWORD   type;
      KEYBDINPUT      ki;
} INPUTX, *PINPUTX;

INPUTX input[2] =
{
     {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY, 0, 0},
     {INPUT_KEYBOARD, VK_CAPITAL, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0, 0}
};

....

   SendInput(2, (PINPUT)input, sizeof(INPUTX));

Note, that sizeof(..) must use sizeof(INPUTX) as the new struct has a different size.

Regards, Alex


0
 
LVL 2

Expert Comment

by:sitbon
ID: 10850345
itsmeandnobodyelse, you're probably right, but the the point is this: if you change the header, compile your program, and say change it back, the only thing that would break it is re-arranging or changing the size of the INPUT struct... which is unlikely. I do agree that it it kind of a messy solution in a way, mainly in the sense of "what the hell did he do here?" when someone else reads it down the line :)

da mango - glad you liked my ideas :)
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10851065
>> the only thing that would break it is re-arranging or changing the size of the INPUT struct... which is unlikely

No, much more likely he will get a new version of the compiler thus overwriting the changes, recompile the project - not remembering that there is a header that must be changed. If there are some years between there is a good chance to overlook that. And what makes it worse is that it will compile without problems. Changing a standard header isn't a good idea as long as you have a cheap alternative.

>> the only thing that would break it is re-arranging or changing the size of the INPUT

That is actually a minor problem as the size is an argument of SendInput.

Regards, Alex

0
 
LVL 2

Expert Comment

by:sitbon
ID: 10851117
I don't think you really get what I'm saying, but that's ok because the question is answered. It's obvious that changing the header causes those issues.
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now