几何尺寸与公差论坛------致力于产品几何量公差标准GD&T (GDT:ASME)|New GPS(ISO)研究/CAD设计/CAM加工/CMM测量  


返回   几何尺寸与公差论坛------致力于产品几何量公差标准GD&T (GDT:ASME)|New GPS(ISO)研究/CAD设计/CAM加工/CMM测量 » 仿射空间:CAX软件开发(三)二次开发与程序设计 » CAD二次开发 » AutoCAD二次开发 » DirectDWG
用户名
密码
注册 帮助 会员 日历 银行 搜索 今日新帖 标记论坛为已读


回复
 
主题工具 搜索本主题 显示模式
旧 2009-05-05, 12:26 PM   #1
yang686526
高级会员
 
注册日期: 06-11
帖子: 14579
精华: 1
现金: 224494 标准币
资产: 234494 标准币
yang686526 向着好的方向发展
默认 【转帖】how do i create a link to an external database

how do i create a link to an external database?
how do i create a link to an external database?
autocad can create links to records in external database tables (e.g. ms access) using odbc or ole db. how do i create such a link using opendwg?
autocad links to external databases are stored in dwg file as xdata. if you know its structure you can add it "manually". dwgdirect has no high level api for it.
sergey slezkin
how to create object_ptr records?
thanks, sergey.
i do not have documentation on autocad's database link xdata, but i was able to create some test dxf files with autocad and decipher the necessary fields.
unfortunately, in addition to xdata, database links also require object_ptr records. i can find no reference to those records in opendwg. when i ran odcopyex on a file containing them, the program deleted those records. autocad does not recognize database links without those records.
can you tell me how to create object_ptr records with opendwg?
dxf object_ptr object has class name casedlpntablerecord. include folder contains its header but dwgdirect reads in and saves this object as proxy object (does not delete it).
this is because we noticed some problems with writing this object back to dwg file. sometimes if the object has some specific xdata for dco15 application autocad crashes if xdata was written to file unchanged. probably it contains some timestamps or check summs of something else.
in other words this object is not implemented in dd. as a work around you can write your own implementation of this class - custom class derived from oddbobject, with class name casedlpntablerecord and dxf name object_ptr (see examples/excustobjs)
but you may face the same problems we had...
sergey slezkin
thanks, sergey.
for the sake of anyone else who might be trying to do the same thing i will mention that i could not create the c++ class casedlpntablerecord because opendwg already has a class of that name. i had to give it a different name. in order to make sure that the autocad classname was correct i had to create a modified version of the odrx_dxf_define_members macro that would allow me to specify one name for the c++ class and a different name for the autocad class.
i have a question about the crash you were seeing. when i load a file containg db links into autocad 2002, then do some queries on the links, and finally exit autocad, sometimes i will get the following error:
fatal error: unhandled access violation reading 0x0008 exception at 3004bed0h
is that what you were seeing? i discovered i could get that same error without using opendwg to create the files. i created a small autocad file using only autocad 2002 and it would cause the crash, so i know opendwg is not to blame. i assume it is just a bug in autocad 2002.
how do i read the xdata in an object_ptr?
sergey,
in addition to writing db links i also need to read them. i am running into a problem because the object_ptr has been converted to a proxy. i can convert that object to an oddbproxyextptr and can print out the originaldxfname of it (object_ptr), but how do i access the xdata in it?
solved "how do i read the xdata in an object_ptr?"
i solved the problem by creating the same casedlpntablerecordptr class that i created for writing. i cast the object to that class and now am able to access the xdata records.
but xdata of oddbproxyobject can be accessed too since it's derived from oddbobject.
sergey slezkin
sergey,
maybe i just don't know how to use oddbproxyobject. i have the following code:
casedlpntablerecordcustomptr object = casedlpntablerecordcustom::cast( dictiter->getobject() );
it works fine. i changed it to:
oddbproxyobjectptr object = oddbproxyobject::cast( dictiter->getobject() );
the cast returns a null object. what am i doing wrong?
if casedlpntablerecordcustom class is not derived from oddbproxyobject the cast returns null. i suppose that it's derived from oddbobject. if so classes oddbproxyobject and casedlpntablerecordcustom are unrelated.
if casedlpntablerecordcustom class is registered before database loading proxies representing this class (if they exist in the database) are converted to casedlpntablerecordcustom objects.
sergey slezkin
hi jkenwilliams (sorry i do not know your name),
can you post the code snippet that uses the custom class to read and write database linkages (both from dxf and dwg). thanks a billion for any help on this.
regards,
saroja
sample code to write external database linkages
hi, saroja,
here is the code to write linkages. it is the same for dxf and dwg, but i recommend you start with dxf so that you can examine the resulting file and compare it with what autocad produces.
the code includes a few data types (like out_codes) and variables that are not defined in this snippet. i think you can probably figure out what you need without those definitions. i know the code will not compile as it is right now, since you don't have those definitions.
ken williams
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%
casedlpntablerecordcustom
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
// the opendwg programmers found that autocad would sometimes crash if they
// wrote records using the casedlpntablerecord class (in dxf it is called
// object_ptr), so they disabled it. that is why i have to implement it here
// as a custom class, because i cannot support db links without it.
// the following is copied from excustobjs/excustobjexport.h
#if defined(_msc_ver)
#ifdef _toolkit_in_dll_
#ifdef excustobjs_dll_exports
#define excustobjexport __declspec(dllexport)
#else /* oda_gi_exports */
#define excustobjexport __declspec(dllimport)
#endif /* oda_gi_exports */
#else /* _toolkit_in_dll_ */
#define excustobjexport
#endif /* _toolkit_in_dll_ */
#else /* _msc_ver */
#define excustobjexport
#endif /* _msc_ver */
// the following is adapted from excustobjs/excustobject.h & .cpp
class excustobjexport casedlpntablerecordcustom : public oddbobject
{
public:
// macro to declare
oddb_declare_members(casedlpntablerecordcustom);
casedlpntablerecordcustom() : oddbobject()
{
}
virtual ~casedlpntablerecordcustom()
{
}
};
typedef odsmartptr<casedlpntablerecordcustom> casedlpntablerecordcustomptr;
// odrx_dxf_define_members_custom is a slightly modified version of odrx_dxf_define_members defined
// in rxobject.h. i had to modify it because the class name that autocad must see is
// casedlpntablerecord, but i cannot declare a c++ class of that name because opendwg already
// defined it.
#define odrx_dxf_define_members_custom(classname,acadclass name,parentclass,docreate,dwgver,maintver,nproxyfl ags,dxfname,appname)\
odrx_define_members(classname);\
odrxobjectptr classname:seudoconstructor() { odrxobjectptr pobj; docreate(classname, pobj); return pobj; }\
\
odrxobject* classname::queryx(const odrxclass* pclass) const\
{ return :dqueryximpl<classname,parentclass>(this, pclass); }\
\
void classname::rxinit()\
{\
if (!classname::g_pdesc)\
classname::g_pdesc = ::newodrxclass(#acadclassname,parentclass::desc(), &pseudoconstructor,\
dwgver,maintver,nproxyflags,#dxfname,#appname);\
}\
\
void classname::rxuninit()\
{\
::deleteodrxclass(g_pdesc);\
g_pdesc = 0;\
}
odrx_dxf_define_members_custom(casedlpntablerecord custom,
casedlpntablerecord,
oddbobject,
dbobject_constr,
oddb::vac15,
oddb::kmrelease0,
oddbproxyentity::keraseallowed,
object_ptr,
ase-lpntablerecord)
***** after the odinitialize call, add this:
casedlpntablerecordcustom::rxinit();
***** at the end of the program, do this:
casedlpntablerecordcustom::rxuninit();
oduninitialize(); // dwgdirect termination
***** when you want to add a db link, call this:
/************************************************** ***************************
* set a db link
************************************************** **************************/
static bool // out: true if success (currently always true)
acadot_setdblink(
oddbentityptr pentity, // in: entity to which db links will be attached
out_codes* vcodes // in: acadot interface structure
)
{
odresbufptr temp;
if( !opendwgstate.supportsappdco15 )
{
opendwgstate.pdb->newregapp( db_application ); // add support for db application
// create the two db dictionaries
oddbdictionaryptr pmain =
opendwgstate.pdb->getnamedobjectsdictionaryid().safeopenobject( oddb::kforwrite );
// create the dictionary that lists the data source, table name and link column name.
opendwgstate.conldefdictionary = oddbdictionary::createobject();
// add new dictionary to the main dictionary.
pmain->setat( "conldefdictionary", opendwgstate.conldefdictionary );
// create the dictionary that holds the db link records
opendwgstate.aseindexdictionary = oddbdictionary::createobject();
pmain->setat( "ase_index_dictionary", opendwgstate.aseindexdictionary );
// add extended data fields
odresbufptr xase = odresbuf::newrb( 1001 );
temp = xase;
temp->setstring( db_application );
temp->setnext( odresbuf::newrb( 1040 ) );
temp = temp->next();
temp->setdouble( 0.0 ); // i don't know what this is for or if 0 is a valid value for it, but it appears to work ok.
opendwgstate.aseindexdictionary->setxdata( xase );
char dbbasename[max_filespec];
filename_make( file_ret, vcodes->dbfilename.text, null,
sizeof( dbbasename ), dbbasename );
opendwgstate.dbsourcename = dbbasename;
opendwgstate.dbsourcename += "...";
opendwgstate.supportsappdco15 = true;
}
odstring linktemplatename = vcodes->dbtablename.text;
linktemplatename += db_link_template;
oddbxrecordptr tablexrecord = opendwgstate.asexrecords[ vcodes->dbtablename.text ];
if( tablexrecord.get() == null )
{
// first time we have used this table. create the object_ptr that defines the link template.
// note: i don't know what all of these fields mean. i discovered them by looking at a dxf
// file i created in autocad.
casedlpntablerecordcustomptr object_ptr = casedlpntablerecordcustom::createobject();
opendwgstate.conldefdictionary->setat( linktemplatename, object_ptr );
odresbufptr object_ptrres = odresbuf::newrb( 1001 );
temp = object_ptrres;
temp->setstring( db_application );
temp->setnext( odresbuf::newrb( 1000 ) );
temp = temp->next();
temp->setstring( opendwgstate.dbsourcename + vcodes->dbtablename.text + "(" +
linktemplatename + ")" );
temp->setnext( odresbuf::newrb( 1000 ) );
temp = temp->next();
temp->setstring( vcodes->dblinkcol.text );
temp->setnext( odresbuf::newrb( 1000 ) );
temp = temp->next();
temp->setstring( "" );
temp->setnext( odresbuf::newrb( 1000 ) );
temp = temp->next();
temp->setstring( "" );
temp->setnext( odresbuf::newrb( 1070 ) );
temp = temp->next();
temp->setint16( 4 );
temp->setnext( odresbuf::newrb( 1070 ) );
temp = temp->next();
temp->setint16( 0 );
temp->setnext( odresbuf::newrb( 1070 ) );
temp = temp->next();
temp->setint16( 0 );
temp->setnext( odresbuf::newrb( 1070 ) );
temp = temp->next();
temp->setint16( 0 );
temp->setnext( odresbuf::newrb( 1070 ) );
temp = temp->next();
temp->setint16( 1024 );
object_ptr->setxdata( object_ptrres );
// create the xrecord that will list the link records for this table
tablexrecord = oddbxrecord::createobject();
tablexrecord->setmergestyle( oddb::kdrcignore );
opendwgstate.asexrecords[ vcodes->dbtablename.text ] = tablexrecord;
oddbobjectid xrid =
opendwgstate.aseindexdictionary->setat( linktemplatename, tablexrecord );
}
// create extended data that references the db link record
// (i determined the fields needed by creating a db link in autocad and
// looking at the resulting dxf records. i don't know what they all mean.)
odresbufptr xiter = odresbuf::newrb(1001);
temp = xiter;
temp->setstring(db_application);
temp->setnext( odresbuf::newrb( 1071 ) );
temp = temp->next();
temp->setint32( 1 );
temp->setnext( odresbuf::newrb( 1071 ) );
temp = temp->next();
temp->setint32( 1 );
temp->setnext( odresbuf::newrb( 1000 ) );
temp = temp->next();
temp->setstring( linktemplatename );
temp->setnext( odresbuf::newrb( 1004 ) );
temp = temp->next();
odbinarydata binarylink;
binarylink.resize( sizeof( odint32 ) );
*( (odint32*)binarylink.getptr() ) = vcodes->dblink;
temp->setbinarychunk( binarylink );
pentity->setxdata(xiter);
// create link information and add it to the xrecord
odresbufptr xlink = odresbuf::newrb( 330 );
temp = xlink;
temp->sethandle( pentity->getdbhandle() );
temp->setnext( odresbuf::newrb( 1004 ) );
temp = temp->next();
binarylink.resize( sizeof( odint32 ) * 4 );
odint32* binarydblinkdata = (odint32*)binarylink.getptr();
binarydblinkdata[0] = vcodes->dblink;
// i don't know what the next 3 numbers mean, but in my tests autocad always gave them these values.
binarydblinkdata[1] = 0;
binarydblinkdata[2] = 0xffffffff;
binarydblinkdata[3] = 0xffff0001;
temp->setbinarychunk( binarylink );
tablexrecord->appendrbchain( xlink );
return true;
}
sample code to read external database linkages
here is sample code for reading external database linkages.
(i should mention that you need the db_application defined for writing as well. i forgot to include it with that sample.)
#define db_application "dco15" // autocad's name for the database application
the casedlpntablerecordcustom definition is the same as for writing files. (see other post.)
read the link templates:
/************************************************** ************************
* retrieve information about all link templates in the file
************************************************** *************************/
static void
acadin_processlinktemplates()
{
opendwgstate.linktemplatesprocessed = true;
// open main dictionary
oddbdictionaryptr pmain =
opendwgstate.pdb->getnamedobjectsdictionaryid().safeopenobject( oddb::kforread );
// get the dictionary containing the link templates
oddbdictionaryptr linktemplatedict =
(oddbdictionaryptr)pmain->getat( "conldefdictionary", oddb::kforread );
if( linktemplatedict.isnull() )
{
... set error code ...
return;
}
// each object in this dictionary is a link template definition
oddbdictionaryiteratorptr dictiter = linktemplatedict->newiterator();
for( ; !dictiter->done(); dictiter->next() )
{
linktemplateinfo linktemplateinfo;
linktemplateinfo.m_validlink = true;
linktemplateinfo.m_errorcode = 0;
casedlpntablerecordcustomptr object =
casedlpntablerecordcustom::cast( dictiter->getobject() );
odresbufptr resbuf = object->xdata( db_application );
int stringnumber = 0;
while( !resbuf.isnull() )
{
if( resbuf->restype() == 1000 )
{
stringnumber += 1;
odstring string = resbuf->getstring();
switch( stringnumber )
{
default:
break;
case 1:
// should look like: "db_name...table_name(link_template_name)"
{
int tablenamepos = string.find( '.' );
if( tablenamepos < 0 )
{
// cannot parse.
linktemplateinfo.m_validlink = false;
linktemplateinfo.m_tablename = "";
}
else
{
// table name begins after 3 dots
tablenamepos += 3;
int parenpos = string.find( '(' );
if( parenpos < tablenamepos )
{
// should never get here, but just in case ...
linktemplateinfo.m_tablename = string.mid( tablenamepos );
}
else
{
linktemplateinfo.m_tablename =
string.mid( tablenamepos, parenpos - tablenamepos );
}
}
}
break;
case 2:
linktemplateinfo.m_columnname = string;
break;
case 3:
// i don't know what this string is for. for an integer column it is blank.
// for an ascii column it is "1252". ignore it.
break;
case 4:
// must be blank for an integer column
if( linktemplateinfo.m_validlink && string != "" )
{
linktemplateinfo.m_validlink = false;
}
break;
case 5:
// this is the name of the second link column (which i am not handling)
if( linktemplateinfo.m_validlink )
{
linktemplateinfo.m_validlink = false;
}
break;
}
}
resbuf = resbuf->next();
} // end while
opendwgstate.linktemplatehash[ dictiter->name().c_str() ] = linktemplateinfo;
}
}
for each entity that has a db link:
// db links
odresbufptr resbuf = pent->xdata( db_application );
dblink dblink;
while( !resbuf.isnull() )
{
if( resbuf->restype() == 1000 )
{
dblink.linktemplatename = resbuf->getstring();
if( !resbuf.isnull() )
resbuf = resbuf->next();
if( !resbuf.isnull() && resbuf->restype() == 1004 )
{
odbinarydata binarylink = resbuf->getbinarychunk();
switch( binarylink.size() )
{
default:
// unsupported size (wrong column type)
dblink.linkid = -1;
break;
case 2:
// i have never seen a two-byte link, but just in case ...
dblink.linkid = *(odint16*)binarylink.getptr();
break;
case 4:
dblink.linkid = *(odint32*)binarylink.getptr();
break;
}
acadin_dblinks.push_back( dblink );
}
}
if( !resbuf.isnull() )
resbuf = resbuf->next();
} // end while
}
thanks. it works..
ken, thanks a million - this is exactly what i needed. redefining the macro did the trick.
regards,
saroja
what s hould we give these values
"binarydblinkdata[2] = 0xffffffff" and "binarydblinkdata[3] = 0xffff0001"
if we are handling text.
thanks
ramu
yang686526离线中   回复时引用此帖
GDT自动化论坛(仅游客可见)
回复


