Mixed managed C++ method does not always return the same result to the calling C# code - c#

A C++ method returns the correct value when I use a conditional breakpoint, but an incorrect value without a breakpoint.
C# method which calls C++:
bool SetProperty(Element element, Node referencePoint, List<Materializer> materializers, List<ulong> properties)
{
// Loop over STLs
for (int i = 0; i < materializers.Count; i++)
{
Materializer materializer = materializers[i];
if (materializer.IsPointInside(referencePoint.X, referencePoint.Y, referencePoint.Z, pentalTreeDatasets[i].top))
{
element.PropertyId = properties[i];
return true;
};
}
return false;
}
C++ methods in the header file:
int CountIntersects(double x, double y, double z, PentalTreeNode ^root)
{
Math3d::M3d rayPoints[2], intersectionPoint;
rayPoints[0].set(x,y,z);
rayPoints[1].set(x,y,1.0e6);
if(!root)
return 0;
else
{
int special = CountIntersects(x,y,z,root->special);
if (x <= root->xMax && x >= root->xMin && y <= root->yMax && y >= root->yMin)
{
if( _stlMesh->IsRayIntersectsPoly(root->index, rayPoints, intersectionPoint))
{
return (1 + special);
}
else
return special;
}
else
{
if (y>root->yMax)
{
return (CountIntersects(x,y,z,root->top)+special);
}
else if(y<root->yMin)
{
return (CountIntersects(x,y,z,root->bottom)+special);
}
else if(x<root->xMin)
{
return (CountIntersects(x,y,z,root->left)+special);
}
else if(x>root->xMax)
{
return (CountIntersects(x,y,z,root->right)+special);
}
else
return special;
}
}
}
bool IsPointInside(double x, double y, double z, PentalTreeNode ^root)
{
int intersectionCount = 0;
Math3d::M3d rayPoints[2], intersectionPoint;
rayPoints[0].set(x,y,z);
rayPoints[1].set(x,y,1.0e6);
if(_box->IsContainingPoint(x,y,z))
{
intersectionCount=CountIntersects(x,y,z,root);
return (intersectionCount%2!=0);
}
}
C++ methods in other header files:
bool IsRayIntersectsPoly(int nPolygonIndex, Math3d::M3d RayPoints[2], CVector3D& IntersectionPoint)
{
CMeshPolygonBase& Poly = m_PolygonArray[nPolygonIndex];
CArrayResultI Result;
int* pPolygonPoints = GetPolygonPoints(Poly, Result);
Math3d::MPlane TrianglePlane;
double Atmp[3], A;
CVector3D* pPoints[3];
pPoints[0] = &m_PointArray[*pPolygonPoints].m_Position;
for(int i = 1; i < Result.GetSize() - 1; i++)
{
pPoints[1] = &m_PointArray[*(pPolygonPoints+i)].m_Position;
pPoints[2] = &m_PointArray[*(pPolygonPoints+i+1)].m_Position;
TrianglePlane.Init(*pPoints[0], *pPoints[1], *pPoints[2]);
TrianglePlane.IntersectLine(RayPoints[0], RayPoints[1], IntersectionPoint);
A = GetTriangleArea(*pPoints[0], *pPoints[1], *pPoints[2]);
for(int j = 0; j < 3; j++)
{
Atmp[j] = GetTriangleArea(*pPoints[j], *pPoints[(j+1)%3], IntersectionPoint);
}
if( fabs(A - Atmp[0] - Atmp[1] - Atmp[2]) < 1.0e-5 ) return true;
}
return false;
};
double GetTriangleArea(CVector3D& T1, CVector3D& T2, CVector3D& T3)
{
double a, b, c, s;
a = (T1 - T2).length();
b = (T2 - T3).length();
c = (T3 - T1).length();
s = 0.5 * (a + b + c);
return( sqrt(s * (s - a)* (s - b)* (s - c)) );
}
When I start the program which calls SetProperty() within the for-loop, the results for some iterator values are wrong. When I set conditional breakpoints for critical iterator values in the for-loop and step over it, then the result is OK for that item. What may be the problem?
This is method in which I post breakpoint. For example, for critical element.Id==2393.
private void StartButton_Click(object sender, EventArgs e)
{
DateTime startTime = DateTime.Now;
List<Materializer> materializers = new List<Materializer>();
List<ulong> properties = new List<ulong>();
// Load STLs
for (int i = 0; (int)i < (this.dataGridView.RowCount - 1); i++)
{
if (dataGridView.Rows[i].Cells[1].Value != null && (string)dataGridView.Rows[i].Cells[1].Value != "")
{
Materializer materializer = new Materializer();
materializer.LoadSTLMesh(dataGridView.Rows[i].Cells[0].Value.ToString());
materializers.Add(materializer);
properties.Add((ulong)dataGridView.Rows[i].Cells[1].Tag);
}
}
CreatePentalTrees(materializers);
int processedElementCount = 0;
int changedElementCount = 0;
// Loop over elements
foreach (Element element in model.ElementsList.Values)
if ((element.Topology == 7 || element.Topology == 8) && !lockedProperties.ContainsKey(element.PropertyId)) // 3D elements only
{
Node center = this.CenterPoint(element, model.NodesList);
if (element.Id == 2393)
{
//if breakpoints thats ok, else not ok
Console.WriteLine(element.Id);
Console.WriteLine(element.PropertyId);
}
if (SetProperty(element, center, materializers, properties)) // Check for center point
{
//changedElements.Add(element.Id, true);
changedElementCount++;
}
else
{
// Check for all nodes if center point does not belong to any STL
int[] nodeOrder;
switch (element.Topology)
{
case 7:
nodeOrder = wedgeNodeOrder;
break;
case 8:
nodeOrder = brickNodeOrder;
break;
default:
throw new Exception("Unknown topology " + element.Topology.ToString());
}
for (int i = 0; i < nodeOrder.Length; i++)
{
Node node = model.NodesList[element.NodeIds[nodeOrder[i]]];
if (SetProperty(element, node, materializers, properties))
{
//changedElements.Add(element.Id, true);
changedElementCount++;
break;
}
}
}
if (++processedElementCount % 100 == 0)
{
labelTime.Text = "Changed/processed elements: " + changedElementCount.ToString() + "/" + processedElementCount.ToString();
labelTime.Refresh();
Application.DoEvents();
}
}
DateTime endTime = DateTime.Now;
labelTime.Text = "Total time: " + (endTime - startTime).TotalSeconds.ToString() + " s";
MessageBox.Show("Completed.");
SaveFileDialog saveFileDlg = new SaveFileDialog();
saveFileDlg.Title = "Save FEMAP neutral file";
saveFileDlg.Filter = "(*.neu)|*.neu";
if (saveFileDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
FemapNeutral.ExportNeu(saveFileDlg.FileName, model);
}
}

