TheSwamp
Code Red => .NET => Topic started by: Andrey Bushman on July 27, 2010, 01:37:06 PM
-
Hi All!
I get error in row of 15 (message's copy in row's comment).
AutoCAD 2009 x64 SP3. If use AutoCAD 2009 x86 - then look comment of 14 row's.
1: //Test code
2: Document dwg = acadApp.DocumentManager.MdiActiveDocument;
3: Database db = dwg.Database;
4: TableStyle ts = new TableStyle();
5: TableStyle ts1;
6: ObjectId id = ts.PostTableStyleToDatabase(dwg.Database, tableStyleName);
7: using (Transaction t = dwg.TransactionManager.StartTransaction())
8: {
9: ts1 = (TableStyle)t.GetObject(id, OpenMode.ForRead);
10: }
11: AcadApplication app = (AcadApplication)acadApp.AcadApplication;
12: if (ts == ts1)[color=green]//additional check on searching of error[/color]
13: {
14: long i = (long)id.OldIdPtr;// [color=green]if AutoCAD x86, then write this: int i = (int)id.OldIdPtr;[/color]
15: object x = app.ActiveDocument.ObjectIdToObject(i);//[color=red]Error HRESULT E_FAIL has been returned from a call to a COM component.[/color]
16: IAcadTableStyle2 ts2 = (IAcadTableStyle2)x;
17: }
Where my mistake?
-
hmmm ...
Just from looking at the code, it appears as though ts is a new TableStyle and it appears as though you are putting it in the current document, but from the code it doesn't appear as though you are giving it a name ... tableStyleName isn't set in this code (although it may be set elsewhere).
Perhaps you need to verify whether or not i actually contains a value, and whether that value is valid.
-
hmmm ...
Just from looking at the code, it appears as though ts is a new TableStyle and it appears as though you are putting it in the current document, but from the code it doesn't appear as though you are giving it a name ... tableStyleName isn't set in this code (although it may be set elsewhere).
Perhaps you need to verify whether or not i actually contains a value, and whether that value is valid.
i actually contains a value.
-
Hi All!
I get error in row of 15 (message's copy in row's comment).
AutoCAD 2009 x64 SP3. If use AutoCAD 2009 x86 - then look comment of 14 row's.
1: //Test code
2: Document dwg = acadApp.DocumentManager.MdiActiveDocument;
3: Database db = dwg.Database;
4: TableStyle ts = new TableStyle();
5: TableStyle ts1;
6: ObjectId id = ts.PostTableStyleToDatabase(dwg.Database, tableStyleName);
7: using (Transaction t = dwg.TransactionManager.StartTransaction())
8: {
9: ts1 = (TableStyle)t.GetObject(id, OpenMode.ForRead);
10: }
11: AcadApplication app = (AcadApplication)acadApp.AcadApplication;
12: if (ts == ts1)[color=green]//additional check on searching of error[/color]
13: {
14: long i = (long)id.OldIdPtr;// [color=green]if AutoCAD x86, then write this: int i = (int)id.OldIdPtr;[/color]
15: object x = app.ActiveDocument.ObjectIdToObject(i);//[color=red]Error HRESULT E_FAIL has been returned from a call to a COM component.[/color]
16: IAcadTableStyle2 ts2 = (IAcadTableStyle2)x;
17: }
Where my mistake?
Where's your mistake? Apart from still using COM when I showed you in your other thread how to use PInvoke, it's your use of long's and trying to convert them to objectid's when you don't have to.
Ponder the following, which is an update to the code I previously provided in your other cellstyles thread:
using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
[assembly: CommandClass(typeof(CellStyles.MyCommands))]
namespace CellStyles
{
public class MyCommands
{
[CommandMethod("q1", CommandFlags.Modal)]
public void TestMethod()
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
DBDictionary tsd = (DBDictionary) tr.GetObject(db.TableStyleDictionaryId, OpenMode.ForRead);
foreach (DBDictionaryEntry item in tsd)
{
TableStyle ts = (TableStyle)tr.GetObject(item.Value, OpenMode.ForRead);
// CODE Added - Start
IAcadTableStyle comTableStyle = ts.AcadObject as IAcadTableStyle;
if (comTableStyle == null)
{
ed.WriteMessage("{0}Ooooops!", Environment.NewLine);
}
else
{
ed.WriteMessage("{0}COM TableStyle name: {1}", Environment.NewLine, comTableStyle.Name);
}
// this is for demonstration purposes and not necessarily required...
Marshal.FinalReleaseComObject(comTableStyle);
// CODE Added - End
ed.WriteMessage(string.Format("{0}Table style name: '{1}'", Environment.NewLine, ts.Name));
ed.WriteMessage(string.Format("{0}(TableStyle.CellStyles.IsReadOnly ='{1}')",
Environment.NewLine, ts.CellStyles.IsReadOnly));
//Print all cell style names of table style
PrintCellStylesInfo(ts);
string stName = "MyStyle";// name for my new cell style
ed.WriteMessage(string.Format("{0}Before modify: Cell Styles Count: {1}",
Environment.NewLine, ts.CellStyles.Count));
ts.UpgradeOpen();
AcDbTable.createCellStyle(ts.UnmanagedObject, stName);
ed.WriteMessage(string.Format("{0}After modify: Cell Styles Count: {1}{0}",
Environment.NewLine, ts.CellStyles.Count));
ts.SetCellClass(CellClass.Label, stName);
ed.WriteMessage(string.Format("{0}{1}{0}", "\nAfter modify:", new string('*', 30)));
//Print all cell style names of table style
PrintCellStylesInfo(ts);
}
tr.Commit();
}
}
private void PrintCellStylesInfo(TableStyle ts)
{
foreach (var cs in ts.CellStyles)
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
ed.WriteMessage(string.Format("{0}CellStyle Type: '{1}'; CellStyle.ToString: {2}",
Environment.NewLine, cs.GetType(), cs.ToString()));
}
}
}
public static class AcDbTable
{
// Acad::ErrorStatus createCellStyle(const ACHAR* pszCellStyle);
[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("acdb18.dll", CallingConvention = CallingConvention.ThisCall, CharSet = CharSet.Unicode,
EntryPoint = "?createCellStyle@AcDbTableStyle@@QEAA?AW4ErrorStatus@Acad@@PEB_W@Z")]
public static extern ErrorStatus createCellStyle(IntPtr tableStyle, string name);
}
}
Follow the Online AutoCAD .NET Developers Guide (http://docs.autodesk.com/ACD/2010/ENU/AutoCAD%20.NET%20Developer's%20Guide/index.html?url=WS73099cc142f48755-5c83e7b1120018de8c0-23ce.htm,topicNumber=d0e351) to add the required references. It will tell you to add files from 'Common Files' whereas as I added the same files from the ObjectARXSDK\inc-x64 directory.
Hope this helps.
-
Glenn there are probably 3 or 4 entry points reqd.
How do you derive EntryPoint = "?createCellStyle@AcDbTableStyle@@QEAA?AW4ErrorStatus@Acad@@PEB_W@Z")]
-
Bryco,
Trial and error, although you can see it has createcellstyle, acdbtablestyle acaderrorstatus in the mangled name.
I used dependencywalker for this as dumpbin is not available in express and there could be a very specific way to lookup the arx function call, but its the first time I've used it....<sheepish grin> hehe
-
Glenn there are probably 3 or 4 entry points reqd.
How do you derive EntryPoint = "?createCellStyle@AcDbTableStyle@@QEAA?AW4ErrorStatus@Acad@@PEB_W@Z")]
Bryco,
Trial and error, although you can see it has createcellstyle, acdbtablestyle acaderrorstatus in the mangled name.
I used dependencywalker for this as dumpbin is not available in express and there could be a very specific way to lookup the arx function call, but its the first time I've used it....<sheepish grin> hehe
I've just posted these. Perhaps someone will add the AC2009 dumps.
http://www.theswamp.org/index.php?topic=34278.msg395750#msg395750
-
I used dependencywalker for this as dumpbin is not available in express and there could be a very specific way to lookup the arx function call, but its the first time I've used it....<sheepish grin> hehe
dumpbin is available in the Express C++ Edition.
-
Ripper Rita, that helps
-
Ripper Rita, that helps
I added to Kerry's post a method to unmangle the names in the file dumpbin produces.
-
it's your use of long's and trying to convert them to objectid's when you don't have to.
I use long in my code for AutoCAD 2009 x64, because I get error when use int:
(http://habreffect.ru/files/972/004bb3ed5/28.07.png)
I use int in my code for AutoCAD 2009 x86, but I get it error again.
Ponder the following, which is an update to the code I previously provided in your other cellstyles thread:
Thank you for code, but I have not problem with iteration for existing table styles. I get my error after new table style add in drawing data base - when try get IAcadTableStyle for it.
Follow the Online AutoCAD .NET Developers Guide to add the required references. It will tell you to add files from 'Common Files' whereas as I added the same files from the ObjectARXSDK\inc-x64 directory.
But I use it references already (and I get it error).
-
IAcadTableStyle comTableStyle = ts.AcadObject as IAcadTableStyle;
I thought I was the only one to name COM variable prefixed with com.... :wink:
-
it's your use of long's and trying to convert them to objectid's when you don't have to.
I use long in my code for AutoCAD 2009 x64, because I get error when use int:
OldIdPtr returns an IntPtr, so try using ToIntXX :-)
ObjectId id = ObjectId.Null;
IntPtr i = id.OldIdPtr;
i.ToInt32();// 32
i.ToInt64();// 64
-
Interestingly, according to Microsoft, whenever you use managed code to make calls to COM objects, the interop object is supposed map the types required from managed to unmanaged and vice versa transparently. However, since int is available in both code structures, you don't need to do anything i.e. IntPtr probably isn't required.
Since C# doesn't (or isn't supposed to) return an HRESULT structure, the error isn't being generated from your code, and is instead being generated by the COM type library. So the value you are passing is obviously incorrect.
-
just a wild-assed thought ..
what does this produce when debugging
var i = id.OldIdPtr;
-
OldIdPtr returns an IntPtr, so try using ToIntXX :-)
I tried this methods use (ToInt32() for x86 and ToInt64() for x64) before it's topic created. But it not help me. (((
-
I see it crashes pretty hard, how are your c++ skills? :wink:
-
Thanks All!
My mistake: I forget use AddNewlyCreatedDBObject method of Transaction
It work:
Document dwg = acadApp.DocumentManager.MdiActiveDocument;
Database db = dwg.Database;
using (Transaction t = dwg.TransactionManager.StartTransaction())
{
TableStyle ts = new TableStyle();
ObjectId stId = ts.PostTableStyleToDatabase(db, "MyTableStyle");
t.AddNewlyCreatedDBObject(ts, true);
AcadApplication app = (AcadApplication)acadApp.AcadApplication;
int c = stId.OldIdPtr.ToInt32();//Good work!
////or
//int c = (int)stId.OldIdPtr;// It to good work!
object x = app.ActiveDocument.ObjectIdToObject(c);
IAcadTableStyle2 ts2 = (IAcadTableStyle2)x;
t.Commit();
}
And It work too:
Document dwg = acadApp.DocumentManager.MdiActiveDocument;
Database db = dwg.Database;
using (Transaction t = dwg.TransactionManager.StartTransaction())
{
TableStyle ts = new TableStyle();
DBDictionary tableStylesDict = (DBDictionary)t.GetObject(db.TableStyleDictionaryId, OpenMode.ForWrite);
ObjectId stId = tableStylesDict.SetAt("MyTableStyle", ts);
t.AddNewlyCreatedDBObject(ts, true);
AcadApplication app = (AcadApplication)acadApp.AcadApplication;
////int c = stId.OldIdPtr.ToInt32();//Good work!
////or
int c = (int)stId.OldIdPtr;// It to good work!
object x = app.ActiveDocument.ObjectIdToObject(c);
IAcadTableStyle2 ts2 = (IAcadTableStyle2)x;
t.Commit();
}
-
I see it crashes pretty hard, how are your c++ skills? :wink:
I do not know C++. I know C# only. :oops:
-
You're missing my point. If you have an ObjectId, for a TableStyle in this instance, just open it up as normal and cast it to 'TableStyle'.
So, let's say your variable for the opened TableStyle is ts; call ts.AcadObject as IAcadTableStyle; as I showed in my example. There is no need to use special incantations on ints/longs or whatever that shoehorn an ObjectId.
Every RCW for an AutoCAD object provides this method, which get's a COM interface pointer to the underlying ARX/C++/C# object.
-
IAcadTableStyle comTableStyle = ts.AcadObject as IAcadTableStyle;
I thought I was the only one to name COM variable prefixed with com.... :wink:
Not the only one, as it makes sense...great minds blah blah ;-)
-
Ripper Rita, that helps
I added to Kerry's post a method to unmangle the names in the file dumpbin produces.
Thanks Paul. I found out last night, that you can get the 'undecorated' name in one of DependencyWalker's windows as well...just right-click on the entry once you've found it.
-
Good Job Hwd 8-)
-
< .. >
Every RCW for an AutoCAD object provides this method, which get's a COM interface pointer to the underlying ARX/C++/C# object.
for those following :
RCW =>> Runtime Callable Wrapper
http://msdn.microsoft.com/en-us/library/8bwh56xe.aspx
-
Thanks All!
I forget use AddNewlyCreatedDBObject method of Transaction
Excellent news that it's working for you :)
-
You're missing my point. If you have an ObjectId, for a TableStyle in this instance, just open it up as normal and cast it to 'TableStyle'.
So, let's say your variable for the opened TableStyle is ts; call ts.AcadObject as IAcadTableStyle; as I showed in my example. There is no need to use special incantations on ints/longs or whatever that shoehorn an ObjectId.
Every RCW for an AutoCAD object provides this method, which get's a COM interface pointer to the underlying ARX/C++/C# object.
and
< .. >
Every RCW for an AutoCAD object provides this method, which get's a COM interface pointer to the underlying ARX/C++/C# object.
for those following :
RCW =>> Runtime Callable Wrapper
http://msdn.microsoft.com/en-us/library/8bwh56xe.aspx
Thank you!
-
Where's your mistake? Apart from still using COM when I showed you in your other thread how to use PInvoke...
Hi Glenn,
About the COM usage, is that just for this case in particular? or in other words for what the OP routine is doing?
BTW, I have some large amount of code lines, that I am taking out my COM calls, so far noticed a difference in the speed, when selecting an object get all the properties, and pass those to a form (ie. tree control)... I still need the use of com objects - was thinking to probably post some of my code, but it is very specific, don't know...
So any comment you might have about COM...
Thank you Sir! :)
-
Luis, if speed is an issue, perhaps you could issue asynchronous calls and continue working on other stuff until the thread completes the callback.
-
Luis, if speed is an issue, perhaps you could issue asynchronous calls and continue working on other stuff until the thread completes the callback.
Hi Keith,
No, there is no issue about speed, just been trying to implement more or better all in .NET vs COM calls usage.. in example something like this below:
With COM
SetXDictDat(ent, node);
SetXDataDat(ent, node);
if (ent is Autodesk.AutoCAD.Interop.Common.AcadBlockReference)//(ent.EntityName.CompareTo("AcDbBlockReference") == 0)
{
AcadBlockReference blk = ent as AcadBlockReference;
if (blk != null && blk.HasAttributes)
{
Object[] objAtt;
AcadAttributeReference Att;
childnode = new Node();
childnode.Text = "Attributes";
nodtag = new NodeTag();
nodtag.strPropertyName = "Attributes";
nodtag.strPropertyDesc = "Block attributes";
nodtag.bIsCustom = true;
nodtag.bIsArray = true;
childnode.Tag = nodtag;
node.Nodes.Add(childnode);
objAtt = (Object[])blk.GetAttributes();
for (i = 0; i < objAtt.Length; i++)
{
Att = objAtt[i] as AcadAttributeReference;
if (Att == null)
continue;
cnode = new Node();
childnode.Nodes.Add(cnode);
SetDatPropObj(objAtt[i], cnode);
//cnode.Text = "Attribute" + (i + 1).ToString();
cnode.Text = Att.TagString;
nodtag = new NodeTag();
nodtag.strPropertyName = "Attribute";
nodtag.strPropertyDesc = "Block attribute";
nodtag.bIsCustom = true;
nodtag.intIndex = i;
cnode.Tag = nodtag;
}
}
}
node.Nodes.Sort();
node.TreeControl.EndUpdate();
return ("");
No COM (notice that here the need of a transaction on the com above, was very straight...)
SetXDictDat(component, node);
SetXDataDat(component, node);
if (ent is BlockReference)
{
BlockReference blk = ent as BlockReference;
Autodesk.AutoCAD.DatabaseServices.AttributeCollection attributes = blk.AttributeCollection;
if (blk != null && attributes.Count != 0)
{
childnode = new Node();
childnode.Text = "Attributes";
nodtag = new NodeTag();
nodtag.strPropertyName = "Attributes";
nodtag.strPropertyDesc = "Block attributes";
nodtag.bIsCustom = true;
nodtag.bIsArray = true;
childnode.Tag = nodtag;
node.Nodes.Add(childnode);
Document doc = AcadApp.DocumentManager.MdiActiveDocument;
//Editor ed = doc.Editor;
//Database db = doc.Database;
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
foreach (ObjectId objid in attributes)
{
DBObject obj = tr.GetObject(objid, OpenMode.ForRead, false) as DBObject;
if (obj != null)
{
AttributeReference att = obj as AttributeReference;
cnode = new Node();
childnode.Nodes.Add(cnode);
SetDatPropObj(obj, cnode);
//cnode.Text = "Attribute" + (i + 1).ToString();
cnode.Text = att.TextString;
nodtag = new NodeTag();
nodtag.strPropertyName = "Attribute";
nodtag.strPropertyDesc = "Block attribute";
nodtag.bIsCustom = true;
nodtag.intIndex = i++;
cnode.Tag = nodtag;
}
}
tr.Commit();
}
}
}
node.Nodes.Sort();
node.TreeControl.EndUpdate();
return ("");
-
Personally, as long as there isn't a performance issue, I don't see the problem with utilizing COM objects. Aside from the interops that must be shipped and/or installed on the end user's system, why not use the infrastructure available?
Of course once software developers move closer to fully managed code, the ability to utilize COM objects will be limited. One might wonder then, if there is a death knell for applications built with unmanaged code.
-
I think the big reason to avoid the Interops is that if you have fully-managed code, you can build one DLL (or set of DLLs), and run it on multiple releases of Autocad, on either 32-bit or 64-bit platforms, and you don't have to worry about any of the platform issues.
And of course, the .NET interface is typically faster than the COM interface.
-
Where's your mistake? Apart from still using COM when I showed you in your other thread how to use PInvoke...
Hi Glenn,
About the COM usage, is that just for this case in particular? or in other words for what the OP routine is doing?
BTW, I have some large amount of code lines, that I am taking out my COM calls, so far noticed a difference in the speed, when selecting an object get all the properties, and pass those to a form (ie. tree control)... I still need the use of com objects - was thinking to probably post some of my code, but it is very specific, don't know...
So any comment you might have about COM...
Thank you Sir! :)
Luis,
It's late and my eyes are hanging out of my head, so I'll post a more coherent reply tomorrow, which will be just my opinions, based on observations I've made over the years.
Cheers,
-
Luis,
It's late and my eyes are hanging out of my head, so I'll post a more coherent reply tomorrow, which will be just my opinions, based on observations I've made over the years.
Cheers,
Perfect....
I see your eyes on the avatar, you are right :)
-
Don't go diss'ing my avatar now... ;-)
Chat tomorrow. L8R
-
Where's your mistake? Apart from still using COM when I showed you in your other thread how to use PInvoke...
Hi Glenn,
About the COM usage, is that just for this case in particular? or in other words for what the OP routine is doing?
BTW, I have some large amount of code lines, that I am taking out my COM calls, so far noticed a difference in the speed, when selecting an object get all the properties, and pass those to a form (ie. tree control)... I still need the use of com objects - was thinking to probably post some of my code, but it is very specific, don't know...
So any comment you might have about COM...
Thank you Sir! :)
Luis,
Sorry for the delay. It was in context to the OP's question, but more generally, this is what I tend to follow:
A. Is it in the Managed API? Yes - use it; No, goto plan B
B. Can I get to it easily with PInvoke? Yes - use it; No, goto plan C
3. Can I use it through COM, taking into account how much I need it, dependencies etc. Yes - use it; No, well....redesign maybe...:D
-
Luis,
Sorry for the delay. It was in context to the OP's question, but more generally, this is what I tend to follow:
A. Is it in the Managed API? Yes - use it; No, goto plan B
B. Can I get to it easily with PInvoke? Yes - use it; No, goto plan C
3. Can I use it through COM, taking into account how much I need it, dependencies etc. Yes - use it; No, well....redesign maybe...:D
Got it! Glenn, it makes sense :)