Shoutbox

my first script any help would be appriciated.. - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: my first script any help would be appriciated.. (/showthread.php?tid=93829)

my first script any help would be appriciated.. by Yustme on 02-13-2010 at 03:25 PM

Hi,

Im trying to create a script which logs me in automatically in several accounts. I know there is one out there, but its bugged. Tried fixing it, but it's too messed up to understand it.

The error i get is that the script is defective and that it can't be started.

Here is my code:

JScript code:
 
if(Messenger.Version >= 8.5)
{
    var WLMkey = 'SOFTWARE\\Microsoft\\MSNMessenger';
    var WLMexe = 'SOFTWARE\\Microsoft\\Windows Live\\Messenger';
}
 
else
{
    var WLMkey = 'SOFTWARE\\Microsoft\\MSNMessenger';
    var WLMexe = WLMkey;
}
var MPLkey = 'SOFTWARE\\Patchou\\Messenger Plus! Live';
//var MPLscriptkey = (MsgPlus.ScriptRegPath).replace(/HKCU\\/i, '');
 
var delayOpenWnd = 2000;
 
function OnEvent_Initialize(MessengerStart)
{
    if ( Messenger.MyStatus < STATUS_INVISIBLE ) return;
    MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
 
}
 
function OnEvent_Uninitialize(MessengerExit)
{
    MsgPlus.CancelTimer('windowDelayer');
}
 
function SetDefaultAccount()
{
    var emailList = new Array();
    emailList.push('mailaddress@hotmail.com');
    emailList.push('mailaddress@hotmail.com');
    emailList.push('mailaddress@hotmail.com');
 
   
    for(int i = 0; i < emailList.length; i++)
    {
        var email = emailList[i];
        SetBinaryValue(HKEY_CURRENT_USER, WLMkey + '\\PerPassportSettings', 'DefaultMemberName', email);
        SetStringValue(HKEY_CURRENT_USER, MPLkey, 'DefaultUser', email);
        ExecuteWLM();
    }
    //Debug.Trace('Set default account: ' + email);
}
 
function ExecuteWLM()
{
    new ActiveXObject("Shell.Application").ShellExecute("C:/Program Files (x86)/Windows Live/Messenger/" + "msnmsgr.exe", "", "", "open", 1);
}
 
function OnEvent_Timer(timerId)
{
    switch(timerId)
    {
        case 'windowDelayer':
            SetDefaultAccount();
        break;
        default:
       
    }
}



Can't seem to get the code highlighted..
RE: my first script any help would be appriciated.. by roflmao456 on 02-13-2010 at 04:43 PM

quote:
Originally posted by Yustme
JScript code:
for(int i = 0; i < emailList.length; i++)



instead of "int i", use "var i" and it will work.

quote:
Can't seem to get the code highlighted..
[code=JScript]blah[/code]
RE: RE: my first script any help would be appriciated.. by Yustme on 02-13-2010 at 04:58 PM

quote:
Originally posted by roflmao456
quote:
Originally posted by Yustme
JScript code:
for(int i = 0; i < emailList.length; i++)



instead of "int i", use "var i" and it will work.

quote:
Can't seem to get the code highlighted..
[code=JScript]blah[/code]


Hi,

Thank you twice!

I got another small question. I put a delay for the windows, but somehow that doesn't work. The msn windows open too soon after each other. How can I delay this in a proper way?


Edit:
It seems to skip all the email addresses to log in and logs only the last email address. Something wrong with my timer?
RE: my first script any help would be appriciated.. by Matti on 02-13-2010 at 07:02 PM

quote:
Originally posted by Yustme
It seems to skip all the email addresses to log in and logs only the last email address. Something wrong with my timer?
Well yes, you should be putting a delay inside your loop instead of before calling the function with the loop.
  • Make global variables from the e-mail address array and the current loop position.
  • Write a function to use as timer callback:
    1. Read the current item using the global variables.
    2. Set the registry keys and launch Messenger.
    3. Check for remaining items in the list. If there are none, exit.
    4. Increment the position and create a new delay timer for the next iteration.
I could give you the code to do that myself, but I believe it'd be a good exercise to try this yourself first. If you find yourself having trouble with getting the code right, reply here and we'll see how we can help you. :)
RE: RE: my first script any help would be appriciated.. by Yustme on 02-13-2010 at 07:18 PM