You seem to be calling a lot of methods you haven't listed, and/or the wall of code made me get lost. Adding that code won't help: reducing your problem to a simpler one that demonstrates the problem might.
However, the most likely cause of your problem, if you have unmanaged code reading managed data, is that you failed to marshal or pin the data prior to using the managed code.
Unpinned data can be moved around by the garbage collector in unexpected ways.

Related

Function sometimes randomly calling

i am making a board/card game Carcassonne. I have prefab cards and every card has four variables s, v, j, z (world compass in my language). I have a function that finds a side with a value "R" (stands for road) and finds card that is next to it (thanks to the location of cards). For example if s == "R" it calls the second function, that finds the tile on top of the card and sets variable lastSide to "j" so that when the first function is called again it doesnt go back. Road is always only on two side so thats why there is "nicovani". I hope this is not hard to understand, the problem is sometimes when i lay a card the function is called once from the card layed and once from the card layed before, then once again from the card just layed. I have no idea why, but its the last thing i need to solve to complete this. If've read this far i am already thankful. Here's the important code:
public string s;
public string v;
public string j;
public string z;
private int cross = 0;
public bool Layed;
public bool IsRoadEnding;
private string lastSide;
private int nicovani = 0;
private bool isScored = false;
public void OnMouseDown()
{
if(Layed == false)
{
if(r == 1)
{
r = 2;
IsHere = false;
StartCoroutine(Follow());
}
else
{
if(IsHere == true)
{
TheWholeThing();
}
else
{
r = 1;
transform.position = spawner.transform.position;
}
}
}
}
void TheWholeThing()
{
setPos = new Vector2 (Mathf.RoundToInt(transform.position.x), Mathf.RoundToInt(transform.position.y));
r = 1;
transform.position = setPos;
FindTile();
CheckTile(asociatedTile);
if(r == 1)
{
drawer.SpawnCard();
SetTile(asociatedTile);
gmg.GenerateGrid(transform.position.x, transform.position.y+1, "j" , s);
gmg.GenerateGrid(transform.position.x, transform.position.y-1, "s", j);
gmg.GenerateGrid(transform.position.x +1, transform.position.y, "z", v);
gmg.GenerateGrid(transform.position.x -1, transform.position.y, "v", z);
Layed = true;
startingTile = gameObject.transform;
if(nicovani < 2)
{
FindScoringRoad(transform.position.x, transform.position.y, "", s, v, j, z);
return;
}
}
else
{
return;
}
IsHere = false;
}
void FindScoringRoad(float x, float y, string side, string s, string v, string j, string z)
{
if(isScored == false)
{
lastSide = side;
if(lastSide != "s")
{
if(s == "R")
{
cross = 0;
Debug.Log("s");
FindNextCard("j", x, y + 1);
}
}
if(lastSide != "v")
{
if(v == "R")
{
cross = 0;
Debug.Log("v");
FindNextCard("z", x + 1, y);
}
}
if(lastSide != "j")
{
if(j == "R")
{
if(nicovani == 2)
{
nicovani = 0;
return;
}
else
{
cross = 0;
Debug.Log("j");
FindNextCard("s", x , y - 1);
}
}
}
if(lastSide != "z")
{
if(z == "R")
{
if(nicovani == 2)
{
nicovani = 0;
return;
}
else
{
cross = 0;
Debug.Log("z");
Debug.Log(x + " " + y);
FindNextCard("v", x - 1, y);
}
}
}
cross = 0;
return;
}
}
void FindNextCard(string side, float x, float y)
{
if(x == startingTile.position.x & y == startingTile.position.y)
{
Debug.Log("Road Closed");
isScored = true;
return;
}
foreach(GameObject card in drawer.spawnedCards)
{
if(card.transform.position.x == x & card.transform.position.y == y)
{
var cardS = card.GetComponent<Card>();
if(cross < 1)
{
FindScoringRoad(card.transform.position.x, card.transform.position.y, side, cardS.s, cardS.v, cardS.j, cardS.z);
cross++;
}
return;
}
}
Debug.Log("Ends here");
cross = 0;
nicovani++;
return;
}
The code describes what i tried so far. Thanks for any help, it means a lot to me!
the problem is sometimes when i lay a card the function is called once
from the card layed and once from the card layed before, then once
again from the card just layed.
So the problem is FindScordingRoad is called three times and you only expect twice? I think this is your problem.
void FindScoringRoad(float x, float y, string side, string s, string v, string j, string z)
{
// we enter this function so this method has been called once
// assuming s and v equals "R" but not j and z
if (isScored == false)
{
lastSide = side;
// lastSide == "" so we enter if below.
if (lastSide != "s")
{
// as per assumption this is true and we enter if
if (s == "R")
{
...
// This will call FindScoringRoad a second time
FindNextCard("j", x, y + 1);
}
}
// lastSide == "" still so we enter if below.
if (lastSide != "v")
{
// as per assumption this is true and we enter if
if (v == "R")
{
...
// This will call FindScoringRoad a third time
FindNextCard("z", x + 1, y);
}
}
...
}
}
You can fix this by setting cross=0 and returning right after FindNextCard
if (lastSide != "s")
{
if (s == "R")
{
cross = 0;
Debug.Log("s");
FindNextCard("j", x, y + 1);
cross = 0;
return;
}
}