主题工具 搜索本主题
搜索本主题:

高级搜索
显示模式

发帖规则
不可以发表新主题
不可以回复主题
不可以上传附件
不可以编辑您的帖子

vB 代码开启
[IMG]代码开启
HTML代码关闭

相似的主题
主题 主题发起者 论坛 回复 最后发表
【转帖】headers and compiler configuration yang686526 DirectDWG 0 2009-05-05 12:03 PM
【转帖】dwf7import link error yang686526 DirectDWG 0 2009-05-05 07:56 AM
【转帖】adt static link settings yang686526 DirectDWG 0 2009-05-04 03:50 PM
【转帖】2005 link error yang686526 DirectDWG 0 2009-05-04 02:57 PM
【转帖】1.13 hostapp systemservices problems yang686526 DirectDWG 0 2009-05-04 02:48 PM


所有的时间均为北京时间。 现在的时间是 05:01 AM.


于2004年创办,几何尺寸与公差论坛"致力于产品几何量公差标准GD&T | GPS研究/CAD设计/CAM加工/CMM测量"。免责声明:论坛严禁发布色情反动言论及有关违反国家法律法规内容!情节严重者提供其IP,并配合相关部门进行严厉查处,若內容有涉及侵权,请立即联系我们QQ:44671734。注:此论坛须管理员验证方可发帖。
沪ICP备06057009号-2
更多