quote:
Originally posted by Matti
quote:
Originally posted by Yustme
It seems to skip all the email addresses to log in and logs only the last email address. Something wrong with my timer?
Well yes, you should be putting a delay inside your loop instead of before calling the function with the loop.
  • Make global variables from the e-mail address array and the current loop position.
  • Write a function to use as timer callback:
    1. Read the current item using the global variables.
    2. Set the registry keys and launch Messenger.
    3. Check for remaining items in the list. If there are none, exit.
    4. Increment the position and create a new delay timer for the next iteration.
I could give you the code to do that myself, but I believe it'd be a good exercise to try this yourself first. If you find yourself having trouble with getting the code right, reply here and we'll see how we can help you. :)



Hi Matti,

Thank you! I'll be back in a few hours to tell my progress.
RE: my first script any help would be appriciated.. by Yustme on 02-14-2010 at 12:02 AM

Hi Matti,

I got it almost completely working with your guidance. I still got a minor problem.

Here is my code:

JScript code:
var emailList = new Array();
var counter = 0;
var delayOpenWnd = 2000;
 
 
var MPLkey = 'SOFTWARE\\Patchou\\Messenger Plus! Live';
var WLMkey;
var WLMexe;
 
if(Messenger.Version >= 8.5)
{
    WLMkey = 'SOFTWARE\\Microsoft\\MSNMessenger';
    WLMexe = 'SOFTWARE\\Microsoft\\Windows Live\\Messenger';
}
 
else
{
    WLMkey = 'SOFTWARE\\Microsoft\\MSNMessenger';
    WLMexe = WLMkey;
}
 
 
function OnEvent_Initialize(MessengerStart)
{
    if ( Messenger.MyStatus < STATUS_INVISIBLE ) return;
   
    emailList.push('test1@hotmail.com');
    emailList.push('test2@hotmail.com');
    emailList.push('test3@hotmail.com');
    emailList.push('test4@hotmail.com');
   
    MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
}
 
function OnEvent_Uninitialize(MessengerExit)
{
    MsgPlus.CancelTimer('windowDelayer');
}
 
 
function ExecuteWLM()
{
    new ActiveXObject("Shell.Application").ShellExecute("C:/Program Files (x86)/Windows Live/Messenger/" + "msnmsgr.exe", "", "", "open", 1);
}
 
function OnEvent_Timer(timerId)
{
    switch(timerId)
    {
        case 'windowDelayer':
            var email = emailList[counter];
            counter++;
            SetBinaryValue(HKEY_CURRENT_USER, WLMkey + '\\PerPassportSettings', 'DefaultMemberName', email);
            SetStringValue(HKEY_CURRENT_USER, MPLkey, 'DefaultUser', email);
            ExecuteWLM();
            Debug.Trace("Set default account = " + email);
            MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
        break;
        default:
    }
}
 
 
function OnEvent_SigninReady(emailaddr)
{
    var emailstat = Messenger.MyEmail;
    if(Messenger.MyStatus != STATUS_UNKNOWN)
    {
        Debug.Trace("User signed in, email = " = emailaddr + '\n');
        Debug.Trace("emailstat = " + emailstat + '\n');
    }
}



I got another quick question. Is there anything in this code that I don't need? for example the OnEvent_SigninReady?

Not sure what it should do.


Also, the function SetBinaryValue takes 4 arguments, but i'm only passing it 3.

JScript code:
function SetBinaryValue(lKeyLocation, sKey, sKeyName, sKeyValue)
{
Debug.Trace("sKeyValue = " + sKeyValue);
    var hKey = Interop.Allocate(4);
    var lBufferSize = Interop.Allocate(4);
        lBufferSize.WriteDWORD(0, 2 * sKeyValue.length + 2);
    var lRetVal = Interop.Call('advapi32.dll', 'RegOpenKeyExW', lKeyLocation, sKey, 0, KEY_WRITE, hKey);
        if(lRetVal == ERROR_SUCCESS)
        {
            lRetVal = Interop.Call('advapi32.dll', 'RegSetValueExW', hKey.ReadDWORD(0), sKeyName, 0, REG_BINARY, sKeyValue, lBufferSize.ReadDWORD(0));
            if(lRetVal == ERROR_SUCCESS)
            {
                CloseKey(hKey);
                return true;
            }
            else
            {
            return false;
            }
        }
        else
        {
        return false;
        }
}


