Closed IslandHydro closed 4 years ago
I just looked at the C++ code and I don't see anything that could explain this:
void CShapefileCategories::ApplyExpressionCore(long CategoryIndex)
{
if (!_shapefile)
return;
CComPtr<ITable> tbl = NULL;
_shapefile->get_Table(&tbl);
if ( !tbl ) return;
long numShapes;
_shapefile->get_NumShapes(&numShapes);
// vector of numShapes size with category index for each shape
std::vector<int> results;
results.resize(numShapes, -1);
bool uniqueValues = true;
for (unsigned int i = 0; i < _categories.size(); i++) {
tkCategoryValue value;
_categories[i]->get_ValueType(&value);
if (value != cvSingleValue) {
uniqueValues = false;
break;
}
}
// ----------------------------------------------------------------
// we got unique values classification and want to process it fast
// ----------------------------------------------------------------
bool parsingIsNeeded = true;
if (_classificationField != -1 && uniqueValues)
{
parsingIsNeeded = false; // in case there are unique values only we don't need any parsing
std::map<CComVariant, long> myMap; // variant value as key and number of category as result
for (unsigned int i = 0; i < _categories.size(); i++)
{
if (i == CategoryIndex || CategoryIndex == -1 )
{
CComVariant val;
_categories[i]->get_MinValue(&val);
if (val.vt != VT_EMPTY)
{
CComVariant val2;
VariantCopy(&val2, &val);
myMap[val2] = i;
}
}
}
// applying categories to shapes
VARIANT val;
VariantInit(&val);
for (long i = 0; i < numShapes; i++)
{
tbl->get_CellValue(_classificationField, i, &val);
if (myMap.find(val) != myMap.end())
{
results[i] = myMap[val]; // writing the index of category
}
}
VariantClear(&val);
}
// -------------------------------------------------------------
// Analyzing expressions
// -------------------------------------------------------------
if (parsingIsNeeded)
{
// building list of expressions
std::vector<CString> expressions;
for (unsigned int i = 0; i < _categories.size(); i++)
{
if (i == CategoryIndex || CategoryIndex == -1 )
{
CComBSTR expr;
_categories[i]->get_Expression(&expr);
USES_CONVERSION;
CString str = OLE2CA(expr);
expressions.push_back(str);
}
else
{
// we don't need this categories, so dummy strings for them
CString str = "";
expressions.push_back(str);
}
}
// adding category indices for shapes in the results vector
TableHelper::Cast(tbl)->AnalyzeExpressions(expressions, results);
}
// saving results
if (CategoryIndex == -1 )
{
for (unsigned long i = 0; i < results.size(); i++)
{
_shapefile->put_ShapeCategory(i, results[i]);
}
}
else
{
for (unsigned long i = 0; i < results.size(); i++)
{
if (results[i] == CategoryIndex)
_shapefile->put_ShapeCategory(i, CategoryIndex);
}
}
}
I don't have MapWinGIS v4.8 anymore, I'm using v4.9-dev and I'm all up-to-date with Win10.
Perhaps you could try to reinstall MapWinGIS?
You could try to create a small new application in VB.NET (or C#) with 1 form with MapWinGIS and open a shapefile and to the Categories.ApplyExpressions
.
When it is not crashing it suggests it is something with MS-Access, if it is still crashing you could share the code and I can have a look.
You could also add a try-catch around the method and log the exception. That might help as well.
Thanks for the reply Paul. I did re-install MapWinGIS to no avail. I don't have MS Studio (Vb.net / C#) so I can't try that approach. VBA doesn't include try-catch but does have on-error routines. The application shuts down without triggering any error trapping routines. I'm at a bit of a loss on what to do, so any thoughts would be appreciated.
Can you save your data as Shapefile and share it with me? And show the code that makes the categories? I can try to make a small program that does the same. But from tomorrow I'll be offline for a week, so I can't work on it until next week.
Thank you so much for the offer Paul, I really appreciate it. I had a breakthrough just now, which solved the problem but makes me wonder if I am doing something fundamentally wrong in how I deal with this situation. First the fix: I noticed that some other layers that I am using (although less commonly) also use the offending "Layer.Categories.ApplyExpressions" that was crashing the application. Since the code utilized by those layers was identical, just pointing at a different layer, I began to suspect something was wrong with my layer. So I created a new, empty layer and re-ran the code and all is fine!
This apparent corruption of the layer leads me to wonder if I am doing something incorrectly. The layer in question is a layer that is continuously emptied and re-filled based on search criteria (spatial and other). The unloading of the layer is accomplished via something like this:
SelWellsLayer.StartEditingShapes (True)
While SelWellsLayer.NumShapes > 0
SelWellsLayer.EditDeleteShape (0)
Wend
SelWellsLayer.Categories.Clear
Reloading is accomplished via:
While Not Recs.EOF
Call AddPointToShapefile(SelWellsLayer, Recs("WellKey"), Recs("WellEast"), Recs("WellNorth"), FnWellIcon(Recs("WellKey")))
Recs.MoveNext
Wend
SelWellsLayer.StopEditingShapes
SelWellsLayer.Save
I then go on to apply expressions to the layer with the following:
Set Icons = CurrentDb.OpenRecordset(SearchSQL)
While Not Icons.EOF
Set SfImage = New MapWinGIS.Image
BmpName = Icons("WellIconCode") & ".bmp"
If SfImage.Open(FnDbFolderPath & "MapData\IconsNew\" & BmpName, USE_FILE_EXTENSION, True) = True Then
Set ShapeCat = SelWellsLayer.Categories.Add(Left(BmpName, InStr(BmpName, ".") - 1))
ShapeCat.Expression = "[GE_Code] =" & Chr(34) & Left(BmpName, InStr(BmpName, ".") - 1) & Chr(34)
ShapeCat.DrawingOptions.PointType = ptSymbolPicture
ShapeCat.DrawingOptions.PictureScaleX = WellIconSize
ShapeCat.DrawingOptions.PictureScaleY = WellIconSize
ShapeCat.DrawingOptions.Picture = SfImage
End If
Icons.MoveNext
Wend
hndSelWells = mapCtl.AddLayer(SelWellsLayer, True)
SelWellsLayer.Categories.ApplyExpressions
This has been working for a number of years, so perhaps it really was just some sort of corruption of the .shp file. But if there is a better way to 're-use' a shapefile for selected data I'd like to know. Thanks again, I appreciate your willingness to help, and your (and everyone elses) efforts in creating this product, it is truly very useful.
Do you need the layer/shapefile to be disk-based? Creating an in-memory shapefile might speed up things if you change the shapes a lot.
I would also recommend removing shapes in reverse order. Something like:
var numShapes = SelWellsLayer.NumShapes;
for (var i=numShapes; i>0;i--) {
SelWellsLayer.EditDeleteShape(i);
}
If this is still an issue with the latest release (https://github.com/MapWindow/MapWindow5/releases) could you create a new issue? For now, I close this old issue.
As of yesterday, MapWinGIS started crashing on one pc (my main). I had not changed anything on the pc (although a Windows 10 update happened the same morning....). The exact same code still works on other pc's. The application is a MsAccess database, several forms utilizing MapWinGIS. This code has been working fine for the last 4 or 5 years. I'm running MapWinGIS version 4.8. The line of code that crashes is:
SelWellsLayer.Categories.ApplyExpressions
The .ApplyExpressions function causes crashes in all forms that have that code. When that line of code is run, the database just disappears (closes) without any messages. I'm at a bit of a loss on how to diagnose this. I tried uninstalling and re-installing MapWinGIS, no change. Thoughts?
Thanks, Doug