AutoHotkey warns that a local variable has the same name as a global variable - global-variables

Any time I try accessing a global variable from an AutoHotkey function with #warn enabled, I'm shown a warning prompt saying my local variable has the same name as a global variable.
This warning only seems to affect functions. Accessing the variable from a hotstring doesn’t raise any warnings.
#Warn
myString := "Hello, world!"
DisplayString() {
MsgBox %myString% ; Warning: local variable
}
^j::
MsgBox, %myString% ; Perfectly valid!
Return
Why can't I access global variables from a function when warnings are enabled?

When using #Warn, global variables should be explicitly declared as global to prevent ambiguity. This can be done in one of three ways.
Declare the variable as global prior to use
myString := "Hello, world!"
DisplayString()
{
global myString ; specify this variable is global
MsgBox %myString%
}
Assume-global mode inside the function
myString := "Hello, world!"
DisplayString()
{
global ; assume global for all variables accessed or created inside this function
MsgBox %myString%
}
Use a super-global variable
global myString := "Hello, world!" ; global declarations made outside a function
; apply to all functions by default
DisplayString()
{
MsgBox %myString%
}
For more information about global variables, refer to the official AutoHotkey documentation.

Related

Why does Go's package flag use pointers?

Consider the following code from gopl.io/ch2/echo4
package main
import (
"flag"
"fmt"
"strings"
)
var n = flag.Bool("n", false, "omit trailing newline")
var sep = flag.String("s", " ", "separator")
func main() {
flag.Parse()
fmt.Print(strings.Join(flag.Args(), *sep))
if !*n {
fmt.Println()
}
}
I'm interested why the variables n and sep are pointers to the flag variables, rather than normal variable type.
It is because they need to be assigned value after they are created. The order of actions is:
Create variable var n = flag.Bool("n", false, "omit trailing newline") The value is false now.
Assign value with flag.Parse(). Variable is now assigned value passed as command line argument.
If you check the code here, you'll see that there's an exported variable called CommandLine, which is a pointer to a FlagSet. This is where the magic happens. When you import that library, it's instantiated. When you invoke the exported functions, for example, flag.Bool(), that function, in turn, calls the method Bool(), which has a pointer receiver to...FlagSet. It will create a new bool to store your flag's value, invoke BoolVar() to store a pointer to the newly created bool variable within the FlagSet data structure (you'll need to trace BoolVar to see how this is accomplished), and returns the very same pointer to you so you can later get the current value (which could be the default value or an entirely new value as a result of the call toParse())
// CommandLine is the default set of command-line flags, parsed from os.Args.
// The top-level functions such as BoolVar, Arg, and so on are wrappers for the
// methods of CommandLine.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
// NewFlagSet returns a new, empty flag set with the specified name and
// error handling property. If the name is not empty, it will be printed
// in the default usage message and in error messages.
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
f := &FlagSet{
name: name,
errorHandling: errorHandling,
}
f.Usage = f.defaultUsage
return f
}
// A FlagSet represents a set of defined flags. The zero value of a FlagSet
// has no name and has ContinueOnError error handling.
//
// Flag names must be unique within a FlagSet. An attempt to define a flag whose
// name is already in use will cause a panic.
type FlagSet struct {
// Usage is the function called when an error occurs while parsing flags.
// The field is a function (not a method) that may be changed to point to
// a custom error handler. What happens after Usage is called depends
// on the ErrorHandling setting; for the command line, this defaults
// to ExitOnError, which exits the program after calling Usage.
Usage func()
name string
parsed bool
actual map[string]*Flag
formal map[string]*Flag
args []string // arguments after flags
errorHandling ErrorHandling
output io.Writer // nil means stderr; use Output() accessor
}
// Bool defines a bool flag with specified name, default value, and usage string.
// The return value is the address of a bool variable that stores the value of the flag.
func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
p := new(bool)
f.BoolVar(p, name, value, usage)
return p
}
// Bool defines a bool flag with specified name, default value, and usage string.
// The return value is the address of a bool variable that stores the value of the flag.
func Bool(name string, value bool, usage string) *bool {
return CommandLine.Bool(name, value, usage)
}
Going back to your question:
why the variables n and sep are pointers to the flag variables, rather than normal variable type.
It's because Parse() can manipulate the original variables and your new variables n and sep would have only captured a copy of the original values. By using the pointer, you and the FlagSet are looking at exact the same variables.

How can I dereference a pointer in Inno Setup Pascal Script?

