Skip to content
⌘ NSIS Forum Archive

NSISArray plugin

147 posts

Afrow UK#
TobbeSweden, late reply but looking at the NSISArray script header of course you cannot use an ErrorStyle of 2. Using 2 stops the plugin pushing errors to the stack but of course the script macros are still popping the same number of elements. Hence why your problem occurs as it is expecting 4 items on the stack but only gets 3.

What you should have used was the ArrayErrorStyle macro which has 3 possible values: MsgBox, LogWin and Off. All 3 options still push items to the stack and therefore do not break any of the script header macros.

Edit: Will upload new version later with fixed SearchI/ExistsI.
Edit #2: Uploaded.

Stu
TobbeSweden#
Heh, had forgotten all about this 🙂

Good job on the update.

Now if arrays could only be an integrated part of NSIS itself...
dougcvc#
Hello great job on the plugin.

I am having trouble in using it for what i need however, i may just be doing something wrong.

I have added all the data in the array which consists of numbers and i need to sort in in a certain order.

Lets say the 3 values in the array are


7069
4776
63374


I need the data sorted from lowest to highest number, however when i use the sort function it arranges it as the following

4776
63374
7069

It sorts the nummbers by the first digit only.
Is there any way to sort by the values lowest to highest such as

4776
7069
63374

or am i just doing something wrong?



Many thanks.
Afrow UK#
Ah that is a problem. NSISArray stores strings and therefore sorts them as if they were strings (not numbers).

I would need to write a new sort function to perform this but at the moment I don't have the build tools available and won't have them for some time until I go back home.

Stu
dougcvc#
Ah thank you for the quick response, I am sure theres some other way to do what im trying to achieve anyway.

Cheers.
grs1961#
Re: Array Write fails to write empty strings

Originally posted by jerrydg
I have a couple of problems with NSISArray:

1. If I write to an index higher than one that has previously been written, that value is not actually written.
Don't skip over array indices. It's not really a random array, but if you pre-load things it will behave as you expect.

2. If I write a "" to an array element that previously contained a non-zero length string, that element is not set to the empty string. The write function seems to ignore an empty string parameter. This defeats the purpose of using an array to store user input that can legally be an empty string.
If you do:
${ArrayErrorStyle} MsgBox
at the start of the section you will get a big clue - hint: passing empty strings to macros is not necessarily a simple task.

Oh, and your example is missing a "${a1->Read} $tmp $i" from near the end of the loop (so it is working as written, not as intended).
Afrow UK#
That is explained under 2.3 Plug-in DLL information. I will take a look at the empty string problem some time today.

Yes as jerrydg has rightly pointed out - you can't just skip an array index as the upper bound when working with the array needs to be known otherwise memory leaks are possible.

Stu
grs1961#
Re: limit on number of arrays

Originally posted by jerrydg
I ran into another undocumented limitation: There is a limit of 8 arrays. 🙁 I realize my installer requirements are atypical, but this is a pretty small upper bound.
But it is documented, you just have to read far enough along.

That said, I re-built it almost immediately with 24 as the limit.
Afrow UK#
I have added a /numeric switch to the Sort function to sort an array numerically rather than alphabetically. I have also addressed the issue of adding empty values to an array.

Stu
HarryPlotter#edited
Since a few days I am working with this great plugin.
I only have one problem with it. If the array is not previously initialized, there is a stack problem in ${myArray->Inited}.
I've modified the example Inited.nsi. It shows the problem.
ChocJunkie#
NSISArray and "0xC0000005 - access violation" error

Hi,

I'm using the NSISArray plugin for quite some time now. Until today it worked perfectly for me.
Today, I've added another array to my installer. Now I get the system error '0xc0000005' (access violation of the memory) after I did differnt actions on my different arrays.

I've got absolutely no hint whats the problem - beside its a memory error. I've tried several differnt combinations of active (-> initialized and not deleted) arrays and sizes of the arrays.

I did several test to get a hint.

