Inno Setup - Fully resolve an environment variable that contains another variable - global-variables

Edit - this issue appears to be Windows 7 and Vista due to a bug (see here - Same issue reported)
Edit2 - I might be running into a similar issue users wee with PATH (I am not using PATH but same result - Unanswered question with similar issues
I have an Inno Setup script that uses an environment variable to locate a folder and delete the contents. When I try to expand the variable without elevated privileges I get this:
TEST_USER=%APPDATA%\PROG\USER_DATA (this is set in Windows)
If I run this as Admin (or change privileges to admin) I see:
TESTUSER=c:\users\username\appdata\roaming\PROG\USER_DATA
Googling %APPDATA% issues shows others have this issue, usually they hit this when used in PATH, something to do with the path not being set before it is requested.
I was hoping to avoid a complex routine of checking with pos if the return value contains %appdata%. But I think that might be my only solution.
cmd.exe - Example of the issue

This was my answer to make it work. However, please check the answer from #Tobias81 to InnoSetup, expand environment variable (taken from registry value using {reg:...} ) that works and offers a more generic solution.
I am making multiple modules first then combining later to making 1 executable with multiple components so a user can select an action. Due to this I need to check the current value of a variable not the registry value. Plus the registry still returns %APPDATA% as my screen shot.
So my answer was to just hunt for the appearance of %APPDATA% and deal with it.
Here is my debugging routine. Now I can find it and deal with it allowing me to find the value no matter if it was set by the parent or only set in windows.
procedure InitializeWizard;
var
test_user: string;
app_user: string;
folder_to_find: string;
begin
test_user := (ExpandConstant('{%TEST_USER}'));
app_user := (ExpandConstant('{%APPPDATA}'));
if (test_user <> '') AND (Pos(Uppercase('%APPDATA%'), Uppercase(test_user))=0) then
begin
folder_to_find := test_user;
MsgBox('Folder found : ' + folder_to_find + ' APPDATA STRING WAS NOT DETECTED', mbInformation, MB_OK)
end
else
if (test_user <> '') AND (Pos(Uppercase('%APPDATA%'), Uppercase(test_user))=1) then
begin
StringChangeEx(test_user, '%APPDATA%', '', True);
folder_to_find := app_user + test_user;
MsgBox('Folder found : ' + folder_to_find + ' APPDATA STRING WAS DETECTED & REMOVED!', mbInformation, MB_OK);
end
else
begin
MsgBox('The TEST_USER Environment is not set' + #13#10#13#10 + 'This process will now exit!',mbInformation, MB_OK)
Abort;
end;
end;

Related

Error during compiling: `identifier not found` (code C3861)

I have a field in my acore_characters table named 'rank' with a tinyint which ranges from 0 to 3 inclusive, based on player's progression. I need to read that value at both login and at certain specific circumstances.
I wrote the following PreparedStatement: "SELECT rank FROM acore_characters WHERE guid = ?" and then the code which is supposed to read that value:
uint16 GetCharactersRank(uint64 guid) {
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(mystatement);
stmt->setUInt32(0, GetGUID());
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (result) {
[...truncated]
and then fetching the result and so on, but then I get a code C8361 when compiling because 'GetGUID':identifier not found in Player.cpp file...what goes wrong? The other GetGUID calls throughout the file dont give this result. I'm not very fond of c++, any help is very appreciated.
It's not recommended to directly patch the core to add customisations to it. Instead, use modules.
An example can be found here: Is it possible to turn a core patch into a module for AzerothCore?
You can have a look and copy the skeleton-module and start modifying it to create your own.
In your case, you probably want to use the OnLogin player hook.

How to get Delphi to access an SQLite database in the directory of the executable? [duplicate]

This question already has answers here:
Delphi Get file location
(2 answers)
Closed 6 years ago.
I am using SQLite, rather than MySQL, because it is simpler and requires no extra running software, just my executable.
For simplicity's sake I would prefer to have the database file in the same directory as my executable, and to be able to copy or move that folder elsewhere and still have the program work. Meaning that it can find the SQLite database file, which was copied along with it, in its new location.
However, it looks like I have to specify an absolute path to the database file.
Is there any way to change this at run time?
For those who don't quite follow that, I will try to explain:
let us say that my app's .exe is in C:\A\A.exe
so, I want to put the database file in the same directory. Lets call it C:\A\A.db
Delphi seems to require an absolute path. I.e, C:A\A.db and not .\A.db
I want to be able to copy both the .exe and its database to C:\B and still have the .exe be able to find its database file, which is now in C:\B\A.db
How can I do that programmatically, at run-time?
Answer
The path to the database is stored in the database connection component, so something like myConnection.parameters.database := 'C:\my_database.db;
Just compute the SQlite3 database file name on the fly, using:
myDbFileName := ExtractFilePath(paramstr(0)) + 'mysqlite3file.db3';
This will point e.g. to c:\my\app\folder\mysqlite3file.db3 file, when you run c:\my\app\folder\myprogam.exe.
First you want to copy the db to the EXE folder :
if FileExists(FDConnection1.Params.Database) then
CopyFile(Pchar(FDConnection1.Params.Database),Pchar('EXE Folder\A.db'),True);
then you can change the connection to the new db (copy) :
if FileExists('EXE Folder\A.db') then
begin
FDConnection1.Params.Database := 'EXE Folder\A.db';
FDConnection1.Connected := True;
end;
You always have to specify absolute path to the database file. Alternative would be preforming a full search for the database file which is stupid.
Here is a little piece of code I use to create backup of the database so you get the idea:
procedure TForm1.dxBarButton1Click(Sender: TObject);
var fileSource, fileDest,dirName: string;
begin
dirname := ExtractFilePath(Application.ExeName)+'\backup database' ;
if not directoryexists(dirName) then
CreateDir(dirName);
if MessageDlg('Create database copy ?'+ #13#10 +'Attention,new copy will overwrite existing one',
mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrNo then
exit
else
try
dataModule2.ACRDatabase1.Close;
fileSource := ExtractFilePath(Application.ExeName)+'sgit.adb';
fileDest := ExtractFilePath(Application.ExeName)+'\backup database\sgit.adb';
If CopyFile(PChar(fileSource), PChar(fileDest), False) then begin
dataModule2.ACRDatabase1.Open;
dataModule2.FIRME.Open;
ShowMessage('Copy was made !');
end else
RaiseLastOSError;
except on E: Exception do
showMessage(Format('Error during copying : %s',[E.Message]));
end;
end;
So in your case you can write to an *.ini file where the database was copied to and then load the information during startup of your application. So basically you must always supply the database path (fileSource). How you do it is up to you. Just an idea ...

Why is SQL Server not recognized, even though I've got a reference to DAL05.dll?

It seems that whenever I add anything to my project which uses code in my commonClass.vb file, I get errors about SQL Server not being recognized.
I do have a reference to DAL05.
SQL Server in the file shows it's not recognized, as does the DAL05.DataAccess imports:
Do I need to add another reference? Another or a different Imports? Or what?
As you can see, I am referencing DAL05, and it is not offered as a way for SQL Server to be recognized:
UPDATE:
A possibly significant factoid: A difference between the legacy project - which has no problem with recognizing SQL Server - is that it does not even have a References folder; DAL05.dll (and DAL05.pdb) are below \<project>\bin\Common
So should I force a Bin and Bin\Common folder into my project (via Windows Explorer) and then add those files there? Is that the solution (no pun intended)?
UPDATE 2:
Okay, now this is getting really weird; based on a clue I found here about a similar issue, I prepended DAL095.DataAccess. to the SQL Server like so:
Dim sqlDAL As New DAL05.DataAccess.SQLServer(
The results are as follows:
This does NOT reduce the number of errors.
This seems superfluous/moot because DAL05.DataAccess." is grayed out.
The red underscore on the second and last r of SQLServer is NOT removed.
Yet, when I 2-click the top "Type 'SQLServer' is not defined." error msg from the error list, it no longer takes me to the references to "SQLServer" to which I have appended the seemingly useless "DAL05.DataAccess" but go instead only to the "naked" references to "New SQLServer":
In case it means anything, a failing function is:
Public Function GetUserInfo(ByVal userid As String, ByVal password As String, ByVal memberno As String) As DataTable
Dim sqlDAL As New SQLServer(System.Configuration.ConfigurationManager.AppSettings("OrderEnterConnection"))
Dim dset As DataSet
dset = sqlDAL.runSQLDataSet("Exec up_GetUserData_Web_2012 '" + userid + "','" + password + "','" + memberno + "'")
Return dset.Tables(0)
End Function
UPDATE 3:
Ever stranger: after I changed this:
Imports DAL05.DataAccess
...to this:
Imports DAL05.DataAccess.SQLServer
I was finally given some seemingly sensible Intellisense help; it said,
Import DAL05.DataAccess.SQLServer' and other missing references?
I accepted that, but I still have the same 204 errors.
And Imports DAL05.DataAccess.SQLServer is completely grayed out, with the following helpful msg:
As #B. Clay Shannon (the OP) Commented the solution is:
1) getting rid of all the TFS vestiges (files and entries in the .sln file);
2) Deleting the .suo files and (probably had nothing to do with it)
3) Opening Visual Studio as administrator.
Another Case
I was having the same problem and i does the following steps
1) closing all the open tabs, cleaning all the projects and rebuilding,
2) shutting down all my Visual Studio instances
3) restarting my computer.
and it fixed the issue