Any idea what sKeyValue should be?

It gives me an error in the debug window. It says:

Error: 'length' is null or not an object (code: -2146823281)
       File: _Registry.js. Line: 145.



This would be the affected line:

lBufferSize.WriteDWORD(0, 2 * sKeyValue.length + 2);


In function:

SetBinaryValue()
RE: my first script any help would be appriciated.. by Matti on 02-14-2010 at 11:04 AM

The reason why you're getting that error is because you're not checking how much e-mail addresses there are left in the array. You're simply incrementing the counter without checking whether it exceeds the length of the array.

By doing that, you end up with the email variable becoming undefined after a while. This won't throw an error immediately, so the script will continue and pass it as parameter to SetBinaryValue. However as soon as you try to access the length property of sKeyValue, an error will be thrown since there is no length property in undefined.

Looking at your code, it seems that you should have been able to find this out. You're tracing the value of sKeyValue at the start of SetBinaryValue so normally you should have found "sKeyValue = undefined" in your debugger.

Javascript code:
var emailList = [ 'test1@hotmail.com', 'test2@hotmail.com', 'test3@hotmail.com', 'test4@hotmail.com' ];
// ...
 
function OnEvent_Initialize(MessengerStart)
{
    // Check if there's anything to be done
    if(emailList.length > 0) {
        MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
    }
}
 
// ...
 
function OnEvent_Timer(timerId)
{
    switch(timerId)
    {
        case 'windowDelayer':
            var email = emailList[counter];
            SetBinaryValue(HKEY_CURRENT_USER, WLMkey + '\\PerPassportSettings', 'DefaultMemberName', email);
            SetStringValue(HKEY_CURRENT_USER, MPLkey, 'DefaultUser', email);
            ExecuteWLM();
            Debug.Trace("Set default account = " + email);
 
            // Check if we should continue
            if(counter < emailList.length) {
                counter++;
                MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
            }
        break;
    }
}

As you can see, despite of the debugger throwing an error inside SetBinaryValue, there was nothing wrong with that function. This is a good lesson for a developer - never rely solely on the error information! ;)

On another note, there seems to be a few more oddities in your script:
  • When the OnEvent_Initialize function is called on Messenger start-up, Messenger.MyStatus will still be 0 and thus your function will return immediately. This means that the emailList array will never be populated, causing your whole script to fail. I changed this in the code snippet above by populating the array as soon as its declared and by removing the status check at initialisation.
  • What happens when the other Messenger instances are opened? Is the script going to be executed for all those instances as well? Would that mean that all those script instances will keep opening new Messenger instances? Or am I wrong about this?

RE: RE: my first script any help would be appriciated.. by Yustme on 02-14-2010 at 11:29 AM

quote:
Originally posted by Matti
The reason why you're getting that error is because you're not checking how much e-mail addresses there are left in the array. You're simply incrementing the counter without checking whether it exceeds the length of the array.

By doing that, you end up with the email variable becoming undefined after a while. This won't throw an error immediately, so the script will continue and pass it as parameter to SetBinaryValue. However as soon as you try to access the length property of sKeyValue, an error will be thrown since there is no length property in undefined.

Looking at your code, it seems that you should have been able to find this out. You're tracing the value of sKeyValue at the start of SetBinaryValue so normally you should have found "sKeyValue = undefined" in your debugger.

Javascript code:
var emailList = [ 'test1@hotmail.com', 'test2@hotmail.com', 'test3@hotmail.com', 'test4@hotmail.com' ];
// ...
 
function OnEvent_Initialize(MessengerStart)
{
    // Check if there's anything to be done
    if(emailList.length > 0) {
        MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
    }
}
 
// ...
 
function OnEvent_Timer(timerId)
{
    switch(timerId)
    {
        case 'windowDelayer':
            var email = emailList[counter];
            SetBinaryValue(HKEY_CURRENT_USER, WLMkey + '\\PerPassportSettings', 'DefaultMemberName', email);
            SetStringValue(HKEY_CURRENT_USER, MPLkey, 'DefaultUser', email);
            ExecuteWLM();
            Debug.Trace("Set default account = " + email);
 
            // Check if we should continue
            if(counter < emailList.length) {
                counter++;
                MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
            }
        break;
    }
}