Test (#1):
I've got 8 active arrays. When I'm trying to init the 9th one, the initialization fails. After that I trie to delete all initialized arrays befor the installer ends. The first three deletion commands succeed. Deleting the fourth array fails and I get the '0xc0000005' exception.

Test #2:
I'm using only 8 active arrays. Everything works fine until I want to delete the arrays when the installer finishes. Like at test #1, the first three deleting commands succed - yes, that are the same as in #1. The fourth deletion command fails. Result: The same error for the SAME! memory address.

Test #3:
It's the same installer as in #2.
I cancel the installation process early when I've got only 2 initialized arrays. Everything works fine.

I'm kind of helpless about determing and solving the problem.
Any ideas what the reason could be or what I can text explicitly?

Thanks!

CJ

[moderator - 2 post thread merged into plug-in discussion)
ChocJunkie#
Ok, at first I have to say, I'm not used to C/C++. 😉

I've rebuilded the NSISArray plug-in as debug version. The debugger shows me:
- I've got 8 active arrays [as expected]
- the pointers to my first two arrays have been overwritten at some point. So that they are pointing to nowhere (at the address 0x00000000). [unexpected]

I know, the two compromized arrays have not been wrong right from the beginning, because I'm using them several times befor the crash occueres.

If someone comes up with 'Oh, I know at which line/block of the plug-in the problem is located!', I would be happy. 😉


CJ
ChocJunkie#edited
Two things...

1.) Why can only 8 arrays be declared? Is there a reason or can I manipulate this value for my purpose?


2.) Inside the debug function, the value of g_iArrayCount is decreased at last after deleting the array. Because of that, the array after the deleted one will be erased. (But this one is empty so that no problems will be detected.) That's not exactly correct but it works as long as the user doesn't use 8 (ARRAY_MAX_COUNT) arrays. Because if he does, the memory 'after' the array will be manipulated.

In short

Old version:
g_iArrInformation[g_iArrayCount][ARRAY_UPPERINDEX] = g_iArrInformation[g_iArrayCount][ARRAY_INDEXES] = g_iArrInformation[g_iArrayCount][ARRAY_BUFFER] = 0;
my_strcpy(g_szArrNames[g_iArrayCount], (int)ARRAY_BUFFER_NAME, "", 1);
g_iArrayCount--;
Corrected
g_iArrayCount--;
g_iArrInformation[g_iArrayCount][ARRAY_UPPERINDEX] = g_iArrInformation[g_iArrayCount][ARRAY_INDEXES] = g_iArrInformation[g_iArrayCount][ARRAY_BUFFER] = 0;
my_strcpy(g_szArrNames[g_iArrayCount], (int)ARRAY_BUFFER_NAME, "", 1);
CJ
Afrow UK#
Thanks for spotting that. With that fixed would you mind posting a script that crashes?

Stu
Afrow UK#
v2.2 is now available. Some bug fixes, new NSIS plugin API integration and a unicode build is included.

Stu
SpudNyk#
Error in ReadFirst Macro

There is an compilation error when using the ReadFirst Macro

I belive I fixed it by changing line 676 from:
${Array_PopErrVar} 
to:
${Array_PopErrVar} true
Asides from that the plugin works well, Thanks for writing it and supporting it too.

Cheers
Afrow UK#
Uploaded v2.4. The DLL had an XML manifest in it defining Microsoft VC90 CRT as a dependency.

Stu
montonero#
Hi. Thanks for useful plugin. There's my contribution: errors fixes for Join and Subtract functions.
--- I:/nsis/Contrib/NSISArray/NSISArray.cpp    Thu Apr 22 12:57:24 2010
+++ C:/Program Files/NSIS/Contrib/NSISArray/NSISArray.cpp    Mon Oct 18 11:41:42 2010
@@ -1,5 +1,6 @@
 #include <windows.h>
 #include <commctrl.h>
+#include <assert.h>
 #ifdef UNICODE
 #include "nsis_unicode/pluginapi.h"
 #else
@@ -1462,9 +1463,10 @@
         return;
       }
 
