How do i working with Arrays in a While loop? - c#

I have tried to wipe this data while trying to export a database into my program.
The basic problem is that I do not know why he can not use LIKE in my SQL statement.
So I wanted to catch all DataRows and write them into an array, which I can edit later.
The program throws an exception:
Error message: System.IndexOutOfRangeException: "The index was outside the array area."
If I did something unusual or wrong in my Post I sincerely apologies, this is my first entry in this forum.
Code:
public void TestQuery()
{
string file = #"C:\Users\Michael\Downloads\7z1900-x64.msi";
// Get the type of the Windows Installer object
Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
// Create the Windows Installer object
WindowsInstaller.Installer installer = (WindowsInstaller.Installer)Activator.CreateInstance(installerType);
// Open the MSI database in the input file
Database database = installer.OpenDatabase(file, 0);
// Open a view on the Property table for the version property
View view = database.OpenView("SELECT * FROM `File`");
// Execute the view query
view.Execute(null);
// Get the record from the view
Record record = view.Fetch();
int i = 1;
string[] sreturns = new string[60];
while (record != null)
{
Console.WriteLine("Ausgabe: " + record.get_StringData(0) + '=' + record.get_StringData(1) + '=' + record.get_StringData(2) + '=' + record.get_StringData(3));
record = view.Fetch();
sreturns[i] = record.get_StringData(0).ToString();
i++;
}
}

First thing I see is that you're starting at 1, while (C#) arrays are 0-based.
In you screenshot I see that i is 60, so that would be the problem. Index 60 doesn't actually exist in your array, as it goes from 0 to 59.

You can add i < sreturns.Length to make sure you are in the array range.
Also, make sure you start with i = 0 and not 1.
int i = 0;
string[] sreturns = new string[60];
while (record != null && i < sreturns.Length)
{
Console.WriteLine("Ausgabe: " + record.get_StringData(0) + '=' + record.get_StringData(1) + '=' + record.get_StringData(2) + '=' + record.get_StringData(3));
record = view.Fetch();
sreturns[i] = record.get_StringData(0).ToString();
i++;
}

Why not using a list instead of an array?
List<string> sreturns = new List<string>();
while (record != null)
{
try
{
Console.WriteLine("Ausgabe: " + record.get_StringData(0) + '=' + record.get_StringData(1) + '=' + record.get_StringData(2) + '=' + record.get_StringData(3));
record = view.Fetch();
var result = record.get_StringData(0);
sreturns.Add(result.ToString());
}
catch (Exception e)
{
Console.WriteLine("No record...");
}
}
This way you dont need to worry about the array size - its maintainable -efficient - and if in the future the size change you don't have to worry about it.
List documentation here

