This code seems to work, but I got some examples from here, and I'm not sure if I used them right. I was just wondering if people with more experience with Object DBX could take a glance and give me some pointers. What it does is import blocks from a drawing. Thanks. Tim ps. I attached the ".dcl" file, just rename the extension from ".txt" to ".dcl". (defun ImportBlockDia (BlockList / blist diaload ipblist bilist) (if BlockList (progn (setq blist (vl-sort BlockList '(lambda (x y) (< (vla-get-Name x) (vla-get-Name y))))) (setq diaload (load_dialog "CloseDwg.dcl")) (if (not (new_dialog "Cdrawings" diaload)) (exit) ) (start_list "tx2" 3); clear the list (mapcar '(lambda (x) (add_list (vla-get-Name x))) blist) (end_list) (action_tile "accept" "(progn (setq ipblist (get_tile \"tx2\")) (done_dialog 1) )" ) (action_tile "cancel" "(progn (setq ipblist nil) (done_dialog 1) )" ) (start_dialog) (if ipblist (progn (setq ipblist (read (strcat "(" ipblist ")"))) (foreach item ipblist (setq bilist (cons (nth item blist) bilist)) ) ) ) ) ) bilist ) ;--------------------------------------------------------------------- (defun c:CopyBlocks (/ dbxDoc rslt con *blocks cblist blist) (if (setq rslt (tmw:OpenDBX)) (progn (setq cblist (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-ACAD-Object)))) (setq *blocks (vla-get-Blocks (car rslt))) (vlax-for item *blocks (if (and (/= (vla-get-IsXRef item) :vlax-True) (not (vl-string-search "|" (vla-get-Name item))) (not (vl-string-search "*" (vla-get-Name item))) ) (setq con (cons item con)) ) ) (if (setq blist (ImportBlockDia con)) (foreach item blist (vla-CopyObjects (car rslt) (vlax-SafeArray-Fill (vlax-Make-SafeArray vlax-vbObject '(0 . 0)) (list item)) cblist ) ) ) (VL-CATCH-ALL-APPLY 'vlax-release-object (list dbxDoc con *blocks cblist blist)) (tmw:CloseDBX rslt) ) ) (princ) ) ;----------------------------------------------------------------- (defun tmw:OpenDBX (/ FileName NewFileName TestIf dbxDoc) (if (setq FileName (getfiled "Select file:" (getvar "dwgprefix") "dwg" 4)) (progn (if (setq TestIf (open FileName "a")) (close TestIf) (progn (setq NewFileName (strcat (vl-filename-directory FileName) "\\" (strcat "CopyOf-" (vl-filename-base FileName) ".dwg"))) (vl-file-copy FileName NewFileName) (setq FileName NewFileName) ) ) (setq dbxDoc (vla-GetInterfaceObject (vlax-get-ACAD-Object) "ObjectDBX.AxDbDocument.16")) (vla-Open dbxDoc FileName) (list dbxDoc FileName) ) ) ) ;---------------------------------------------------------------------- (defun tmw:CloseDBX (Results / FileName) (setq FileName (cadr Results)) (vl-Catch-All-Apply '(lambda () (vla-Close (car Resutls)))) (vlax-Release-Object (car Results)) (if (vl-string-search "CopyOf-" (vl-filename-base FileName)) (vl-file-delete FileName) ) )
Well I can't say I read the code....but it should be just copying the object then inserting it into your drawing... You could open the drawing and filter only its blocks, then copy and insert into your drawing... Just remember to filter out xrefs from regular blocks... I used this to differ from what an xref is and a block... (vl-load-com) (defun c:dbxblock (/ dbxDoc dwgname la cn lp it con) (setq dwgname (getfiled "Select Drawing File" "" "dwg" 4)) (if dwgname (progn (setq dbxDoc (vla-GetInterfaceObject (vlax-get-acad-object) "ObjectDBX.AxDbDocument" ) ) (vla-open dbxDoc DwgName) (setq la (vla-get-block dbxdoc) cn (vla-get-count la) lp 0 ) (repeat cn (setq it (vla-item la lp) ) (setq con (vla-get-isxref it)) (princ con) (setq lp (1+ lp)) ) (vl-catch-all-apply '(lambda () (vla-close DBXDOC ':VLAX-TRUE 'ITEM)) ) (VL-CATCH-ALL-APPLY 'vlax-release-object (list dbxDoc dwgname la cn lp it con) ) (vlax-release-object dbxDoc) (setq dbxDoc nil) ) ) (princ) ) -- MASi Copyright 2004 by Cadentity www.Cadentity.com Autodesk Authorized Developer
Rudy, I saw you post this before, that is one of the reason why I tried to make my own routine. I didn't quite understand some of the functions you used, and even after reading the help files I still only could grasp a little. The two parts are: (vl-catch-all-apply '(lambda () (vla-close DBXDOC ':VLAX-TRUE 'ITEM)) ) and (VL-CATCH-ALL-APPLY 'vlax-release-object (list dbxDoc dwgname la cn lp it con) ) The first one looks as if you are closing the document that you opened in Object DBX, but I don't understand what the ':vlax-true or the 'item do. The second one you are release all the variable names that you use, but when does it and what, has to be released? Any pointers is greatly appreciated. Thanks. Tim
After several conversations with other developers and friend...any object that you use within the dbx function must be released or variable as illustrated...or else the drawing will not close and remain open...of which effects mean leaving a lock on the file and the drawing open. This mentioned...affects what you could use to update the file or edit it...even simply reading it. The only way you'll be able to gain access to the file again you'll have to shut down autocad or else the file will say it's open by guess who..? YOU. As you'v noticed..the first part opens and assigns the object file...then second simply uses the vla methods of acquiring objects or properties...then changing all things to given object... and finally releasing the object then cancel out each variable regardless of were how you used it within the illustrated list... Again there must be a LIST of all Variable that you used within the final list for the file to be released... -- MASi Copyright 2004 by Cadentity www.Cadentity.com Autodesk Authorized Developer
;;For ref (defun IMPORTBLOCKDIA (BLOCKLIST / BLIST DIALOAD IPBLIST BILIST) (if BLOCKLIST (progn (setq BLIST (acad_strlsort BLOCKLIST)) (setq DIALOAD (load_dialog "CloseDwg.dcl")) (if (not (new_dialog "Cdrawings" DIALOAD)) (exit) ) (start_list "tx2") (mapcar 'add_list BLIST) (end_list) (action_tile "accept" "(setq ipblist (get_tile \"tx2\")) (done_dialog 1)" ) (action_tile "cancel" "(done_dialog 0)" ) (start_dialog) (if IPBLIST (progn (setq IPBLIST (read (strcat "(" IPBLIST ")"))) (foreach ITEM IPBLIST (setq BILIST (cons (nth ITEM BLIST) BILIST)) ) ) ) ) ) BILIST ) ;;--------------------------------------------------------------------- (defun C:COPYBLOCKS (/ DBXDOC CON *BLOCKS CBLIST BLIST) (if (setq FILENAME (getfiled "Select file:" (getvar "dwgprefix") "dwg" 4) ) (progn (setq DBXDOC (vla-getinterfaceobject (vlax-get-acad-object) "ObjectDBX.AxDbDocument.16" ) ) (vla-open DBXDOC FILENAME) (setq CBLIST (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)) ) ) (setq *BLOCKS (vla-get-blocks DBXDOC)) (vlax-for ITEM *BLOCKS (if (and (/= (vla-get-isxref ITEM) :vlax-true) (not (vl-string-search "|" (vla-get-name ITEM))) (not (vl-string-search "*" (vla-get-name ITEM))) ) (setq CON (cons (vla-get-name ITEM) CON)) ) ) (if (setq BLIST (IMPORTBLOCKDIA CON)) (foreach ITEM BLIST (vla-copyobjects DBXDOC (vlax-safearray-fill (vlax-make-safearray vlax-vbobject '(0 . 0)) (list (vla-item *BLOCKS ITEM)) ) CBLIST ) ) ) (vl-catch-all-apply 'vlax-release-object (list DBXDOC *BLOCKS CBLIST) ) ) ) ;;Add some code for insert into your drawing... (princ) )
Who told you that? The only object that you have to explicitly release, is the AxDbDocument. All others are destroyed regardless of any references or not.
Don't feel bad, Rudy doesn't seem to understand them either. I don't know where Rudy got the idea that you can close an AxDbDocument like that, but you can't. The AxDbDocument object has no Close method, but of course, since Rudy wraps the call in a vl-catch-all-apply, he never sees the error. To 'close' an AxDbDocument, just use (vlax-release-object) on the variable containing the document, and that'll do it.
Thanks for enlightening me... I'd have to go back a few weeks and rewind me thoughts...just in case you didn't follow the original thread, you may want to comment on it there...but of coarse you're probably too busy to look... We should hear from you more often, instead of you just degrading us...
Hi Tim, Looking at the code you posted, and what Lucas posted (the two seem related), I don't see checking for duplicate block names from source file to target file. Or maybe I'm missing something? I haven't tried to run either program. What I'd expect to see is a filtered list of block names contained in target file. Then while copying blocks from source file, a check to ensure source file block name doesn't exist in target file. Without such a check, I think a duplicate record error would occur sooner or later. And may I suggest, if you want folks to critique your code, you should post it in form that's easy to understand. For instance, attaching a dcl file will turn most people off. It's not relevant to your primary question about ODBX. I often rewrite code when I want to post a question here. Just so the question is clear. Related, a line like this will also trurn off the folks you are most interested in talking to. (setq cblist (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-ACAD-Object)))) The expression returns the blocks collection vla-object of the active file. That's not a list, so the var name is misleading. In turn, that makes the rest of your code hard to understand at first glance. Joe Burke
Joe, Thanks for the comments, as I am still learning. The reason why I posted the dcl file was incase someone tried to run it, just wanted them to be able to without comeing back and asking for the dcl file. When I tested it with blocks that were the same name, I didn't have a problem, but now that you said something, and made me think. I wonder if the new blocks being imported is over writting the one that already exist? I will have to check that out. About my variable names, I understand what you are talking about. On the fly while writting, I name how I reference them in my own mind. The collection is still like a list in my mind, even though when I stop and think about it, it really isn't. Tim
This is directed to Tony Tanzillo but anyone can chime in... Tony, I have found that when dealing with Land Desktop activex objects, such as PVI's from PVI collection, I have to release the PVI object after I use it or I get rather random but persistent crashes. I use a vlax-for loop like this: (this one deletes all but one special PVI...) (VLAX-FOR PVI PVIS (IF (/= (VLAX-GET-PROPERTY PVI 'STATION) 1234567.89) (VL-CATCH-ALL-APPLY 'VLAX-INVOKE-METHOD (LIST PVIS "DELETE" (VLAX-GET-PROPERTY PVI 'STATION))) ) (VL-CATCH-ALL-APPLY 'vlax-release-object (list PVI)) ) Note the release object at the end of each loop. This seems to solve the problem of the crashes. Now I see no reason why this should be necessary but experience shows it is. I really need to understand what is going on with the PVI object, is there a reason I would get a problem with an object in a foreach loop? I think it has to do with a bug in the handling of the garbage cleanup of the com objects...any advice appereciated though. "T.Willey" <> |>This code seems to work, but I got some examples from here, and I'm not sure if I used them right. I was just wondering if people with more experience with Object DBX could take a glance and give me some pointers. |> |>What it does is import blocks from a drawing. |> |>Thanks. |>Tim |> |>ps. I attached the ".dcl" file, just rename the extension from ".txt" to ".dcl". |> |>(defun ImportBlockDia (BlockList / blist diaload ipblist bilist) |> |>(if BlockList |> (progn |> (setq blist (vl-sort BlockList '(lambda (x y) (< (vla-get-Name x) (vla-get-Name y))))) |> (setq diaload (load_dialog "CloseDwg.dcl")) |> (if (not (new_dialog "Cdrawings" diaload)) |> (exit) |> ) |> (start_list "tx2" 3); clear the list |> (mapcar '(lambda (x) (add_list (vla-get-Name x))) blist) |> (end_list) |> (action_tile "accept" |> "(progn |> (setq ipblist (get_tile \"tx2\")) |> (done_dialog 1) |> )" |> ) |> (action_tile "cancel" |> "(progn |> (setq ipblist nil) |> (done_dialog 1) |> )" |> ) |> (start_dialog) |> (if ipblist |> (progn |> (setq ipblist (read (strcat "(" ipblist ")"))) |> (foreach item ipblist |> (setq bilist (cons (nth item blist) bilist)) |> ) |> ) |> ) |> ) |>) |>bilist |>) |> |>;--------------------------------------------------------------------- |> |>(defun c:CopyBlocks (/ dbxDoc rslt con *blocks cblist blist) |> |>(if (setq rslt (tmw:OpenDBX)) |> (progn |> (setq cblist (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-ACAD-Object)))) |> (setq *blocks (vla-get-Blocks (car rslt))) |> (vlax-for item *blocks |> (if |> (and |> (/= (vla-get-IsXRef item) :vlax-True) |> (not (vl-string-search "|" (vla-get-Name item))) |> (not (vl-string-search "*" (vla-get-Name item))) |> ) |> (setq con (cons item con)) |> ) |> ) |> (if (setq blist (ImportBlockDia con)) |> (foreach item blist |> (vla-CopyObjects |> (car rslt) |> (vlax-SafeArray-Fill (vlax-Make-SafeArray vlax-vbObject '(0 . 0)) (list item)) |> cblist |> ) |> ) |> ) |> (VL-CATCH-ALL-APPLY 'vlax-release-object (list dbxDoc con *blocks cblist blist)) |> (tmw:CloseDBX rslt) |> ) |>) |>(princ) |>) |> |>;----------------------------------------------------------------- |> |>(defun tmw:OpenDBX (/ FileName NewFileName TestIf dbxDoc) |> |>(if (setq FileName (getfiled "Select file:" (getvar "dwgprefix") "dwg" 4)) |> (progn |> (if (setq TestIf (open FileName "a")) |> (close TestIf) |> (progn |> (setq NewFileName (strcat (vl-filename-directory FileName) "\\" (strcat "CopyOf-" (vl-filename-base FileName) ".dwg"))) |> (vl-file-copy FileName NewFileName) |> (setq FileName NewFileName) |> ) |> ) |> (setq dbxDoc (vla-GetInterfaceObject (vlax-get-ACAD-Object) "ObjectDBX.AxDbDocument.16")) |> (vla-Open dbxDoc FileName) |> (list dbxDoc FileName) |> ) |>) |>) |> |>;---------------------------------------------------------------------- |> |>(defun tmw:CloseDBX (Results / FileName) |> |>(setq FileName (cadr Results)) |>(vl-Catch-All-Apply '(lambda () (vla-Close (car Resutls)))) |>(vlax-Release-Object (car Results)) |>(if (vl-string-search "CopyOf-" (vl-filename-base FileName)) |> (vl-file-delete FileName) |>) |>) James Maeding jmaeding at hunsaker dot com Civil Engineer/Programmer
HI all, If your [Chinese lang] is good enough , you can visit http://www.mjtd.com/bbs/dispbbs.asp?boardID=27&ID=8884&page=1 just wanted them to be able to without comeing back and asking for the dcl file. problem, but now that you said something, and made me think. I wonder if the new blocks being imported is over writting the one that already exist? I will have to check that out. fly while writting, I name how I reference them in my own mind. The collection is still like a list in my mind, even though when I stop and think about it, it really isn't.
Hi Tim, I ran your code. Nice work, BTW. It's simply skipping blocks with the same name in target file. You're right, the check I suggested isn't needed. Though still, you might want to know which ones were copied or skipped. If you want it to replace blocks of the same name you could do something like this. Check to see if source block name exists in target block collection. If so, use vlax-for to delete all objects in the target block definition. Then use CopyObjects to copy the objects from source block into the now empty target block definition. Of course this is getting into some dangerous territory, so be careful. I have something I wrote for myself which replaces same name blocks from one drawing to another using the above method. It uses dos_checklist (DOSLib) for the block selection dialog. Kinda nice since it provides a check box for each block name. Joe Burke
Joe, Thanks for testing it, and thanks for the compliment. Glad you pointed out what it was doing with blocks of the same name. I will look into your idea when I have some time. If I run into problems with the new part of the code, I will be back here posting. Work came up and have deadlines, ya know. Tim
Final version (for now). Last update: will let you know what blocks will not be inserted. Tim ps Change the txt extension to lsp to work.
Joe, I was trying to work on something that would replace one block definition with another, but I couldn't get it to work. I was trying to use the 'CopyObject method, but it only seems to work with an acad document or an acad database, which a block table definition doesn't seem to be either one. How were you able to do this? or if anyone else knows, could you please advise? Thanks. Tim ps. Here is what I had so far, but it doesn't work. The only thing it does is delete the objects form the old block. (defun ReplaceBlock (BlockOld BlockNew / cnt1 temp1) (if (and (= (vla-get-ObjectName BlockOld) "AcDbBlockTableRecord") (= (vla-get-ObjectName BlockNew) "AcDbBlockTableRecord") ) (progn (vlax-for item BlockOld (vlax-invoke-method item 'Delete) ) (setq cnt1 0) (while (/= cnt1 (vla-get-Count BlockNew)) (setq temp1 (vla-Item BlockNew cnt1)) (vla-CopyObjects BlockNew (vlax-SafeArray-Fill (vlax-Make-SafeArray vlax-vbObject '(0 . 0)) (list temp1)) BlockOld ) (setq cnt1 (1+ cnt1)) ) ) ) )