As you can see, despite of the debugger throwing an error inside SetBinaryValue, there was nothing wrong with that function. This is a good lesson for a developer - never rely solely on the error information! ;)

On another note, there seems to be a few more oddities in your script:
  • When the OnEvent_Initialize function is called on Messenger start-up, Messenger.MyStatus will still be 0 and thus your function will return immediately. This means that the emailList array will never be populated, causing your whole script to fail. I changed this in the code snippet above by populating the array as soon as its declared and by removing the status check at initialisation.
  • What happens when the other Messenger instances are opened? Is the script going to be executed for all those instances as well? Would that mean that all those script instances will keep opening new Messenger instances? Or am I wrong about this?



Hi Matti,

I forgot about that check with length! :$

I did found that the "sKeyValue = undefined" in the debugger. But I thought that was because I didn't pass 4 argument to that function. I only passed 3 to it.

Well the script executes all the messenger windows and signs in all the email addresses. Then it stops. It doesn't repeat this step for all instances of messenger.

Good point though, because my 3th try making such a script opened like 8 instances of messenger over and over.

I got another quick question. Is there any way to check which email addresses have been logged in?
RE: my first script any help would be appriciated.. by petsas on 07-02-2010 at 01:49 PM

Did anyone find the answer to the last question?

Is there any way to check which email addresses have been logged in?

That's because we have to know which accounts are logged in, so as the procedure to stop
when all accounts are successfully created.

If there is no way to do that, then each of the accounts that will be created will run this script,
as a result this script will produce always new accounts..

any ideas??


RE: my first script any help would be appriciated.. by whiz on 07-02-2010 at 02:07 PM

You could get the script to check for a registry key, and if it doesn't exist, it should create one because it is the first launch.

Javascript code:
// add to the top
var shell = new ActiveXObject("WScript.Shell");
 
// ...
 
function OnEvent_Initialize(MessengerStart)
{
    try {
        // value exists, already running, exit now
        shell.RegRead(MsgPlus.ScriptRegPath + "\\IsRunning");
        return false;
    } catch (error) {
        // not yet running, make a registry value, continue
        shell.RegWrite(MsgPlus.ScriptRegPath + "\\IsRunning", "1");
    }
 
    // Check if there's anything to be done
    if(emailList.length > 0) {
        MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
    } else {
        // finished, delete the registry key
        shell.RegDelete(MsgPlus.ScriptRegPath + "\\IsRunning");
    }
}
 
// ...


RE: my first script any help would be appriciated.. by CookieRevised on 07-03-2010 at 11:11 AM

quote:
Originally posted by Yustme
Im trying to create a script which logs me in automatically in several accounts. I know there is one out there, but its bugged. Tried fixing it, but it's too messed up to understand it.

One of the reasons is because such scripts are complicated. There are many circumstances you need to take into account and it all requires deep knowledge of how the scripting engine works in order to make such a thing always working in all circumstances.

As you have already noticed, there are many things which will break this script or which will make it not work like you'd expect. And there are probably also things which you haven't noticed yet which might break it.

quote:
Originally posted by Yustme
Well the script executes all the messenger windows and signs in all the email addresses. Then it stops. It doesn't repeat this step for all instances of messenger.
That would actually be a bug in your script (the script you have, thus without the addition of Whiz) and a manifestation of how scripts are loaded in Messenger/Messenger Plus! and the delays, etc...

quote:
Originally posted by whiz
You could get the script to check for a registry key, and if it doesn't exist, it should create one because it is the first launch.
Javascript code:
// add to the top
var shell = new ActiveXObject("WScript.Shell");
 
// ...
 
function OnEvent_Initialize(MessengerStart)
{
    try {
        // value exists, already running, exit now
        shell.RegRead(MsgPlus.ScriptRegPath + "\\IsRunning");
        return false;
    } catch (error) {
        // not yet running, make a registry value, continue
        shell.RegWrite(MsgPlus.ScriptRegPath + "\\IsRunning", "1");
    }
 
    // Check if there's anything to be done
    if(emailList.length > 0) {
        MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
    } else {
        // finished, delete the registry key
        shell.RegDelete(MsgPlus.ScriptRegPath + "\\IsRunning");
    }
}
 