+      int iBiggestArrayBuffer=max(g_iArrInformation[iArrayIndexA][ARRAY_BUFFER], g_iArrInformation[iArrayIndexB][ARRAY_BUFFER]);
       for (i=0; i<iNewSize; i++)
       {
-        szArrTemp[i] = (TCHAR *)MALLOC(sizeof(TCHAR) * g_iArrInformation[iArrayIndexA][ARRAY_BUFFER]);
+        szArrTemp[i] = (TCHAR *)MALLOC(sizeof(TCHAR) * iBiggestArrayBuffer);
         if (szArrTemp[i] == NULL)
         {
           FREE(szArrTemp);
@@ -1474,10 +1476,10 @@
       }
 
       for (i=0; i<=g_iArrInformation[iArrayIndexB][ARRAY_UPPERINDEX]; i++)
-        my_strcpy(szArrTemp[i], g_iArrInformation[iArrayIndexA][ARRAY_BUFFER], g_szArrData[iArrayIndexB][i], g_iArrInformation[iArrayIndexB][ARRAY_BUFFER]);
+        my_strcpy(szArrTemp[i], iBiggestArrayBuffer, g_szArrData[iArrayIndexB][i], g_iArrInformation[iArrayIndexB][ARRAY_BUFFER]);
 
       for (i=g_iArrInformation[iArrayIndexB][ARRAY_UPPERINDEX]+1, j=0; i<iNewSize; i++, j++)
-        my_strcpy(szArrTemp[i], g_iArrInformation[iArrayIndexA][ARRAY_BUFFER], g_szArrData[iArrayIndexA][j], g_iArrInformation[iArrayIndexA][ARRAY_BUFFER]);
+        my_strcpy(szArrTemp[i], iBiggestArrayBuffer, g_szArrData[iArrayIndexA][j], g_iArrInformation[iArrayIndexA][ARRAY_BUFFER]);
 
       for (i=0; i<g_iArrInformation[iArrayIndexB][ARRAY_INDEXES]; i++)
         FREE(g_szArrData[iArrayIndexB][i]);
@@ -1487,7 +1489,7 @@
 
       g_iArrInformation[iArrayIndexB][ARRAY_UPPERINDEX] = iNewSize-1;
       g_iArrInformation[iArrayIndexB][ARRAY_INDEXES] = iNewSize;
-      g_iArrInformation[iArrayIndexB][ARRAY_BUFFER] = g_iArrInformation[iArrayIndexA][ARRAY_BUFFER];
+      g_iArrInformation[iArrayIndexB][ARRAY_BUFFER] = iBiggestArrayBuffer;
 
       NoErrorMsg();
     }
@@ -1860,6 +1862,13 @@
         }
       }
 
