' 1:< DBG_INFO: Could not load file or assembly 'file:///L:\Revit\bwtools\Plotting\Plotting.dll' or one of its dependencies. An attempt was made to load a program with an incorrect format.: line 93 of .\Source\APIManagedExecuteCommand.cpp.This is the generic error for when a 32bit program is called from a 64bit environment. After some experimentation, it seems that this was caused by my application Microsofts 32bit DSOFile.dll. To get my program to start at all, I had to compile for x64, this didn't fix my problem totally (I'll discuss this below) however it allowed me to start the dll and debug to pinpoint where exactly the error was occuring. To do this in visual studio head to the properties page of your project and go to the 'build' section. Then set the platform target to 'x64'. I then specified a different output directory (as we have 64bit and 32bit users on our network) and built the project. It was then a matter of updating the target users revit.ini file to point to the 64bit build instead of the 32bit build. I did this by updating my ini edting program to detect if the operating system is vista, if so check if revit is in the program files, or program files (x86) directory and copy the text accordingly. This got my macro to start, but it then crashed when calling the DLL. This however gave me the chance to pinpoint the location of the exception. Find 64bit version of 3rd party DLL's The problem I described above, was due to me accessing a 3rd party COM DLL which is compiled for 64bit. The only way I am able to rectify this is by finding a 32bit version of the required DLL and installing it on the users machine. This will be different for each situation, but one thing to keep in mind that regsvr32.exe, the tool used to reference DLL's in the registry does not have a regsvr64.exe counterpart, contrary to common logic. Unfortunately microsoft decided to keep the name the same, but simply store it in a different directory. So C:\Windows\SysWOW64\regsvr32.exe is the 64bit dll registrar. Summary The process has been made really easy by the revit team, assuming one thing - you do not use a 3rd party 32bit dll. So for 99% of external commands, the switch is simple, and chances are you won't have to do anything! Unfortunately for the other 1% the reality of 64bit development is that you are going to run into problems with external 32bit references, and will probably be cast into DLL-hell. So test those commands! If anyone has had other issues with 64bit Revit they would like to share please comment this article or join this discussion at AUGI.
Monday, October 13, 2008
Revit 64bit & The Revit API
64bit System.Security.SecurityException errors
Friday, August 29, 2008
RIS services fails to start with Error 127: the specified procedure could not be found error
Wednesday, August 20, 2008
How to get the full path of a file from a HTML File Input
Monday, August 18, 2008
How to detect Windows Vista in batch file or logon script
VER | findstr /i "5.0." > nul IF %ERRORLEVEL% EQU 0 set version=2000
VER | findstr /i "5.1." > nul IF %ERRORLEVEL% EQU 0 set version=XP
VER | findstr /i "5.2." > nul IF %ERRORLEVEL% EQU 0 set version=2003
VER | findstr /i "6.0." > nul IF %ERRORLEVEL% EQU 0 set version=Vista
This searches for the build number in the ver string.Increase vista performance
Friday, August 15, 2008
the temp folder is on a drive that is full or is inaccessible. free up space on the drive or verify that you have write permission on the temp folder.
Tuesday, June 10, 2008
How to set custom attributes / file properties on a file in C# .Net
In the office here we have developed a document management system, which uses Custom Properties on PDF and DWG files to keep a track of what revision etc they are. In my Revit API development, we required an easy way of settings these from inside of Revit, so I set about creating a plotting external command using the new Print methods in the 2009 API and PDF995's ini file.
Once I'd printed the documents, I wanted to rename them and set the custom properties such as Revision, drawer, designer etc. After much searching, I discovered what you need to get is "DSOFile" from Microsoft, it is intended for editing Microsoft Word document properties, but works on anything. There is an easy to understand VB.Net example included in the download.
DSO File works by adding a reference to the DLL and creating a new DSOFile.OleDocumentPropertiesClass, and then performing actions on that. So, I created a new: private DSOFile.OleDocumentPropertiesClass m_file; Then in my constructor for my ParamaterSetter class I created an instance of OleDocumentPropertiesClass and then called the Open() Method with my filename:
//create new isntance of OleDocumentPropertiesClass
m_file = new DSOFile.OleDocumentPropertiesClass();
// select the file you would like to open
m_file.Open(path, false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
From there you can perform actions such as : m_file.CustomProperties.Add(key, ref valueForKey); where key is the name of your property, and valueForKey is the value. For more standard properties, such as the "Summary" properties (in summary tab when you go properties on the file), you can access them directly, such as: m_file.SummaryProperties.Comments = value;
For reference, here is the utility class I use:
class FileParameterSetter { //DSOFile document private DSOFile.OleDocumentPropertiesClass m_file; public FileParameterSetter(string path) { //create new isntance of OleDocumentPropertiesClass m_file = new DSOFile.OleDocumentPropertiesClass(); // select the file you would like to open m_file.Open(path, false, DSOFile.dsoFileOpenOptions.dsoOptionDefault); } /// <summary> /// Sets a custom property in the file. /// </summary> /// <param name="key">key to set</param> /// <param name="value">value to set to key</param> public void SetCustomproperty(string key, string value) { try { object valueForKey; //check for valid inputs if ((key == null) || (value == null) || (key.Length == 0) || (value.Length == 0)) { //Error, no key or value. return; } valueForKey = value; //write to file m_file.CustomProperties.Add(key, ref valueForKey); //save change m_file.Save(); } catch(Exception ex) { System.Windows.Forms.MessageBox.Show("There was an error adding properties to PDF file: " + ex); } } /// <summary> /// Saves and closes document /// </summary> public void Close() { m_file.Close(true); } /// <summary> /// Sets a standard property, such as Comments, Subject, Title etc /// </summary> /// <param name="key"></param> /// <param name="value"></param> public void SetStandardProperty(string key, string value) { if (key.Equals("Comments")) { m_file.SummaryProperties.Comments = value; } if (key.Equals("Subject")) { m_file.SummaryProperties.Subject = value; } if (key.Equals("Title")) { m_file.SummaryProperties.Title = value; } } }
Tuesday, May 20, 2008
System.Security.SecurityException Request for the permision of type..... errors
Sunday, May 18, 2008
How to update your facebook status via SMS
Thursday, May 15, 2008
Help, my database updates don't stick
Thursday, March 20, 2008
Using Revit KeyboardShortcuts for your external commands
Wednesday, March 19, 2008
Revit commands and the revit.ini file
- Open your Revit.Ini file
- Find [ExternalCommands] if there is one, if not, create that section.
- Insert the reference to your .DLL external command file, it should look similar to as follows
Sunday, March 9, 2008
How to make Vista look like XP
Friday, February 29, 2008
Revit 2009 API information
Tuesday, February 19, 2008
Setting up a template for Revit API External Commands
Recently I have been commissioned to tap into the Autodesk Revit API, and create external commands for Revit Structure (Applies for Revit Architecture as well). Documentation is limited, and there are few experts in Australia at present.
I have used the AUGI Forum community, the API SDK Samples, and this API Webcast to get me going. If you plan on writing a lot of different external commands, then chances are, you're going to be best served with a Visual Studio template.
I'm still using Visual Studio 2005 with .Net 2.0, but I wouldn't imagine it would be much different in visual studio 2008. I am also using C#, rather than visual basic, as most of the examples are in C#, and it is my choice of language. To get you started, reading the introduction material in the API SDK is going to get you started, there is a word document there, then you will have a good idea of what I am doing.
First off, create a new project in Microsoft Visual Studio, just a Class Library will do, unless you want a dialog box in your template. Name it whatever you like (it gets changed when you make a template) and store it in a folder for your Revit commands. Normally here, I would right click on my assembly and go to properties and set a couple of things, but we will skip that step for now as those changes don't get saved in the template.
Now we need to import the RevitAPI file, go to Project > Add Reference, then browse to your Revit directory to find the RevitAPI.dll file, select it. Once it is imported, it will show up in the references folder, click 'RevitAPI' there and go to properties, change 'Copy to Output Directory' to 'Do not copy'. This stops a copy of the RevitAPI file, which is 5-10 mb being made each time.
There will be a default .cs file in your solution, named class1.cs or similar, change this to Command.CS (it doesn't really matter, however this is the format followed in the API samples). And then open it for editing. At the top, add 'using Autodesk.Revit;' to the using list. This tells the class that it will be using the RevitAPI file we imported. Now we need to tell it that this is going to be an external command, to do this, we inherit the IExternalCommand interface, by adding ": IExternalCommand" to the end of our class signature, making it: class Command : IExternalCommand Now, each IExternalCommand needs to supply a result, here is how we start the cogs of our command turning. In our class, create a 'public IExternalCommand.Result', as follows:
" public IExternalCommand.Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) {
} "
This should be nothing new if you have read the API documentation, but I am recapping it for you.
From here, your command will complete its actions, call other classes and methods, and then tell revit whether it succeeded or failed. Seeing as this is just a template, we just need to put the basic framework in, here's how i like to do it: "
try {
// Command does stuff here
return IExternalCommand.Result.Succeeded;
} catch (Exception ex)
{
MessageBox.Show("An error has occured in a this external command, please show this to your Revit Manager: \r\n " + ex.ToString());
return IExternalCommand.Result.Failed;
} "
As you can see, I have enclosed all of my code in Try Catch blocks, this is to make things end a little more neatly in case of a crash. You might like to cut your Try Catch block out while testing and learning, as the Visual Studio 2005 debugger has a hard time helping you when you use them, but make sure you put them back in. You also might not like to spit out the exception to the user, depends on the circumstances. You will also noticed I have added the return of IExternalCommand.Result.Succeeded in the try block, and Failed in the catch, so if an error occurs - the command fails, if not, it succeeds. That is how your command exits, when it reaches either of those lines of code.
Once you have done that, you might like to add some summary comments eg
///
/// Created by Rod Howarth (http://rodhowarth.com) for CLIENT
///
once you have done that, simply go to File > Export Template, and save it where you like. It will automatically be added to your Visual Studio templates. Access it again by going File > New Project > Visual C# (click on the heading) and then choose the template you named. Now you are all setup to start banging out some great Revit External Commands. I intend on blogging some more about the basic process as well as bits of peices of information I discover for myself along the way, in a bid to help increase the amount of Revit API help that is available online.
Wednesday, January 16, 2008
How to tell who is using a shared file (and how to close it!)
Thursday, January 3, 2008
Using Netlimiter to control speeds of computers internet connection over a network
I'd tried all of the bartering and negotiating, to no avail, I even pulled out the LAN for a bit, but I can't leave it out all the time. So I turned to Netlimiter, a program used for bandwidth monitoring and shaping.
I'd already been using RealVNC to close down bandwidth hogging applications on the other computers, so I used that to install Netlimiter. From there I simply went to View -> All Tools -> Permissions Editor, and then ticked 'Monitor' and 'Control' under the Guest account (you may like to assign it to a local passworded account).
Then on my Netlimiter, I went to View -> All Tools -> Remote Administration and entered the computer name, username as 'Guest', refresh time as 1000 & Automatic, clicked save, then clicked connect, entered no password for guest, and away she goes.
From there, you simply choose what to limit the connections down and upload speeds to:
To do this, I changed the units to KB from the dropdown, and set the limits to 4 download and 2 upload, seeing as I'm only on a 512kb connection. You might like to be more generous. You can then tick it on and off at your pleasure.
It's working a charm, I'm wasting my days playing games, my brothers and sisters haven't noticed (I even forgot to turn it off when I went away for the weekend - no complaints), everyone is happy.