krispy 的个人资料Kristian's Space日志列表留言簿更多 工具 帮助

Kristian's Space

Thanks for visiting!
请稍候...
很抱歉,您输入的评论太长。请缩短您的评论。
您没有输入任何内容,请重试。
很抱歉,我们当前无法添加您的评论。请稍后重试。
若要添加评论,需要您的家长授予您相应权限。请求权限
您的家长禁用了评论功能。
很抱歉,我们当前无法删除您的评论。请稍后重试。
您已超过了一天之内允许提供的评论数上限。请在 24 小时后重试。
因为我们的系统表明您可能在向其他用户提供垃圾评论,您的帐户已禁用了评论功能。如果您认为我们错误地禁用了您的帐户,请联系 Windows Live 支持部门
完成下面的安全检查,您提供评论的过程才能完成。
您在安全检查中键入的字符必须与图片或音频中的字符一致。
10月15日

Deploying DLLs Over the Network

After initially "installing" my .net app's to users computers via lisp within AutoCAD I ran into the problem of updating a dll. The problem lies with one of my applications that sets reactors in each drawing, as such it needs to be loaded at AutoCAD startup. Obviously if the dll is loaded it cannot be deleted because it is in use. So we have decided to use a vbscript file to install and update dlls, so far so good.
 
I have created a script file that sits on the network that contains a sub which will install/update a dll file onto the user's local machine and setup registry keys for demand loading. This network script file is then called by a local script file in each user's startup folder.
 
The local user's file contains:
 

