Outside The Box blogs, Autodesk University anecdotes, articles, blog digests, and product news in chronological order. See Writing for the same material by subject.

If you want it done right...

· Programming

I’ve proved once again that if you want it done right, you have to do it yourself. The ManuSoft web site is fully functional again after my longtime ISP had a major network meltdown. I waited for two weeks for them to repair it, then finally moved to a different provider. The new provider’s promised “24/7 tech support” turned out to mean “24 hours to respond, 7 days to fix” every problem, not to mention that I would need to provide step by step instructions to their techs so they could configure the server the way I needed. After two weeks of that, I gave up and configured my own server and now host it myself. Let this be a warning to all of you hosting web sites with reputable providers, or storing your data somewhere in the cloud. I paid big bucks every month to my old provider for secure servers, redundant power supplies, managed and air conditioned server rooms, nightly backups, 99% uptime, etc., but they still lost everything. Almost a month later they still haven’t restored their customers’ data. Luckily, I make my own backups.

Read

Disable InfoCenter in AutoCAD 2010

· Tools

[Update: See Disable AutoCAD InfoCenter] In case you missed it, Tony Tanzillo has posted instructions (http://discussion.autodesk.com/forums/thread.jspa?threadID=721735&tstart=1) for disabling the InfoCenter in AutoCAD 2010. AutoCAD 2010 starts faster when the InfoCenter is disabled. To make it easy, I’ve created an AutoLISP file that defines commands named DisableInfoCenter and EnableInfoCenter: …

Read

ObjectARX 2010: Dealing With Missing Exports

· Programming

In the new ObjectARX 2010 SDK, Autodesk has added some new virtual member functions that are not exported as they should be. For example, the AcGiFaceData class has had two new virtual functions added for setting and getting the face transparency: class AcGiFaceData: public AcRxObject { //[… deleted for brevity] ACDB_PORT virtual AcDbObjectId materials() const; ACDB_PORT virtual AcGiMapper mappers() const virtual void setTransparency(const AcCmTransparency transparency); virtual AcCmTransparency transparency() const private: AcGiImpFaceData mpAcGiImpFaceData; }; As you can see, whoever added the new functions neglected to prefix them with the ACDB_PORT macro. ACDB_PORT evaluates to __declspec(export), which tells the compiler to export the function. Since the macro is missing, the new functions are not exported from acdb18.dll. Since these are virtual functions, you won’t have any problems calling them through a pointer to an AcGiFaceData object that was constructed by AutoCAD. The problem arises when you derive a class from AcGiFaceData. Since the functions are not exported, the linker has no way of resolving their address for creating the virtual function table of your derived class. This results in linker errors: acrxEntryPoint.obj : error LNK2001: unresolved external symbol “public: virtual void __thiscall AcGiFaceData::setTransparency(class AcCmTransparency const )” (?setTransparency@AcGiFaceData@@UAEXPBVAcCmTransparency@@@Z) acrxEntryPoint.obj : error LNK2001: unresolved external symbol “public: virtual class AcCmTransparency * __thiscall AcGiFaceData::transparency(void)const " (?transparency@AcGiFaceData@@UBEPAVAcCmTransparency@@XZ)Following is an example that results in these errors: class AcGiFaceDataEx: public AcGiFaceData { public: AcGiFaceDataEx() {} ~AcGiFaceDataEx() {} } Test; The only solution is to provide an implementation of the missing functions. In this case, it could be accomplished by something like this: class AcGiFaceDataEx: public AcGiFaceData { AcCmTransparency mpTransparency; public: AcGiFaceDataEx() : mpTransparency( NULL ) {} ~AcGiFaceDataEx() { delete mpTransparency; } virtual void setTransparency(const AcCmTransparency transparency) { delete mpTransparency; mpTransparency = (transparency? new AcCmTransparency( transparency ) : NULL); } virtual AcCmTransparency transparency() const { return mpTransparency; } } Test;This will fix the linker errors, but there is no guarantee that it will work as intended. AutoCAD might access its internal transparency value directly without calling through the member functions, which means it would never “see” the transparency set through the replacement member functions. Furthermore, the addition of the new pointer member changes the size of the class, which causes AcGiFaceDataEx arrays to have a different memory footprint than AcGiFaceData arrays. Lastly, what if Autodesk fixes the problem in a future AutoCAD service pack? The ideal solution should not change the size of the class. It should check at runtime whether the function is exported, then use the exported function if it exists. That way, code that is written now will use the exported function if and when it becomes available in a future version of AutoCAD. When the function is not exported, an alternate implementation must be provided. This is not an unusual scenario, and the solution I present for the specific case of AcGiFaceData can be adapted to the more general problem. In the AcGiFaceData case, the missing functions are virtual functions. Knowing this, it is possible to use a trick to get the address of the real function. In the code below, the function getAcGiFaceData_vtable() constructs a temporary AcGiFaceData object, from which it extracts a pointer to the object’s virtual function table. The virtual function table is just an array of function pointers, so the address of the desired function can be obtained by indexing into the virtual function table. The question is, how far? By counting virtual functions and data members starting from the top of the class hierarchy: in this case, 6 virtual functions in AcRxObject plus 16 virtual functions in AcGiFaceData = 22. Note that obtaining a function pointer this way relies on Visual C++ implementation details, but this is safe to do since all ObjectARX modules must be compiled in Visual C++. Following is my solution to the missing AcGiFaceData functions: #pragma warning(push) #pragma warning(disable: 4608) template < typename Src, typename Dest > Dest force_cast( Src src ) { union _convertor { Dest d; Src s; _convertor() : d(0), s(0) {} } convertor; convertor.s = src; return convertor.d; } #pragma warning(pop) static FARPROC getAcGiFaceData_vtable() { static FARPROC rfVTable = (FARPROC**)&AcGiFaceData(); return (rfVTable? rfVTable : NULL); } void AcGiFaceData::setTransparency( const AcCmTransparency transparency ) { typedef void (AcGiFaceData::F_setTransparency)( const AcCmTransparency ); static F_setTransparency pfSetTransparency = force_cast< FARPROC, F_setTransparency >(GetProcAddress( GetModuleHandleA( “acdb18.dll”), “?setTransparency@AcGiFaceData@@UEAAXPEBVAcCmTransparency@@@Z” )); if( !pfSetTransparency ) { static FARPROC rfVTable = getAcGiFaceData_vtable(); if( rfVTable ) pfSetTransparency = force_cast< FARPROC, F_setTransparency >( rfVTable[22] ); } if( pfSetTransparency ) (this->pfSetTransparency)( transparency ); } AcCmTransparency AcGiFaceData::transparency() const { typedef AcCmTransparency (AcGiFaceData::F_transparency)() const; static F_transparency pfTransparency = force_cast< FARPROC, F_transparency >(GetProcAddress( GetModuleHandleA( “acdb18.dll”), “?transparency@AcGiFaceData@@UEBAPEAVAcCmTransparency@@XZ” )); if( !pfTransparency ) { static FARPROC rfVTable = getAcGiFaceData_vtable(); if( rfVTable ) pfTransparency = force_cast< FARPROC, F_transparency >( rfVTable[23] ); } if( pfTransparency ) return (this->*pfTransparency)(); return NULL; }

Read