Check the difference

Hi I'm building a program that will look at files at have been placed into SVN and show what files have been changed in each commit.
As i'm only wanting to show the file path. if the path is that same I only want to show the difference.
example:
First file path is:
/GEM4/trunk/src/Tools/TaxMarkerUpdateTool/Tax Marker Ripper v1/DataModifier.cs
Second file path is:
/GEM4/trunk/src/Tools/TaxMarkerUpdateTool/Tax Marker Ripper v1/Tax Marker Ripper v1.csproj
What I'd like to do is substring at the point of difference.
So in this case:
/GEM4/trunk/src/Tools/TaxMarkerUpdateTool/Tax Marker Ripper v1/
would be substringed
I hope this helps:
public string GetString(string Path1, string Path2)
{
//Split and Put everything between / in the arrays
string[] Arr_String1 = Path1.Split('/');
string[] Arr_String2 = Path2.Split('/');
string Result = "";
for (int i = 0; i <= Arr_String1.Length; i++)
{
if (Arr_String1[i] == Arr_String2[i])
{
//Puts the Content that is the same in an Result string with /
Result += Arr_String1[i] + '/';
}
else
break;
}
// If Path is identical he would add a / which we dont want
if (Result.Contains('.'))
{
Result = Result.TrimEnd('/');
}
return Result;
}
You can do this pretty easily with a loop. Basically:
public String FindCommonStart(string a, string b)
{
int length = Math.Min(a.Length, b.Length);
var common = String.Empty;
for (int i = 0; i < length; i++)
{
if (a[i] == b[i])
{
common += a[i];
}
else
{
break;
}
}
return common;
}
Something like this:
public string GetCommonStart(string a, string b)
{
if ((a == null) || (b == null))
throw new ArgumentNullException();
int Delim = 0;
int I = 0;
while ((I < a.Length) && (I < b.Length) && (a[I] == b[I]))
{
if (a[I++] == Path.AltDirectorySeparatorChar) // or Path.DirectorySeparatorChar
Delim = I;
}
return a.Substring(0, Delim);
}
Keep in mind, that this code is case-sensitive (and paths in windows in general are not).