// ...


This will not work in all circumstances!

You have no control with this over the other scripts. Especially when you're executing multiple Messengers quickly after eachother, delays in loading (and loading Plus!, skins and scripts) will start to happen. This makes that another instance of this script might still be running (or still need to start running) by the time the 'main' script finishes. In other words, the 'main' script will remove the registry check before one of those other scripts get executed, and you're back to square one...

So, do not use a single boolean, instead you must keep track of what accounts have been signed in, or rather in the process of signing in because the actual sign in might fail.

quote:
Originally posted by Yustme
I got another quick question. Is there any way to check which email addresses have been logged in?
yes, but not directly. You either need to manipulate the other instances of Messenger directly as there is no easy way to 'talk' to other instances of the same script running in other Messengers.

Or you either need to find a common storage which is available for all other scripts at any time (eg: registry).

And if you go about it in a smart way, you can actually combine this with what I've suggested as a reply to Whiz' addition.

But either way, it is very tricky because signing in can take a very long time (even minutes). And it is only when you're signed in that you can 'store' the email account as being 'signed in'.

In other words, you can not use something like this to check what account has been signed in during the whole process of multiple sign ins. You can however use this to detect what accounts are already signed in *prior* to starting the whole multiple signin process, so you don't sign in an account twice (and thus sign out an account in one of the already existing Messenger instances).

To do this in the most easiest way:
In the OnEvent_SignIn() add (not replace) the email address to a registry string value if it doesn't already exist in that value (REG_MULTI_SZ is the preferred type, though REG_SZ will work too).

In the OnEvent_SignOut() you remove the email address again from that same registry value.

Then in your OnEvent_Timer() function you first check upon this registry value and only add accounts to the list if they don't exist in that registry value.

This method will prevent you from first signing out already signed in accounts, before signing them in again.
RE: my first script any help would be appriciated.. by whiz on 07-03-2010 at 11:35 AM

quote:
Originally posted by CookieRevised
This will not work in all circumstances!

You have no control with this over the other scripts. Especially when you're executing multiple Messengers quickly after eachother, delays in loading (and loading Plus!, skins and scripts) will start to happen. This makes that another instance of this script might still be running (or still need to start running) by the time the 'main' script finishes. In other words, the 'main' script will remove the registry check before one of those other scripts get executed, and you're back to square one...

So, do not use a single boolean, instead you must keep track of what accounts have been signed in, or rather in the process of signing in because the actual sign in might fail.
How about this?

Javascript code:
// add to the top
var shell = new ActiveXObject("WScript.Shell");
 
// ...
 
function OnEvent_Initialize(MessengerStart)
{
    try {
        // value exists, check the count, write the new one
        var Count = shell.RegRead(MsgPlus.ScriptRegPath + "\\RunCount");
        shell.RegWrite(MsgPlus.ScriptRegPath + "\\RunCount", Count--, "REG_DWORD");
        if (Count === 0) {
            // we're finished, delete the (correct) key :)
            shell.RegDelete(MsgPlus.ScriptRegPath + "\\RunCount");
        }
        return false;
    } catch (error) {
        // not yet running, make a registry value, continue
        shell.RegWrite(MsgPlus.ScriptRegPath + "\\RunCount", emailList.length, "REG_DWORD");
    }
 
    // Check if there's anything to be done
    if(emailList.length > 0) {
        MsgPlus.AddTimer('windowDelayer', delayOpenWnd);
    }
}
 
// ...


RE: RE: my first script any help would be appriciated.. by CookieRevised on 07-03-2010 at 11:56 AM

Sorry, the reason I gave why your addition would fail was slightly wrong...  it isn't the main reason (you get that from being a guy and being busy with multiple things at once :p).

The main reason for not working is that the boolean value will never be removed after the first execution:
emailList.length is always bigger than 0 (well, as long as you have hardcoded some accounts to sign in), so the script will never get to shell.RegDelete. Aka, it would work the first time (when there are no other delays that is), but not the second time.