Set return value as environment variable

I would like to set the return value of an auth call (a token) as an environment variable so that other calls can make use of the value and I don't have to change that value manually.
Can Paw already do this easily?
If not, how would I lay out an extension to achieve this?
The best is that you set your OAuth dynamic value in your header field, then copy the value (select the text and hit Cmd + C):
Go to edit your environments and paste the dynamic value (Cmd + V) in a new variable:
Now go back to your header, and start to write the name of the environment variable you just created, it will offer you to use this variable:
You should be good to go now:
If later you need a change in your token, you can go back to the environments and edit it there, all at the same place.

Fix serialized data broken due to editing MySQL database in a text editor?

Background: I downloaded a *.sql backup of my WordPress site's database, and replaced all instances of the old database table prefix with a new one (e.g. from the default wp_ to something like asdfghjkl_).
I've just learnt that WordPress uses serialized PHP strings in the database, and what I did will have messed with the integrity of the serialized string lengths.
The thing is, I deleted the backup file just before I learnt about this (as my website was still functioning fine), and installed a number of plugins since. So, there's no way I can revert back, and I therefore would like to know two things:
How can I fix this, if at all possible?
What kind of problems could this cause?
(This article states that, a WordPress blog for instance, could lose its settings and widgets. But this doesn't seem to have happened to me as all the settings for my blog are still intact. But I have no clue as to what could be broken on the inside, or what issues it'd pose in the future. Hence this question.)
Visit this page: http://unserialize.onlinephpfunctions.com/
On that page you should see this sample serialized string: a:1:{s:4:"Test";s:17:"unserialize here!";}. Take a piece of it-- s:4:"Test";. That means "string", 4 characters, then the actual string. I am pretty sure that what you did caused the numeric character count to be out of sync with the string. Play with the tool on the site mentioned above and you will see that you get an error if you change "Test" to "Tes", for example.
What you need to do is get those character counts to match your new string. If you haven't corrupted any of the other encoding-- removed a colon or something-- that should fix the problem.
I came to this same problem after trying to change the domain from localhost to the real URL. After some searching I found the answer in Wordpress documentation:
https://codex.wordpress.org/Moving_WordPress
I will quote what is written there:
To avoid that serialization issue, you have three options:
Use the Better Search Replace or Velvet Blues Update URLs plugins if you can > access your Dashboard.
Use WP-CLI's search-replace if your hosting provider (or you) have installed WP-CLI.
Run a search and replace query manually on your database. Note: Only perform a search and replace on the wp_posts table.
I ended up using WP-CLI which is able to replace things in the database without breaking serialization: http://wp-cli.org/commands/search-replace/
I know this is an old question, but better late than never, I suppose. I ran into this problem recently, after inheriting a database that had had a find/replace executed on serialized data. After many hours of researching, I discovered that this was because the string counts were off. Unfortunately, there was so much data with lots of escaping and newlines and I didn't know how to count in some cases and I had so much data that I needed something automated.
Along the way, I stumbled across this question and Benubird's post helped put me on the right path. His example code did not work in production use on complex data, containing numerous special characters and HTML, with very deep levels of nesting, and it did not properly handle certain escaped characters and encoding. So I modified it a bit and spent countless hours working through additional bugs to get my version to "fix" the serialized data.
// do some DB query here
while($res = db_fetch($qry)){
$str = $res->data;
$sCount=1; // don't try to count manually, which can be inaccurate; let serialize do its thing
$newstring = unserialize($str);
if(!$newstring) {
preg_match_all('/s:([0-9]+):"(.*?)"(?=;)/su',$str,$m);
# preg_match_all("/s:([0-9]+):(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")(?=;)/u",$str,$m); // alternate: almost works but leave quotes in $m[2] output
# print_r($m); exit;
foreach($m[1] as $k => $len) {
/*** Possibly specific to my case: Spyropress Builder in WordPress ***/
$m_clean = str_replace('\"','"',$m[2][$k]); // convert escaped double quotes so that HTML will render properly
// if newline is present, it will output directly in the HTML
// nl2br won't work here (must find literally; not with double quotes!)
$m_clean = str_replace('\n', '<br />', $m_clean);
$m_clean = nl2br($m_clean); // but we DO need to convert actual newlines also
/*********************************************************************/
if($sCount){
$m_new = $m[0][$k].';'; // we must account for the missing semi-colon not captured in regex!
// NOTE: If we don't flush the buffers, things like <img src="http://whatever" can be replaced with <img src="//whatever" and break the serialize count!!!
ob_end_flush(); // not sure why this is necessary but cost me 5 hours!!
$m_ser = serialize($m_clean);
if($m_new != $m_ser) {
print "Replacing: $m_new\n";
print "With: $m_ser\n";
$str = str_replace($m_new, $m_ser, $str);
}
}
else{
$m_len = (strlen($m[2][$k]) - substr_count($m[2][$k],'\n'));
if($len != $m_len) {
$newstr='s:'.$m_len.':"'.$m[2][$k].'"';
echo "Replacing: {$m[0][$k]}\n";
echo "With: $newstr\n\n";
$str = str_replace($m_new, $newstr, $str);
}
}
}
print_r($str); // this is your FIXED serialized data!! Yay!
}
}
A little geeky explanation on my changes:
I found that trying to count with Benubird's code as a base was too inaccurate for large datasets, so I ended up just using serialize to be sure the count was accurate.
I avoided the try/catch because, in my case, the try would succeed but just returned an empty string. So, I check for empty data instead.
I tried numerous regex's but only a mod on Benubird's would accurately handle all cases. Specifically, I had to modify the part that checked for the ";" because it would match on CSS like "width:100%; height:25px;" and broke the output. So, I used a positive lookahead to only match when the ";" was outside of the set of double quotes.
My case had lots of newlines, HTML, and escaped double quotes, so I had to add a block to clean that up.
There were a couple of weird situations where data would be replaced incorrectly by the regex and then the serialize would count it incorrectly as well. I found NOTHING on any sites to help with this and finally thought it might be related to caching or something like that and tried flushing the output buffer (ob_end_flush()), which worked, thank goodness!
Hope this helps someone... Took me almost 20 hours including the research and dealing with weird issues! :)
This script (https://interconnectit.com/products/search-and-replace-for-wordpress-databases/) can help to update an sql database with proper URLs everywhere, without encountering serialized data issues, because it will update the "characters count" that could throw your URLs out of sync whenever serialized data occurs.
The steps would be:
if you already have imported a messed up database (widgets not
working, theme options not there, etc), just drop that database
using PhpMyAdmin. That is, remove everything on it. Then export and
have at hand an un-edited dump of the old database.
Now you have to import the (un-edited) old database into the
newly created one. You can do this via an import, or copying over
the db from PhpMyAdmin. Notice that so far, we haven't done any
search and replace yet; we just have an old database content and
structure into a new database with its own user and password. Your site will be probably unaccessible at this point.
Make sure you have your WordPress files freshly uploaded to the
proper folder on the server, and edit your wp-config.php to make it
connect with the new database.
Upload the script into a "secret" folder - just for security
reasons - at the same level than wp-admin, wp-content, and wp-includes. Do not forget to remove it all once the search and
replace have taken place, because you risk to offer your DB details
open to the whole internet.
Now point your browser to the secret folder, and use the script's fine
interface. It is very self-explanatory. Once used, we proceed to
completely remove it from the server.
This should have your database properly updated, without any serialized data issues around: the new URL will be set everywhere, and serialized data characters counts will be accordingly updated.
Widgets will be passed over, and theme settings as well - two of the typical places that use serialized data in WordPress.
Done and tested solution!
If the error is due to the length of the strings being incorrect (something I have seen frequently), then you should be able to adapt this script to fix it:
foreach($strings as $key => $str)
{
try {
unserialize($str);
} catch(exception $e) {
preg_match_all('#s:([0-9]+):"([^;]+)"#',$str,$m);
foreach($m[1] as $k => $len) {
if($len != strlen($m[2][$k])) {
$newstr='s:'.strlen($m[2][$k]).':"'.$m[2][$k].'"';
echo "len mismatch: {$m[0][$k]}\n";
echo "should be: $newstr\n\n";
$strings[$key] = str_replace($m[0][$k], $newstr, $str);
}
}
}
}
I personally don't like working in PHP, or placing my DB credentials in an public file. I created a ruby script to fix serializations that you can run locally:
https://github.com/wsizoo/wordpress-fix-serialization
Context Edit:
I approached fixing serialization by first identifying serialization via regex, and then recalculating the byte size of the contained data string.
$content_to_fix.gsub!(/s:([0-9]+):\"((.|\n)*?)\";/) {"s:#{$2.bytesize}:\"#{$2}\";"}
I then update the specified data via an escaped sql update query.
escaped_fix_content = client.escape($fixed_content)
query = client.query("UPDATE #{$table} SET #{$column} = '#{escaped_fix_content}' WHERE #{$column_identifier} LIKE '#{$column_identifier_value}'")

Resources