C# stack push call issue

I'm having an issue where my C# stack will accept a pushed value but then overwrite the previously existing elements in the stack with the new value as well.
Here's a chunk of the constructor for reference:
public class MazNav //handles processing and navigation
{
private Maze m;
private static Stack<int[]> path;
private int[] currCell;
private int visCell;
private Random rng;
//constructor
public MazNav(Maze mz)
{
m = mz; //assigns this object to a maze
path = new Stack<int[]>(); //initialize the stack
currCell = m.getStart(); //starts the pathfinding at start cell
visCell = 1; //initializes the visited cells count
path.Push(currCell); //adds this cell to the stack
rng = new Random(); //initializes the randomizer
The problem occurs in the if block towards the end of this method (sorry it's still ugly; I'm in the middle of debugging and will clean this up once I have something that works :) ):
public void buildMaze()
{
//variables to represent the current cell
int[] currPos; //coordinates
int nextDir = 0; //direction towards next cell
//variables to represent the next cell
int[] nextPos; //coordinates
int backDir = 0; //holds direction towards previous cell
bool deadEnd = false; //flags true when a backtrack is required
bool outOfBounds = false; //flags true when a move would leave the array
while (visCell < m.getTotCells()) //while the number of visited cells is less than the total cells
{
if (path.Count > 0) // if there is something in the stack
{
currPos = path.Peek(); //check the current coordinates
nextPos = currPos; //movement will happen one cell at a time; setting next cell coordinates the same as current allows easy adjustment
nextDir = findNextUnv(currPos); //find the direction of the next cell to check
deadEnd = false;
outOfBounds = false;
switch (nextDir)
{
case 0: //North
if (nextPos[0] - 1 >= 0)
{
nextPos[0]--;
backDir = 2;
}
else
{
outOfBounds = true;
}
break;
case 1: //East
if (nextPos[1] + 1 < m.getCols())
{
nextPos[1]++;
backDir = 3;
}
else
{
outOfBounds = true;
}
break;
case 2: //South
if(nextPos[0] + 1 < m.getRows())
{
nextPos[0]++;
backDir = 0;
}
else
{
outOfBounds = true;
}
break;
case 3: //West
if (nextPos[1] - 1 >= 0)
{
nextPos[1]--;
backDir = 1;
}
else
{
outOfBounds = true;
}
break;
case 99: //dead end
try
{
deadEnd = true;
path.Pop();
currPos = path.Peek();
int diff;
if (currPos[0] == nextPos[0])
{
diff = currPos[1] - nextPos[1];
if (diff == -1)
{
backDir = 3;
}
else if (diff == 1)
{
backDir = 1;
}
}
else if (currPos[1] == nextPos[1])
{
diff = currPos[0] - nextPos[0];
if (diff == -1)
{
backDir = 2;
}
else if (diff == 1)
{
backDir = 0;
}
}
m.getCell(nextPos[0], nextPos[1]).setBck(backDir, true);
}
catch (Exception) { }
break;
}
if (!deadEnd && !outOfBounds)
{
m.getCell(currPos[0], currPos[1]).setWal(nextDir, false);
m.getCell(nextPos[0], nextPos[1]).setWal(backDir, false);
path.Push(nextPos);
visCell++;
}
}
}
}e
The push call is only executed once but when I watch it on the debugger, after that line runs, the count increases by 1 but every element in the stack is now identical. Has anyone come across this behavior before? Where am I going wrong?
There are a lot of bugs in your code because of the way you are treating nextPos and curPos.
In particular, this line:
nextPos = currPos;
Here you are assigning nextPos to be the same array as curPos, so if you modify one, the other one will be modified along with it. And if you push one on to the stack and then modify either one, the array on the stack will be modified along with it.
The solution I would suggest is to use an immutable data type for your positions, rather than an array (which isn't particularly well suited for coordinates anyway):
internal struct Point
{
internal int X { get; private set; }
internal int Y { get; private set; }
internal Point(int x, int y)
{
X = x;
Y = y;
}
internal Point NewX(int deltaX)
{
return new Point(X + deltaX, Y);
}
internal Point NewY(int deltaY)
{
return new Point(X, Y + deltaY);
}
}
This way, when you need to transition to a new point, you can create a new one instead of modifying an existing one:
if (nextPos.X - 1 >= 0)
{
nextPos = nextPos.NewX(-1);
backDir = 2;
}
This should help you to keep a handle on your values and keep them from overwriting each other every which way.

How to set a dynamic object to the correct type

This is my function to move the scrollbars (I have horizontal one and a vertical one)
private void moveTheScroll(object sbar, int scrollDiff)
{
if (sbar is HScrollBar)
{
int newScrollvalue = ((HScrollBar)sbar).Value + scrollDiff;
if (((HScrollBar)sbar).Minimum < newScrollvalue &&
newScrollvalue < ((HScrollBar)sbar).Maximum)
((HScrollBar)sbar).Value = newScrollvalue;
}
else if (sbar is VScrollBar)
{
int newScrollvalue = ((VScrollBar)sbar).Value + scrollDiff;
if (((VScrollBar)sbar).Minimum < newScrollvalue &&
newScrollvalue < ((VScrollBar)sbar).Maximum)
((VScrollBar)sbar).Value = scrollDiff;
}
}
Is there a way to to not typecast the object every single time I want to use it and make an alias instead?
Something similar to this (this doesnt work because v cannot be initialized)
var v;
if(sbar is HScrollBar)
v = (HScrollBar)sbar;
else if(sbar is VScrollBar)
v = (VScrollBar)sbar;
v.Value = newValue;
If both types are inheriting from Scrollbar class then you just need to perform one cast:
private void moveTheScroll(object sbar, int scrollDiff)
{
var scrollBar = sbar as ScrollBar;
if(scrollBar != null)
{
int newScrollvalue = scrollBar.Value + scrollDiff;
// do other works with scrollBar...
}
}

How to disable formula error check in Excel programmatically

I try to set formula to Excel cell in C# in several steps, however during the process I set it, it seems Excel throws exception due to invalid formula. I wonder how can I turn off the formula error check in C#. thanks
Edit
The formula is too long, longer than 255 characters.
So I can't set formula in one step.
Have to set a short formula, then replace see http://netoffice.codeplex.com/discussions/402947
see code below
but I get an error in rng.Formula = onePart;
where Constants.CUT_LENGTH = 253, Constants.MAX_FORMULA_LENGTH = 255, Separator = "||"
I try to set EvaluateToError to false, still get an error
XLApp.ErrorCheckingOptions.InconsistentFormula = false;
XLApp.ErrorCheckingOptions.EvaluateToError = false;
SetFormula(rangeFunction, formula);
public static void SetFormula(Range rng, string origFormula)
{
int i = 0;
foreach (var onePart in CutStringIntoSubstrings(origFormula))
{
if(i==0)
{
rng.Formula = onePart;
i++;
}
else
{
rng.Replace(Constants.Separator, onePart);
}
}
}
public static IEnumerable<string> CutStringIntoSubstrings(string origFormula)
{
if (origFormula == null) yield return string.Empty;
if (string.IsNullOrEmpty(origFormula)) yield return string.Empty;
if (origFormula.Length <= Constants.MAX_FORMULA_LENGTH) yield return origFormula;
int startIdx = 0;
int endIdx = startIdx + Constants.CUT_LENGTH;
while(endIdx < origFormula.Length)
{
var substr = origFormula.Substring(startIdx, Constants.CUT_LENGTH);
if(startIdx + Constants.CUT_LENGTH < origFormula.Length)
{
substr += Constants.Separator;
}
yield return substr;
startIdx += Constants.CUT_LENGTH;
endIdx = startIdx + Constants.CUT_LENGTH;
}
if (startIdx < origFormula.Length) yield return origFormula.Substring(startIdx);
}
You can refer to this article
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.errorcheckingoptions_members.aspx
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.error.ignore(v=office.11).aspx
May b it might help :)

Categories

Resources