I call a function from DLL-file in Inno Setup Script and its return type is PAnsiChar.
In order to get the whole string I need to dereference the pointer but the standard pascal syntax doesn't work here.
Is it even possible to do that?
function SQLDLL : PAnsiChar;
external 'GetSQLServerInstances#files:IsStartServer.dll stdcall setuponly';
function NextButtonClick(CurPage: Integer): Boolean;
var
hWnd: Integer;
Str : AnsiString;
begin
if CurPage = wpWelcome then begin
hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));
MessageBox(hWnd, 'Hello from Windows API function', 'MessageBoxA', MB_OK or MB_ICONINFORMATION);
MyDllFuncSetup(hWnd, 'Hello from custom DLL function', 'MyDllFunc', MB_OK or MB_ICONINFORMATION);
Str := SQLDLL;
try
{ if this DLL does not exist (it shouldn't), an exception will be raised }
DelayLoadedFunc(hWnd, 'Hello from delay loaded function', 'DllFunc', MB_OK or MB_ICONINFORMATION);
except
{ handle missing dll here }
end;
end;
Result := True;
end;
I have only the DLL-file. The original language is Delphi.
I updated to the latest version of Inno Setup 6.0.3 and tested this code on my home Windows 10 Pro machine:
[Setup]
AppName=My Program
AppVersion=1.5
WizardStyle=modern
DefaultDirName={autopf}\My Program
DisableProgramGroupPage=yes
DisableWelcomePage=no
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=userdocs:Inno Setup Examples Output
[Files]
Source: "MyProg.exe"; DestDir: "{app}"
Source: "MyProg.chm"; DestDir: "{app}"
Source: "Readme.txt"; DestDir: "{app}"; Flags: isreadme
Source: "IsStartServer.dll"; Flags: dontcopy
[Code]
function SQLDLL : PAnsiChar;
external 'GetSQLServerInstances#files:IsStartServer.dll stdcall';
function NextButtonClick(CurPage: Integer): Boolean;
var
Str : PAnsiChar;
begin
Str := SQLDLL;
Result := True;
end;
and now I'm having this kind of error:
I don't understand why does it have to look into my 'temp' directory? I've also heard that this problem may somehow be connected with the group policies in Windows 10 UAC, but I'm not really sure what should I do here to get rid of this error.
If I understand correctly, your SQLDLL manages some memory buffer itself and returns a pointer to a Unicode string (not ANSI, that's why you got only one character when you tried PAnsiChar, according to your comment).
Inno Setup doesn't support this directly and doesn't even have a PWideChar type. However, we can handle it ourselves. We just have to allocate a Inno string with the right size and copy the data manually.
Here is a working example how to do that. It uses GetCommandLineW as an example function that returns a PWideChar, but you can do the same with your SQLDLL function.
Get the pointer from the external function and store it in a variable (a Cardinal - in my example I created a typedef PWideChar for it).
Get the string length using lstrlenW.
Create an empty regular String, but set it to the right length using SetLength. This will reserve enough capacity that we can write the actual contents into it in the next step.
Use lstrcpyW to copy the string that's referenced by the pointer to your regular String variable.
(In case you use the ANSI version of Inno Setup: Use WideCharToMultiByte instead, see my update at the end of this post.)
The trick is to import lstrcpyW in such a way that the destination pointer is declared as String but the source pointer is declared as Cardinal (or my typedef PWideChar here).
type
PWideChar = Cardinal; { Inno doesn't have a pointer type, so we use a Cardinal instead }
{ Example of a function that returns a PWideChar }
function GetCommandLineW(): PWideChar;
external 'GetCommandLineW#kernel32.dll stdcall';
{ This function allows us to get us the length of a string from a PWideChar }
function lstrlenW(lpString: PWideChar): Cardinal;
external 'lstrlenW#kernel32.dll stdcall';
{ This function copies a string - we declare it in such a way that we can pass a pointer
to an Inno string as destination
This works because Inno will actually pass a PWideChar that points to the start of the
string contents in memory, and internally the string is still null-terminated
We just have to make sure that the string already has the right size beforehand! }
function lstrcpyW_ToInnoString(lpStringDest: String; lpStringSrc: PWideChar): Integer;
external 'lstrcpyW#kernel32.dll stdcall';
function InitializeSetup(): Boolean;
var
returnedPointer: PWideChar; { This is what we get from the external function }
stringLength: Cardinal; { Length of the string we got }
innoString: String; { This is where we'll copy the string into }
begin
{ Let's get the PWideChar from the external function }
returnedPointer := GetCommandLineW();
{ The pointer is actually just a renamed Cardinal at this point: }
Log('String pointer = ' + IntToStr(returnedPointer));
{ Now we have to manually allocate a new Inno string with the right length and
copy the data into it }
{ Start by getting the string length }
stringLength := lstrlenW(returnedPointer);
Log('String length = ' + IntToStr(stringLength));
{ Create a string with the right size }
innoString := '';
SetLength(innoString, stringLength);
{ This check is necessary because an empty Inno string would translate to a NULL pointer
and not a pointer to an empty string, and lstrcpyW cannot handle that. }
if StringLength > 0 then begin
{ Copy string contents from the external buffer to the Inno string }
lstrcpyW_ToInnoString(innoString, returnedPointer);
end;
{ Now we have the value stored in a proper string variable! }
Log('String value = ' + innoString);
Result := False;
end;
If you put this into an installer and run it, you see output like this:
[15:10:55,551] String pointer = 9057226
[15:10:55,560] String length = 106
[15:10:55,574] String value = "R:\Temp\is-9EJQ6.tmp\testsetup.tmp" /SL5="$212AC6,121344,121344,Z:\Temp\testsetup.exe" /DEBUGWND=$222722
As you can see, the command line string (which we get as a PWideChar) is copied to a regular string variable correctly and can be accessed normally at the end.
Update: In case you are using the ANSI version of Inno Setup and not Unicode, this code alone won't work. The change needed is this: Instead of using lstrcpyW, you'd use WideCharToMultiByte:
function WideCharToMultiByte_ToInnoString(CodePage: Cardinal; dwFlags: Cardinal; lpWideCharStr: PWideChar; cchWideChar: Cardinal; lpMultiByteStr: String; cbMultiByte: Cardinal; lpDefaultChar: Cardinal; lpUsedDefaultChar: Cardinal): Integer;
external 'WideCharToMultiByte#kernel32.dll stdcall';
{ Later on: Instead of calling lstrcpyW_ToInnoString, use this:
Note: The first parameter 0 stands for CP_ACP (current ANSI code page), and the
string lengths are increased by 1 to include the null terminator }
WideCharToMultiByte_ToInnoString(0, 0, returnedPointer, stringLength + 1, innoString, stringLength + 1, 0, 0);
You cannot dereference a pointer in Inno Setup Pascal Script.
But there are numerous hacks that allow that. Those hacks are very specific, so it depends on particular use case.
Though in your specific case, as pointers to character arrays are widespread in APIs, Inno Setup Pascal Script (similarly to Delphi) can assign a pointer to a character array to a string.
So, you should be able to simply assign the PChar to AnsiString:
function ReturnsPAnsiChar: PAnsiChar; extern '...';
var
Str: AnsiString;
begin
Str := ReturnsPAnsiChar;
end;
See How to return a string from a DLL to Inno Setup?

Using Perl script including R script to retrive Go annotations for list of accesion number

I have wrote a Perl script to retrieve Go annotations (Molecular Function especially with go id). To retrieve go annotation i use a chunck from R that can do this in few lines, and use Perl to format the output. But it's not working.
I have got this error:
Global symbol "$lines" requires explicit package name (did you forget to declare "my $lines"?) at GO_Perl_R line 21. Global symbol "$lines" requires explicit package name (did you forget to declare "my $lines"?) at GO_Perl_R line 22. Global symbol "$hits" requires explicit package name (did you forget to declare "my $hits"?) at GO_Perl_R line 22. Global symbol "$go" requires explicit package name (did you forget to declare "my $go"?) at GO_Perl_R line 24. Global symbol "#MF" requires explicit package name (did you forget to declare "my #MF"?) at GO_Perl_R line 24. Global symbol "$id" requires explicit package name (did you forget to declare "my $id"?) at GO_Perl_R line
24. Global symbol "$lines" requires explicit package name (did you forget to declare "my $lines"?) at GO_Perl_R line 25. Global symbol "$go" requires explicit package name (did you forget to declare "my $go"?) at GO_Perl_R line 25. Global symbol "#MF" requires explicit package name (did you forget to declare "my #MF"?) at GO_Perl_R line
25. Global symbol "#id" requires explicit package name (did you forget to declare "my #id"?) at GO_Perl_R line 25. Global symbol "$go" requires explicit package name (did you forget to declare "my $go"?) at GO_Perl_R line 25. Global symbol "#MF" requires explicit package name (did you forget to declare "my #MF"?) at GO_Perl_R line 25. Global symbol "#term" requires explicit package name (did you forget to declare "my #term"?) at GO_Perl_R line 25. Execution of GO_Perl_R aborted due to compilation errors.
This is my code :
#! usr/bin/perl
use warnings;
use strict;
use Statistics::R;
my $R = Statistics::R->new();
my $i = 1;
# open the file containing uniprot accession numbers
open (ACC, "acc_numbers.txt") or die "Can't open acc_numbers.txt: $!\n";
while (my #lines=<ACC>) {
chomp($_);
}
$R -> startR;
$R -> send('library(mygene);');
$R -> run (q`sink('GO_MF.txt')`);
$R -> run (q`sink()`);
$R -> run (
qq`while($lines){
res<-query($lines,fields='go')$hits,
sink('GO_MF.txt', append=TRUE),
while($i <= length(res$go$MF[[1]]$id) {
print(paste($lines,"\n",res$go$MF[[1]]$id[$i],"\t",res$go$MF[[1]]$term[$i],"\n"),
sink(),
}
}`
);
exit 0;
Any solution to reach my purpose using Perl script, R script or merging both should be useful.
The output file format is like :
P10214
GO:xxxxxxx "aaaaaaaaaaaaaaaaaaaaa"
GO:zzzzzzzz "bbbbbbbbbbbbbbbbbbbbb"
...................
Q34F56
GO:fffffffffff "ccccccccccccccccccccccc"
GO:gggggg "hhhhhhhhhhhhhhhhhhhh"
...................
Thanks you so much.
In double quoted strings, Perl interpolates variables. qq`...` is a double-quoted string, so $lines is interpreted as a Perl variable, but it hasn't been declared with my anywhere, hence the error.
BTW,
while (my #lines=<ACC>) {
chomp($_);
}
is wrong. It iterates just once, as <> used in list context returns all the lines of the filehandle. Inside the loop, $_ is chomped, but $_ hasn't been populated there. Instead, maybe you wanted
chomp( my #lines = <ACC> );

PHP7. Reflection doesn't work from old versions php

I have a php script which was written on php 5.6.19, works on 5.3 version to, with some installed addons.
I decide to try execute it on php7.
The special of the script that I am initializing a class with parameter by reference via creating a new instance with Reflection::class. And there warning then waited variable by reference but value received.
Definition of the class' constructor method tried to create an instance from:
public function __construct($user, IDatabase &$repository, $errors = null);
Sample of code where this constructor is used:
// define manager type to create (all managers has the same constructor)
$manager = $managersNamespace . ucfirst($this->_manager) . "Manager";
// trying to create the manager
// !!!And here a Warning occurs
$reflect = new \ReflectionClass($manager);
$manager = $reflect->newInstance($user, $database, $errors);
After these I am invoking a method I need, and here the fatal error with stopped the script:
$method = "show" . ucfirst($this->_page) . "Page";
$reflect->getMethod($method)->invoke($manager);
I didn't see any changes in documentation. Anyone had the same issue?
First and foremost, why are you passing an object by reference !?
Objects have pass-by-reference semantics, forcibly trying to pass objects by reference has not made good sense since PHP 4.
Just remove the & ...
Let's ignore that, and pretend there is still a problem, so that you can try to understand what is going on.
To break down the problem, first you need to understand the distinction between a variable and an expression:
mine(1 + 2);
The argument to mine has no name, it's represented by a temporary variable in the engine: it's an expression.
mine(1);
The argument to mine has no name, it's not an expression, but a literal constant, represented by a compiler variable in the engine. It's similar to a temporary variable, a kind of constant expression.
mine($a);
The argument to mine has a name, which you can use to refer to it's value. It's a normal variable.
Only variables can be passed by reference because you cannot refer to expressions or literal constants
Next you need to understand why we pass-by-reference:
function mine(int $thing) {
$thing++;
}
$a = 1;
mine($a);
var_dump($a); // int(1)
In this code, $a is passed to mine() by value, so that the changes that mine() make to $thing are only visible inside the scope of mine. $a is unchanged after the call to mine() returns because $a and $thing are distinct, having been passed-by-value, which means it's value was copied on to the call stack for the invocation of mine().
function mine(int &$thing) {
$thing++;
}
$a = 1;
mine($a);
var_dump($a); // int(2)
In the code above, $a is passed to mine() by reference, this means that $a and $thing are no longer distinct. The changes mine() make to $thing are now visible after the call to mine() returns.
The last piece in the puzzle is Reflection:
function mine(int &$thing) {
$thing++;
}
$a = 1;
$reflector = new ReflectionFunction("mine");
$reflector->invoke($a);
The code above will raise:
Warning: Parameter 1 to mine() expected to be a reference, value given in /usr/src/php-src/refs.php on line 9
This is because ReflectionFunction::invoke and similar reflection functions (ReflectionClass::newInstance) accept their parameters by value and pass them onto the invoked function by value.
But ...
There is still a difference between pass-by-reference semantics, and passing by reference, a dangerous one:
class Foo {
public function qux() {}
}
class Bar {}
function mine(Foo &$foo) {
$foo = new Bar();
}
$foo = new Foo;
mine($foo);
$foo->qux();
Will obviously yield:
PHP Fatal error: Uncaught Error: Call to undefined method Bar::qux() in /usr/src/php-src/refs.php:16
Stack trace:
#0 {main}
thrown in /usr/src/php-src/refs.php on line 16
The declaration of mine() tells lies about the type safety of it's parameter. Type safety is only guaranteed upon entry to the function, the function body is free to break type safety, but it doesn't usually affect the caller when relying on the engines pass by reference semantics for objects.
This is an extremely scary kind of API, that should be avoided.

C++ Static vector loses data after exiting function

I have a static function:
void TextManager::printDialogue(vector<Button*>* options, int optionsCount, vector<string> outputDisplayText)
{
active = true;
buttons = *options;
buttonsCount = optionsCount;
outputText = outputDisplayText;
}
The "buttons" variable is static:
static vector<Button*> buttons;
I make a call to printDialogue in an execute function:
void WorldDoor::execute()
{
vector<Button*> buttons;
buttons.push_back(new CancelButton());
buttons.push_back(new ChangeRoomButton(room));
TextManager::printDialogue(&buttons, 2, messages); //<----
std::vector<Button*>::iterator i = buttons.begin();
for ( i = buttons.begin() ; i < buttons.end(); i++ )
{
delete * i;
}
}
For whatever reason, when I debug and have a break point inside of the printDialogue function, the values in "buttons" are perfectly fine. However, after I leave printDialogue, the strings contained in my buttons go from being readable to giving me an error message saying:
I tried passing a pointer to an array instead of using
vector<Button*>
but it was only reading the first variable. Now it is not reading anything. Could anyone please help?
There is a static member variable called buttons, and also a local variable inside execute() called buttons. You should rename to avoid confusion, otherwise, the local variable will be used instead of the static member variable inside execute().
Edit: Completely misunderstood the question.
When you do this:
vector<int*> vector1;
vector<int*> vector2;
vector1.push_back(new int(5));
vector2 = vector1;
It copies the pointers, not the value of the pointers.
So when you later iterate over the first vector and delete the dynamic memory, both vectors have pointers pointing to the same memory that you deleted, so your second vector is pointing to invalid memory.
If you are using C++11, you can use a vector of unique pointers, and std::move() one vector into another.
Otherwise, you can just call 'clear()' on the vector, without deleting the memory.
Here's how the function could be written:
void TextManager::printDialogue(vector<Button*>* options, int optionsCount, vector<string> outputDisplayText)
{
active = true;
buttons = *options;
options->clear(); //<--- Instead of crawling over it and delete-ing it.
buttonsCount = optionsCount;
outputText = outputDisplayText;
}
Everything below this was my misunderstanding the question: (contains other information that might be important)
When you do:
vector<Button*> buttons;
Inside the function, you are creating a new vector called 'buttons', which gets destroyed at the end of the function call.
If you want to access the global one, don't create a new one inside the function, or name them something different.
Example:
int myVar = 100; //Declares a variable called 'myVar' at global scope.
void func()
{
int myVar = 200; //Declares a *different* variable called 'myVar' at function scope.
std::cout << myVar << std::endl; //Prints the one inside the function, not the one outside it.
}
By the way, the variable 'static' shouldn't be used at global scope, unless the variable belongs to a class.
To make a variable global, you just put it outside of any function. To make a class member shared between all instances of that class, you declare it static so that class knows to have all instances share the one variable. It's a different thing. =)
If you have your code split into multiple files, to make a global really-truly global, you have to declare it 'extern' in your header, and not extern in one source file, and have other source files #include the header that externs it. Slightly clunky, but that's how it's done. They are working on a better system for it, but it'll be several years before it becomes standardized.

Resources