+      if (!iNewSize){
+        NoErrorMsg();
+        return;
+      }
+
+      iNewSize=g_iArrInformation[iArrayIndexA][ARRAY_UPPERINDEX]-iNewSize+1;
+
       szArrTemp = (TCHAR **)MALLOC(sizeof(TCHAR *) * iNewSize);
       if (szArrTemp == NULL)
       {
@@ -1881,16 +1890,13 @@
       for (i=0; i<=g_iArrInformation[iArrayIndexA][ARRAY_UPPERINDEX]; i++)
       {
         bFound = FALSE;
-        for (j=0; j<=g_iArrInformation[iArrayIndexB][ARRAY_UPPERINDEX]; j++)
-        {
-          if (lstrcmp(g_szArrData[iArrayIndexA][i], g_szArrData[iArrayIndexB][j]) == 0)
+        for (j=0; j<=g_iArrInformation[iArrayIndexB][ARRAY_UPPERINDEX] && !bFound; j++)
           {
-            bFound = TRUE;
-            break;
-          }
+          bFound = !lstrcmp(g_szArrData[iArrayIndexA][i], g_szArrData[iArrayIndexB][j]);
         }
         if (!bFound)
         {
+          assert(k<iNewSize);
           my_strcpy(szArrTemp[k], g_iArrInformation[iArrayIndexA][ARRAY_BUFFER], g_szArrData[iArrayIndexA][i], g_iArrInformation[iArrayIndexA][ARRAY_BUFFER]);
           k++;
         } 
TVNST#
I'm using the newest version 2.4, but I still can't add empty strings.
Will this ever be fixed? Since for my purposes, it's unusable this way.

Any alternatives?
I've tried NSArray, but it suffers from memory corruption from time to time, loosing complete values or returning corrupted ones.
NSISList plug-in sounds good, but I can only use unicode plugins and it doesn't seem to have a dll for that. Same applies to stack plugin.
Afrow UK#
Originally Posted by TVNST View Post
I'm using the newest version 2.4, but I still can't add empty strings.
Will this ever be fixed? Since for my purposes, it's unusable this way.

Any alternatives?
I've tried NSArray, but it suffers from memory corruption from time to time, loosing complete values or returning corrupted ones.
I don't plan on updating NSISArray any more but I will if I get time. As for nsArray, I have not experienced any memory corruption and I have tested thoroughly in a debugger. Are you using the ANSI or Unicode build? Do you have a script which reproduces?

Stu
TVNST#
I used the Unicode build of both nsArray and NSISArray.

Unfortunately, the memory corruption problems only occur sporadic. There's no way to reproduce the problem reliable.
However, they occured on two different computers.

I experienced two different kinds of problems:
1.) Elements that were added are suddenly missing
I had this several times. I add usually 'sets' of parameters via macro.
Therefore if the first parameter is retrieved, the other parameters must also have been added since the NSIS compiler would fail if there's a parameter missing.
Example:
!macro _TVWriteRegStr sRegPath sValName sValData

nsArray::Set aRegActions /list "WRITE_STRING" `${sRegPath}` `${sValName}` `${sValData}` /end
!macroend
At a later point I retrieve this command values and compute them.
Now, the error I got was that I could retrieve "WRITE_STRING", but if I tried to get one of the following parameters with nsArray::Get aRegActions $R0 the error flag is set, indicating that the array reached its last value which was clearly not the case.

2.) Elements corrupted
Another problem I experienced a few times was if I added a string value, then one letter of the string value was corrupted when I retrieved the value.
One example I remember is that I added "DELETE" and got "DE$ETE" when retrieving the value.

However, there's still the possibility that it's not a bug from nsArray itself, but another buggy plugin function that corrupts the memory of nsArray. However, I would have guessed that this would also affect the NSIS stack, since it's elements are also created dynamically.
Afrow UK#
After your code:

aRegActions = { 0 => "WRITE_STRING", 1 => "${sRegPath}", 2 => "${sValName}", 3 => "${sValData}" }

Are you saying nsArray::Get aRegActions 1 sets the error flag?

For what you are doing, you may find it easier to use my nsJSON plug-in.

Stu
TVNST#
I think I had both the first and the second value setting an error flag on different occasions.
However, the array stores more than just one Registry-Action.
All registry actions in the NSIS code are first gathered in the array and then executed in a loop through all registry actions.
The idea behind that is to implement a rollback on errors mechanism similar to MSI installers which is not supported by NSIS by default.
Therefore, the error flag was set on something like nsArray::Get aRegActions 42 since it wasn't in the first registry action, it was somewhere inbetween.

The JSON plugin uses a file which is not what I want. I could also have used an ini file in this case.
File errors are the most likely errors that can occur in an installation and I want to avoid to make an error check on each write or read operation.
Therefore I'd prefer to keep those actions in the memory.
Afrow UK#
Originally Posted by TVNST View Post
I think I had both the first and the second value setting an error flag on different occasions.
However, the array stores more than just one Registry-Action.
All registry actions in the NSIS code are first gathered in the array and then executed in a loop through all registry actions.
The idea behind that is to implement a rollback on errors mechanism similar to MSI installers which is not supported by NSIS by default.
Therefore, the error flag was set on something like nsArray::Get aRegActions 42 since it wasn't in the first registry action, it was somewhere inbetween.

The JSON plugin uses a file which is not what I want. I could also have used an ini file in this case.
File errors are the most likely errors that can occur in an installation and I want to avoid to make an error check on each write or read operation.
Therefore I'd prefer to keep those actions in the memory.
I'll look into the nsArray issues when I can. As for nsJSON you don't need to use files at all. You can create and manipulate a JSON tree in memory.

Stu
TVNST#
Thanks for the help. I check out the JSON plugin again. If it can keep the data in the memory then it could be a solution for my problems.
I hope I can find some examples somewhere since its use with the tree notes seems a bit complicated.