But say you got the removal of the registry key correct, or that there were some delays in the loading of the other instances, then it would indeed fail for the reason I gave before. You indeed need to have at least a counter instead of a simple boolean, so:

quote:
Originally posted by whiz
How about this?
Javascript code:
...


Now the count is only initiated by the 'main' script, but further handled by the other instances and thus it wont be influenced by possible delays when loading scripts etc. Which looks alright at first sight....

...except for the small booboo:
    shell.RegDelete(MsgPlus.ScriptRegPath + "\\IsRunningRunCount");







PS: Yustme, there are some other things you do a bit wrong in your script and might result in bugs now or in the futur.

1) move the whole if (Messenger.Version >= 8.5) check inside OnEvent_Initialize().

This because the Messenger object might not be initiated yet when the script is loaded (it should, but there are no garantees, and it might change it in futur versions also).

You should never assume specific objects created by Messenger Plus! exist in the global scope of a script!

btw, as for the PerPassportSettings registry key, that can still be found under HKCU\SOFTWARE\Microsoft\MSNMessenger and it's still not version dependant. You also don't need the WLMexe variable anywhere. In other words, that whole version check can actually be removed.

--
But if you ever need to refer to the HKLM registry keys of Messenger, you should use:
Javascript code:
if (Messenger.Version >= 9) {
    var WLM_HKLM = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Live\\Messenger';
} else {
    var WLM_HKLM = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MSNMessenger';
}

Notice the 9 and not 8.5 !.


----------

2) You hard coded the path to the Messenger executable. This is not the proper way to handle this. Instead you should get the current path from the registry:
Javascript code:
// Get the installation path in a proper and secure way
try {
    var WSH = new ActiveXObject('WScript.Shell');
    if (Messenger.Version >= 9) {
        var sPath = WSH.RegRead('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Live\\Messenger\\InstallationDirectory');
    } else {
        var sPath = WSH.RegRead('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MSNMessenger\\InstallationDirectory');
    }
} catch(e) {
    Debug.Trace('Error: the mandatory registry key \'InstallationDirectory\' is missing.');
}

But, for your script, all you actually need is the executable of Messenger. In other words, the module of the process you are already running. You can get this very easily by using the Windows API GetModuleFileName:
Javascript code:
function GetMessengerExecutable() {
    var sBuffer = Interop.Allocate(2050);
    Interop.Call('Kernel32', 'GetModuleFileNameW', 0, sBuffer.DataPtr, sBuffer.Size / 2);
    return sBuffer.ReadString(0, true);
}


----------

3) Your SetBinaryValue() function (and thus possibly SetStringValue() too) can also use some work and a lot of optimizations. It also includes a major bug in the way it is coded and made to be used!!

For starters the content of the allocated datablock lBufferSize is calculated wrong for most binary values. It is not 2*stringsize+2, but just 2*stringsize in case you are passing a JScript string to it (like the function is currently set up).

The extra 2 bytes which are hard coded in that function come from the fact that this function was probably made with null terminated unicode JScript strings in mind. But not all binary variables consist of null terminated unicode string! In fact, most of them even don't (because strings can better be written as a REG_SZ)!!

You're simply lucky that it works because the DefaultMemberName registry key accidently needs a null terminated unicode string too.

This is highly important to know if you ever want to use that same function to write other binary values to the registry. In fact, even many binary registry keys which are in fact unicode strings aren't null terminted at all. So you wouldn't even be able to use this function as-is for such binary strings either.

Either way, this lBufferSize datablock isn't needed at all. The size parameter you need to pass is the length of the binary content (and nothing extra), and if you pass a JScript string you can just as well use a normal JScript variable for that or even directly using sKeyValue.length * 2.

And instead of adding the extra two bytes to accomodate the unicode null character in the size calculation inside the function, you should actually be passing a null terminated string to the function instead! Thus "MyString\0"

Then there is also the issue that unicode strings in JScript can not handle every possible character combination properly! Some character combinations will be converted automatically internally. This means that you actually should not use a JScript string to pass to such a function. Instead it should be made so you can pass a datablock.

And there is the issue that if you use that function with a registry path which doesn't exist yet, it will fail.

To make it short: that function needs a rewrite or should not be used as-is or be copied to another script like it is. Because it will fail for many binary values! Aka: it does not write all binary values properly.