What is the query with LIKE that you have tried? The following should work:
SELECT * FROM File WHERE FileName LIKE '%.exe' OR FileName LIKE '%.msi'
EDIT: On further investigation (https://learn.microsoft.com/en-us/windows/win32/msi/sql-syntax), the documentation seems to imply that the LIKE operator is not supported. But you could start off with an IS NOT NULL and do more complex filtering in the loop, like you're doing.
EDIT 2, expanding on Alex Leo's answer.
List<string> sreturns = new List<string>();
while (record != null)
{
Console.WriteLine("Ausgabe: " + record.get_StringData(0) + '=' + record.get_StringData(1) + '=' + record.get_StringData(2) + '=' + record.get_StringData(3));
var result = record.get_StringData(0);
if(!string.IsNullOrWhiteSpace(result) && (result.EndsWith(".exe") || result.EndsWith(".msi")))
{
sreturns.Add(result.ToString());
}
record = view.Fetch();
}
Note that the view.Fetch() inside the while loop has been moved to the end, or you would skip the first record, as well as get another null reference when the last record has already been read, but the while loop executes one more time.

Related

Saving objects with FindObjectsOfTypeAll()

I have a save-Method to save informations about every block with one of five specific tags, like position, health, rotation etc.
I first want to get all objects (even inactive ones), so i use the FindObjectsOfTypeAll()-Method.
Then i go with a foreach loop through all of the objects that have been found, and check if they have the right tag and if they do, i save them.
This is the code i use:
GameObject[] allObjects = Resources.FindObjectsOfTypeAll(typeof (GameObject)) as GameObject[];
using (StreamWriter write = new StreamWriter(dir + "blocksSave.dat"))
{
Debug.Log(allObjects.Length);
foreach (GameObject block in allObjects)
{
bool isActive = block.activeSelf;
block.SetActive(true);
if (block.tag == "WoodBlock" || block.tag == "WoodSteps" || block.tag == "WoodRamp" || block.tag == "GlasBlock" || block.tag == "WoodDoor")
{
// SAVE
write.WriteLine(block.tag + "," + block.transform.position.x + "," + block.transform.position.y + "," + block.transform.position.z + "," + block.GetComponent<BlockControl>().GetHealth().x + "," + block.GetComponent<BlockControl>().GetHealth().y + "," + block.transform.rotation.x + "," + block.transform.rotation.y + "," + block.transform.rotation.z);
}
block.SetActive(isActive);
}
write.Close();
}
I debugged this and the line if (block.tag == "WoodBlock" || ...) works fine.
The problem is the next line:
write.WriteLine(...);
here i get a nullReferenceException, where it tells me:
NullReferenceException: Object reference not set to an instance of an
object
And i can't figure out why?!
The issue is very probably that
block.GetComponent<BlockControl>()
returns null for one of your found GameObjects since it simply does not have that component.
Instead you could use
Resources.FindObjectsOfTypeAll<BlockCo troll>();
to be sure you only have all the components of type BlockControl in a separate list.
Than you can use a List to easier filter the objects for the tag instead of those || conditions
var searchedTags = new List<string>()
{
"WoodBlock",
"WoodSteps",
"WoodRamp",
"GlasBlock",
"WoodDoor"
};
if (searchedTags.Contains(block.gameObject.tag))
{
....
}
or even esier use Linq to only get the objects you are interested in:
var objectsOfInterest = allObjects.Where(obj => searchedTags.Contains(obj.gameObject.tag)).ToList();
I would also only use the StreamWriter for actually writing and do nothing else within that using block.
And note that if you are using a StreamWriter inside of a using block you don't have to use write.Close() since it is disposed automatically after the using block finishes.
So in complete I would use something like
var searchedTags = new List<string>()
{
"WoodBlock",
"WoodSteps",
"WoodRamp",
"GlasBlock",
"WoodDoor"
};
// This list is used to get all GameObject
// keep track which where active and activate all
var allObjects = Resources.FindObjectsOfTypeAll<GameObject>();
// Here we get all BlockController components
var allBlockObjects = Resources.FindObjectsOfTypeAll<BlockController>();
// finally we only get BlockControllers with the tags we want
var objectsOfInterest = allBlockObjects.Where(obj => searchedTags.Contains(obj.gameObject.tag)).ToList();
Debug.Log("objects total: " + allObjects.Length);
Debug.Log("block objects: " + allBlockObjects.Length);
Debug.Log("objects of interest: " + objectsOfInterest.Length);
// Step 1 keep track which GameObjects where active and activate all
var objectWasNotActive = new List<GameObject>();
foreach (var obj in allObjects)
{
if(!obj.activeSelf)
{
// keep track which objects where not active
objectWasNotActive.Add(obj);
}
// Set all to true
obj.SetActive(true);
}
// Step 2 save your BlockControllers with searched tags
using (StreamWriter write = new StreamWriter(dir + "blocksSave.dat"))
{
foreach (var block in objectsOfInterest)
{
// Here you already have components of type BlockController
// so you don't need to get them
// But GetHealth might also return null so maybe you want to check that too
// It is up to you whether you want to skip or fill it with default values in such case
var health = block.GetHealth();
if(health == null)
{
//option 1 skip
continue;
// OR option 2 default e.g.
// Assuming it is Vector2
health = Vector2.zero;
}
// SAVE
write.WriteLine(
block.gameObject.tag + ","
+ block.transform.position.x + ","
+ block.transform.position.y + ","
+ block.transform.position.z + ","
+ health.x + ","
+ health.y + ","
+ block.transform.rotation.x + ","
+ block.transform.rotation.y + ","
+ block.transform.rotation.z
);
}
}
// Step 3 disable those GameObjects again that where not active before
foreach(var obj in objectWasNotActive)
{
obj.SetActive(false);
}
Now it's really hard to debug this without seeing the code, but try checking this first.
Check if write is being properly initialized without errors, sometimes it fails silently.
Are you sure that all of your objects with those tags have the component BlockControl on them ?
try updating your code to this just to check where exactly is it failing
if (block.tag == "WoodBlock" || block.tag == "WoodSteps" || block.tag == "WoodRamp" || block.tag == "GlasBlock" || block.tag == "WoodDoor")
{
Debug.Log(block.name);
Debug.Log(block.GetComponent<BlockControl>());
Debug.Log(block.GetComponent<BlockControl>().GetHealth());
// SAVE
write.WriteLine(block.tag + "," + block.transform.position.x + "," + block.transform.position.y + "," + block.transform.position.z + "," + block.GetComponent<BlockControl>().GetHealth().x + "," + block.GetComponent<BlockControl>().GetHealth().y + "," + block.transform.rotation.x + "," + block.transform.rotation.y + "," + block.transform.rotation.z);
}
This way you can find out which block is causing the issue and if the problem is with the component or the GetHealth() function.

System.Data.EvaluateException HResult=0x80131920 Message=Cannot perform '=' operation on System.Int32 and System.String

public void MatchedDocumentsInFileCabinet(string MainFolder, string SubFolder, string FileName, string FilePath)
{
// Checking Main Folder is present in FileCabinet, if present retrieving MainFolderID if not Inserting MainFolderName
if (SelectedFileCabinetID == "")
{
SelectedFileCabinetID = "1";
}
int Mainfoldercount = 0;
DocSortResult getfolderdetails = objFolderManager.GetFolderDetails();
DataTable getFolderNames = new DataTable();
if (getfolderdetails.resultDS != null && getfolderdetails.resultDS.Tables[0].Rows.Count > 0)
{
// Following line is showing error
DataRow[] drResult = getfolderdetails.resultDS.Tables[0].Select("FileCabinet_ID = '" + SelectedFileCabinetID + "'" + "and" + " ParentFolderID = '" + "0" + "'" + "and" + " IsDelete = '" + "True" + "'");
if (drResult.Count() != 0)
{
getFolderNames = drResult.CopyToDataTable();
}
}
}
Without knowing getfolderdetails.resultDS.Tables[0] structure is hard to know which column is, but one of those columns is integer and your Select(filter) is telling that all the fields are string.
An example of your code debugging would show .Select("FileCabinet_ID = '4' and ParentFolderID = '0' and IsDelete = 'True' "). And the error message says one of them is not a string.
I would bet that IsDelete = 'True' probably will be boolean (bit column in SQL Server) and FileCabinet_ID or ParentFolderID or both of them are integer (and this is causing the error).
Set a breakpoint and check the datatypes of the datacolumns you are trying to filter.

Index was outside the bounds of the array in MSCORLIB.DLL

I will be amazed if I find a solution for this, since it is very specific and vague, but I figured I would try. I'll try to give as much information as humanly possible, since I've been searching for answers for some time now.
I am building a utility in C# which copies records from a file in a library on the i-series/AS400 and builds an encrypted text file with each record from the AS400 as a comma separated string. In the file, it will have values like filename, fieldvalue1, fieldvalue2, fieldvalue3. I then take that text file to another PC, and run a C# utility which copies that record into the same file name in a library over there on a different i-series machine. Unfortunately, I receive the outside bounds of the array exception in some cases, but I cannot determine why. In the record just prior to the exception, the record looks pretty much the same and it works fine. My code is below in a nutshell. I usually don't give up, but I don't expect to ever figure this out. If someone does, I'll probably sing karaoke tonight.
// Select records from AS400 file and write them to text file
Recordset rs = new Recordset();
sqlQuery = "SELECT * FROM " + dataLibrary + "." + fileName;
try
{
rs.Open(sqlQuery, con);
while (!rs.EOF)
{
int[] fieldLengths;
fieldLengths = new int[rs.Fields.Count];
String[] fieldValues;
fieldValues = new String[rs.Fields.Count];
String fullString = "";
for (i = 0; i < rs.Fields.Count; i++)
{
fieldLengths[i] += rs.Fields[i].DefinedSize;
fieldValues[i] += rs.Fields[i].Value;
}
fullString = fileName + "," + String.Join(",", fieldValues);
fullString = Functions.EncryptString(fullString);
File.AppendAllText(savefile.FileName, fullString + Environment.NewLine);
rs.MoveNext();
}
}
catch (Exception ex)
{
}
cmd.Dispose();
// This gives me a text file of filename, fieldvalue1, fieldvalue2, etc...
// Next, I take the file to another system and run this process:
while ((myString = inputFile.ReadLine()) != null)
{
int stringLength = myString.Length;
String[] valuesArray = myString.Split(',');
for (i = 0; i < valuesArray.Length; i++)
{
if (i == 0)
{
fileName = valuesArray[0];
// Create file if it doesn't exist already
createPhysicalFile(newLibrary, fileName);
SQLStatement = "INSERT INTO " + newLibrary + "." + fileName + "VALUES(";
}
else
{
if (i == valuesArray.Length - 1)
{
SQLStatement += "#VAL" + i + ")";
}
else
{
SQLStatement += "#VAL" + i + ", ";
}
}
}
try
{
using (connection)
{
try
{
connection.Open();
}
catch (Exception ex)
{
}
// Create a new SQL command
iDB2Command command = new iDB2Command(SQLStatement, connection);
for (i = 1; i < valuesArray.Length; i++)
{
try
{
command.Parameters.AddWithValue("#VAL" + i, (valuesArray[i]));
}
catch (Exception ex)
{
}
}
// Just split the array into a string to visually check
// differences in the records
String arraySplit = ConvertStringArrayToString(valuesArray);
// The query gets executed here. The command looks something
// like:
// INSERT INTO LIBNAME.FILENAME VALUES(#VAL!, #VAL2, #VAL3, #VAL4)
// There are actually 320 fields in the file I'm having a problem with,
// so it's possible I'm overlooking something. I have narrowed it down to
// field # 316 when the exception occurs, but in both cases
// field 316 is blanks (when it works and when it doesn't).
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
// Here I get the exception out of bounds error in MSCORLIB.DLL.
// Some records are added fine, while others cause this exception.
// I cannot visibly tell any major differences, nor do I see any
// errors in the AS400 job log or anything in C# that would lead me
// down a certain path.
String error = ex.Message;
}
}
For what it's worth, I found this happening one a smaller file in the system and was able to figure out what going on, after painstaking research into the code and the net. Basically, the file file has numeric fields on the i-series. Somehow, the records were written to the file on the original system with null values in the numeric fields instead of numeric values. When storing the original records, I had to do this calculation:
String fieldType = rs.Fields[i].Type.ToString();
object objValue = rs.Fields[i].Value;
if (fieldType == "adNumeric" && objValue is DBNull)
{
fieldValues[i] += "0";
}
else
{
fieldValues[i] += rs.Fields[i].Value;
}
After this, if null values were found in one of the numeric fields, it just put "0" in it's place so that when writing to the new machine, it would put a valid numeric character in there and continue on writing the rest of the values. Thanks for all the advice and moral support. :)

Can Anyone help me retrieve data from parse using unity please?

I have managed to store data, but I can't retrieve it and i would be so grateful if someone could just help me get at least 1 example working.
First I am storing data when the user signs up:
public void SetupNewParseMember(ParseUser user)
{
ParseObject gameScore = new ParseObject("GameScore");
gameScore["cash"] = 500;
gameScore["playerName"] = user.Username;
gameScore["HighestCash"] = 500;
gameScore["GamesPlayed"] = 0;
Task saveTask = gameScore.SaveAsync();
}
This works fine, I can see the data in parse and all seems ok..
The problem is when i try to retrieve the objects.
public void SetupMainScreen(ParseUser user)
{
var query = ParseObject.GetQuery("GameScore").WhereEqualTo("playerName", user.Username);
query.FindAsync().ContinueWith(t =>
{
IEnumerable<ParseObject> results = t.Result;
List<ParseObject> resultsList = results.ToList();
DealWithResults(resultsList, user);
});
}
public void DealWithResults(List<ParseObject> resultsList, ParseUser me)
{
userGamesPlayed = resultsList[1].Get<int>("GamesPlayed");
userHighestCash = resultsList[2].Get<int>("HighestCash");
userCash = resultsList[3].Get<int>("Cash");
WelcomeText.text = "Welcome, " + me.Username + "\n" +
"Cash: $" + userCash + "\n" +
"Highest Cash: $" + userHighestCash + "\n" +
"Games Played: " + userGamesPlayed;
}
First I tried just making changes to the unity ui from inside the Query but that did not work, So i made an outside function and passed the results to it that way, and that still does not work?
I tried to debug what i was getting in the list with this:
foreach (var res in resultsList)
{
Debug.Log("Class Name = " + res.ClassName + "| Keys are: " + res.Keys);
}
But all it returned was:
Class Name = GameScore| Keys are: System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]
Can anyone offer any insights?
EDIT2:
ok so first i found results list and its contents
http://i.imgur.com/IKcBbey.png
Then if i open it, it seems to be null ref?
http://i.imgur.com/VmSpi9c.png
But if i go digging, i found the info i need all the way down here
http://i.imgur.com/1Wwu5uc.png
Now just need to work out how to get it?
As there is only one set of data it is always accessible through resultsList[0]. What you want is:
double cash = (double)resultsList[0]["cash"];
string playerName = (string)resultsList[0]["playerName"];
double highestCash = (double)resultsList[0]["HighestCash"];
int gamesPlayed = (int)resultsList[0]["GamesPlayed"];
Though you probably want to check that resultsList is not null and contains one element before you try to dereference it.
Also as your ParseObject appears to be a Dictionary you might find this MSDN page useful.
Ended up solving it.. Much different to the examples...
I had to make a coroutine that called a function on callback to access the variables outside of the query.
I called it with
StartCoroutine(SetupMainScreen(me, DealWithResults));
then called this.
public IEnumerator SetupMainScreen(ParseUser user, Action<GameScore> callback)
{
var query = ParseObject.GetQuery("GameScore").WhereEqualTo("playerName", user.Username).FirstOrDefaultAsync();
while (!query.IsCompleted)
{
yield return null;
}
if (query.IsFaulted || query.IsCanceled)
{
Debug.Log("Getting of GameScores faulted or cancelled...");
}
else
{
var obj = query.Result;
if (obj != null)
callback(new GameScore(obj.Get<int>("cash"),obj.Get<string>("playerName"),obj.Get<int>("HighestCash"),obj.Get<int>("GamesPlayed")));
}
}
public void DealWithResults(GameScore gs)
{
WelcomeText.text = "Welcome, " + gs.Username + "\n" +
"Cash: $" + gs.Cash + "\n" +
"Highest Cash: $" + gs.HighestCash + "\n" +
"Games Played: " + gs.GamesPlayed;
}
And i just made a class to hold the objects.. Hopefully this helps someone else.

Gem Box Spreadsheet msi error

I have to do a Excel Manager with C# and i choose to use Gem Box Spreadsheet Free
var ef = new ExcelFile();
ef = ExcelFile.Load(File_Lettura);
ExcelWorksheet ws = ef.Worksheets.ActiveWorksheet;
int riga = 13;
string s = (ws.Cells["B6"]).ToString();
string[] r = s.Split('-');
int c = 0;
while (ws.Cells["B"+riga.ToString()].Value != null)
{
if (ws.Cells["F"+riga.ToString()].Value.ToString() != "")
{
// add row
dgwFile.Rows.Add();
dgwFile.Rows[c].Cells[0].Value = r[0] + "-" + r[1] + "-" + ws.Cells["B"+riga.ToString()].Value.ToString();
dgwFile.Rows[c].Cells[1].Value = ws.Cells["D" + riga.ToString()].Value.ToString() + ws.Cells["G" + riga.ToString()].Value.ToString() + ws.Cells["H" + riga.ToString()].Value.ToString() + ws.Cells["I" + riga.ToString()].Value.ToString();
dgwFile.Rows[c].Cells[2].Value = ws.Cells["F" + riga.ToString()].Value.ToString();
dgwFile.Rows[c].Cells[3].Value = "0";
c++;
}
riga++;
}
VS give me a problem at the first "IF" with error :
An unhandled exception of type 'System.NullReferenceException'
occurred.
I think the wrong rows are the first 3
thanks in advance Smile | :)
i've also tried like it
ExcelFile ef = ExcelFile.Load(File_Lettura);
ExcelWorksheet ws = ef.Worksheets.ActiveWorksheet;
I don't believe the first 3 lines are the problem, however in order to be 100% sure you would need to specify exactly where the exception is thrown.
Nevertheless I presume one of the ExcelCell's that you are targeting is null.
So try this:
while (ws.Cells["B"+riga.ToString()] != null &&
ws.Cells["B"+riga.ToString()].Value != null)
{
if (ws.Cells["F"+riga.ToString()] != null &&
ws.Cells["F"+riga.ToString()].Value != null)
{

Categories

Resources