ExecuteGlobal _
CreateObject("Scripting.FileSystemObject"). _
OpenTextFile("
\\SERVER\FILE_PATH\Setup.vbs").ReadAll

WScript.Quit


The network file contains:


SetupApp "APP_NAME", "Application Description", "FILENAME.dll", LOADCTRLS, "COMMAND_NAME", "GROUP_NAME", True

Const APPLICATION_DATA = &H1a&
Const FOR_APPENDING = 8
Const AUTOCAD_SUPPORT = "\Autodesk\AutoCAD 2008\R17.1\enu"
Const LOCAL_DLLS = "\COMPANY_SPECIFIC_SUBFOLDER"
Const NETWORK_DLLS = "NETWORK_PATH_OF_DLLS"
Const AUTOCAD_REGPATH = "HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\R17.1\ACAD-6001:409\Applications"
Const DEBUGGING = False

If DEBUGGING Then WScript.Echo "AutoCAD add-ons installed"

Sub SetupApp(sAppName, sDescription, sFileName, iLoadCtrls, sCommandName, sGroupName, bUpdate)
 If bUpdate Then
  Set objShell = CreateObject("Shell.Application")
  Set objFSO = CreateObject("Scripting.FileSystemObject")
  Set objFolder = objShell.Namespace(APPLICATION_DATA)
  Set objFolderItem = objFolder.Self
  
  sDestination = objFolderItem.Path & AUTOCAD_SUPPORT & LOCAL_DLLS
  sSource = NETWORK_DLLS
  
  If FileInUse(sDestination & "\" & sFileName) Then
   WScript.Echo sFileName & " is in use." & vbcrlf &  "Could not setup " & sAppName & "."
  Else
   'Create directory if it doesn't exist
   If not objFSO.FolderExists(sDestination) Then
      Set objFolder = objFSO.CreateFolder(sDestination)
      If DEBUGGING Then WScript.Echo sDestination & " created."
   End If
   
   'Delete file if it exists
   If objFSO.FileExists(sDestination & "\" & sFileName) Then
      objFSO.DeleteFile sDestination & "\" & sFileName
      If DEBUGGING Then WScript.Echo sDestination & "\" & sFileName & " deleted."
   End If
   
   'Copy file to replace deleted one
   If objFSO.FileExists(sSource & "\" & sFileName) Then
      objFSO.CopyFile sSource & "\" & sFileName, sDestination & "\"
      If DEBUGGING Then WScript.Echo sDestination & "\" & sFileName & " copied."
   End If
   
   sRegPath = AUTOCAD_REGPATH & "\" & sAppName
   Set WshShell = CreateObject("WScript.Shell")
   
   WshShell.RegWrite sRegPath & "\DESCRIPTION", sDescription, "REG_SZ"
   WshShell.RegWrite sRegPath & "\LOADCTRLS", iLoadCtrls, "REG_DWORD"
   WshShell.RegWrite sRegPath & "\MANAGED", 1, "REG_DWORD"
   WshShell.RegWrite sRegPath & "\LOADER", sDestination & "\" & sFileName, "REG_SZ"
   
   If Not sCommandName = vbNullString Then
    WshShell.RegWrite sRegPath & "\Commands\" & sCommandName, sCommandName, "REG_SZ"
    WshShell.RegWrite sRegPath & "\Groups\" & sGroupName, sGroupName, "REG_SZ"
   End If
   
   If DEBUGGING Then WScript.Echo "Registry paths written."
   If DEBUGGING Then WScript.Echo sAppName & " setup."
  End If
  Set objShell = Nothing
  Set objFSO = Nothing
  Set objFolder = Nothing
  Set objFolderItem = Nothing
 End if
End Sub

Function FileInUse(sFileName)
 On Error Resume Next
 Set objFSO = CreateObject("Scripting.FileSystemObject")
 If objFSO.FileExists(sFileName) Then
  Set objFile = objFSO.OpenTextFile(sFileName, FOR_APPENDING, False)
  
  If Err.Number = 70 Then
   FileInUse = True
  Else
   objFile.Close
   Set objFile = Nothing
   FileInUse =  False
  End If
 Else
  FileInUse = False
 End If
End Function


Basically what this file does is to copy a central (network) version of the dll to the user's local machine. If the dll already exists it will delete it first and replace it with the new one. It will then write the appropriate keys to the registry to set up the application for demand loading within AutoCAD.

A brief description of the Sub's arguments:

  • sAppName: Is the name of the application and will be the key name in the registry.
  • sDescription: Is a description of the application and will be the value of DESCRIPTION in the registry.
  • sFileName: Is the filename of the dll. It is assumed that you will update the CONST variables to match the appropriate network and local locations.
  • iLoadCtrls: Is the value of LOADCTRLS within the registry and will set in what circumstances to demand load the app in AutoCAD.
  • sCommandName: Is the command name referred to within the dll and must match exactly or demand loading will not work.
  • sGroupName: Is the group name the command belongs to.
  • bUpdate: If set to true then the script will attempt to update the dll, otherwise it will skip this application. This is to reduce windows startup times if there becomes a large number of dlls to setup.

If the dll does not contain any commands you will still need to include an argument for sCommandName and sGroupName but they should both be vbNullString.

 

10月9日

*error* handling

Something I have been playing around with lately in the LISP world is error handling. Previously I would create a separate error function and set values for olderr and *error* within the main function. I have since discovered the joys of declaring the *error* function local and nesting it within the main function:
 

 
(defun MAIN (/ *error* xCmdEcho)
  (setq xCmdEcho (getvar "CMDECHO"))
  (defun *error* (msg)
    (if (or
        (= msg "Function cancelled")
        (= msg "quit / exit abort")
      )
      (princ)
      (princ (strcat "\nError: " msg))
    );end if
    (setvar "CMDECHO" xCmdEcho)
  );end error function
 
  ;main function contents
 
  (exit nil)
);end defun MAIN
 

 
The advantage of this, besides having the code encapsulated and local so it is destroyed at the end of the main function, is that not only can you use the *error* function to reset system variables in case of an error, you can also explicitly call the function at the end of the main function like so: (exit nil).
 
This ability to call (exit nil) can be used anywhere within the main function and can be used to terminate execution if invalid input is detected from the user, rather than having multiple nested if's and progn's.
 
The example above simply exits quietly (and resets CMDECHO) if it is called with (exit nil) or if the user hits [ESC], or displays the error message if something unexpected happened.
10月8日

Registry Keys for Demand Loading

These can be set with a registry file (i.e. *.reg) like so:
 

 
Windows Registry Editor Version 5.00
 
[HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\R17.1\ACAD-6001:409\Applications\<Application Name>]
"DESCRIPTION"="<Application Description>"
"LOADCTRLS"=dword:00000002
"MANAGED"=dword:00000001
"LOADER"="<Location of dll on local machine>"
 
[HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\R17.1\ACAD-6001:409\Applications\<Application Name>\Commands]
"<Command Name>"="<Command Name>"
 
[HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\R17.1\ACAD-6001:409\Applications\<Application Name>\Groups]
"<Command Group>"="<Command Group>"
 

 
A few points:
The AutoCAD keys R17.1 and ACAD-6001:409 refer to the build and region of the AutoCAD application. For example, the values shown above are for AutoCAD 2008, english. (AutoCAD 2007 would be R17.0).
 
The <Application Name> and <Application Description> are not referred to within the dll so can be any value that is descriptive.
 
The LOADCTRLS value should be set according to the desired loading behaviour. See my previous post on LOADCTRLS.
 
The MANAGED key is always set to 1 for .NET dlls
 
The LOADER key is the path to the dll file on the local machine. Any backslashes used in the path should be escaped, i.e. \ becomes \\
 
The Commands key is only used if there is a command created within the dll. So if the dll only has reactors then this part can be left out. The Key Name and Value sould be the same as the command name specified within the dll.
 
The Groups key is optional.
 
 

LOADCTRLS

One of the things I am continuously forgetting is the value of LOADCTRLS I need to add to the registry. Below are the possible values (taken straight from the ObjectARX documentation):
 
0x01 = Load application on detection of proxy object
0x02 = Load the application on AutoCAD startup
0x04 = Load the application on command invocation
0x08 = Load the application on request by user or other application
0x10 = Do not load the application
0x20 = Load the application transparently
 
Of course, these values can be added when required.
 
Generally I will use either the 0x02 value when I have reactors that need to be added to all documents, or will combine 0x04 & 0x08 for applications that simply add a command.
 
I have not yet tried creating proxy objects, so have not had to play with these values.

Welcome

Welcome to Kristian's Space.
 
I am starting this blog primarily to keep track of the code snippets and tricks I discover as I continue to learn more about programming for AutoCAD. Hopefully others will also find it useful.
 
Most of the information I gather is either from the built in documentation within the relevant packages, or from discussion groups. If I have a specific block of code or quote from someone I will try to credit the author here. Mostly I will be talking about AutoCAD and Revit programming and I rely on the Autodesk discussion groups for a lot of help: Autodesk Discussion Groups
 
Cheers,
Kris
 

krispy

职业
地点

Xbox Live 玩家卡

Krispy5
Xbox Live 玩家卡
声望:
5/5 星
得分:
4872
区域:
Recreation
Halo 3: ODSTSplosion ManRainbow Six® Vegas 2ZumaUNO