Thus:
Javascript code:
SetBinaryValue(HKEY_CURRENT_USER, 'SOFTWARE\\Microsoft\\MSNMessenger\\PerPassportSettings', 'DefaultMemberName', email + '\0');
 
 
function SetBinaryValue(lKeyLocation, sKey, sKeyName, sKeyValue) {
    // Warning: this function can only be used to write unicode strings!!!
    // Any other attempt to write true binary content with this function might fail due to internal unicode conversions.
    var hKey = Interop.Allocate(4);
    var lRetVal = Interop.Call('advapi32.dll', 'RegCreateKeyExW', lKeyLocation, sKey, 0, 0, 0, KEY_WRITE, 0, hKey.DataPtr, 0);
    if (lRetVal === ERROR_SUCCESS) {
        lRetVal = Interop.Call('advapi32.dll', 'RegSetValueExW', hKey.ReadDWORD(0), sKeyName, 0, REG_BINARY, sKeyValue, sKeyValue.length * 2);
        Interop.Call('advapi32.dll', 'RegCloseKey', hKey.ReadDWORD(0));
    }
    return lRetVal === ERROR_SUCCESS;
}

- notice the addition of a null terminator character in the passed string instead of hard coding it in the function.
- notice the use of sKeyValue.length * 2 instead of that unneeded and wrong calculated datablock.
- notice the use of === (identity operator) which is faster than == (equality operator), also see here
- notice the use of RegCreateKeyExW instead of RegOpenKeyExW which will also create the registry path if it doesn't already exist.
- notice the smarter use of the return value lRetVal, making the code a whole lot shorter, yet the output will be identical as before.


;)
RE: my first script any help would be appriciated.. by petsas on 07-05-2010 at 11:13 AM

Really thank you all for your answers! :)

One more question:

When I run the code, it occurs an error regarding the HKEY_CURRENT_USER:

Error: 'HKEY_CURRENT_USER' is undefined (code: -2146823279)

       File: multiply_auto_login.js. Line: 120.

Function OnEvent_Timer returned an error. Code: -2147352567

Moreover, I want to use different accounts to sign in from the list. When I run the code,
the accounts that are created are the same as the initiator that runs the script..

Any ideas?


RE: my first script any help would be appriciated.. by matty on 07-05-2010 at 01:26 PM

Javascript code:
var HKEY_CLASSES_ROOT = 0x80000000;
var HKEY_CURRENT_USER = 0x80000001;
var HKCU = HKEY_CURRENT_USER;
var HKEY_LOCAL_MACHINE = 0x80000002;
var HKEY_USERS = 0x80000003;
var HKEY_PERFORMANCE_DATA = 0x80000004;
var HKEY_PERFORMANCE_TEXT = 0x80000050;
var HKEY_PERFORMANCE_NLSTEXT = 0x80000060;
var HKEY_CURRENT_CONFIG = 0x80000005;
var HKEY_DYN_DATA = 0x80000006;


RE: my first script any help would be appriciated.. by petsas on 07-05-2010 at 01:42 PM

Thank you very much!!

But, I realized that there are some more that are not defined in my code yet, such as:

KEY_WRITE, ERROR_SUCCESS and REG_BINARY!

Where did you find them? Is there any file that contains all such kind of macros!!

Thank you again :)


RE: my first script any help would be appriciated.. by Matti on 07-05-2010 at 02:26 PM

There used to be a list of them hosted on m00.cx, but apparently that server is down now. Luckily, I made a local copy of the list when it was still up - it's a pretty long list and I didn't have to wait that long every time I needed to look something up. I uploaded my copy as a TXT file to localhostr, go get it. In that list, you'll find that:

Javascript code:
var ERROR_SUCCESS = 0;
var REG_BINARY = 3;

Now, this list is just a rip-off from the Win32 C++ header files, so you'll find that most of the constants are defined as a combination of other constants. For example, KEY_WRITE is defined as:
Javascript code:
var KEY_WRITE = ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE));

If you want to use the constant in your script, you have to include all references constants as well, or you calculate the result and assign it to your constant directly.

Or you just Google something like "const KEY_WRITE" and see if there's a result with the value in it. :P