One of the really compelling features of. NET is it ability to call "legacy" unmanaged C + + APIs. I say "legacy", but we use this facility regularly to call APIs that is far from being considered defunct (the C + + Versio N of Objectarx is alive and kicking, believe me! :-).
One of the really compelling features is that. NET calls the ability to "legacy" unmanaged C + + APIs. I say "legacy", but we use this mechanism to invoke the API far from proving that this thing is dead (c + + version Objectarx alive and Kicking, believe me!).:-).
autodesk understands Development partners has invested many years in application development, and can ' t afford to throw that investment away T o Support the latest & greatest (and sometimes "flavor of the Month") programming technology. For example, over the years we ' ve made sure it is possible to create a VB or VBA user-interface for an existing LISP APPL Ication or now a. NET user-interface for an OBJECTARX application. Sometimes we expose our own interoperability functions to help with this (such as LISP functions to call ActiveX DLLs), an D in the other cases we advise people on how best to leverage standard Microsoft platform technologies.
Autodesk understands that our development partners have been involved in application development for many years and cannot abandon their previous investments in order to support the latest and greatest programming technologies. For example, over the years we have tried to create VB or VBA user interfaces for existing Lisp programs to guarantee or now provide the. NET user interface for Objectarx applications. Sometimes we expose our interoperability capabilities to help users (such as Lisp functions call an ActiveX DLL), while in other cases we advise people how to take advantage of Microsoft platform technology standards.
So ... how does a objectarx function from vb.net? The answer is Platform Invoke (or P/invoke). Microsoft have not exposed the full functionality of the Win32 API through the. NET Framework-just as Autodesk have not ex Posed all of Objectarx through AutoCAD's Managed api-but P/invoke helps you get around this.
So... How do you invoke a Objectarx function from vb.net? The answer is platform invoke (abbreviated as P/invoke). Microsoft has not yet exposed the full functionality of the Win32 API through the. NET Framework. Just like Autodesk does not expose Objectarx through all of AutoCAD's management APIs, but P/invoke helps you circumvent this limitation.
First, some background on what Objectarx really are, and how P/invoke can help us.
First, there are some background about what Objectarx is, and how P/invoke helps us.
objectarx was a set of APIs that was Exported from DLLs or EXEs. Most exported functions get "decorated" or "mangled" during compilation, unless there are a specific compiler directive not To (the the-the-case-all-the-old ADS-functions, for-Instance-they is declared as extern "C" and was therefore not Mangled). The compiler assigns a unique name based on the function signature, which makes sense:it are quite legal in C + + to having TW o functions with the same name, but not with identical arguments and return values. The decorated name includes the full function name inside it, which is what the below technique for finding the correct exp ORT works.
Objectarx is a set of APIs exported as DLLs or EXE, and most output functions are always modified or destroyed during the compilation process, unless there is a specific compiler directive (which is appropriate for the old ads feature, They generate an extension C to ensure that it is not corrupted) The compiler assigns a unique name based on the function signature to ensure that the signature is meaningful because the two functions have the same name in C + + and different signatures are completely legal
The decorated name includes the full function name inside, which is why the following techniques are found to work on the correct export
[ Note: This technique works well for c-style functions, or C + + static functions. It won't work on instance members (methods of classes), as it's not possible-instantiate an unmanaged object of the Class that defines the class from managed code. If you need to expose a class method to managed code, you'll need to write & expose some native C + + code that Instan Tiates the class, calls the method and returns the result. ]
This technique is suitable for C-style functions, or C + + static functions. It does not work with instance members (the method's Class) because it is not possible to instantiate a class that defines a class of unmanaged objects from managed code. If you need to have a class method managed code, you need to write & expose some native C + + code instantiation classes, call the method, and return the results.
To demonstrate the procedure we ' re going to work through the steps needed to call Acedgetuserfavoritesdir () from C # and VB . NET.
The demonstration process we need to complete the required steps to achieve in the C # and the vb.net () called in Acedgetuserfavoritesdir ()
This function was declared in the Objectarx headers as:
extern Adesk::boolean Acedgetuserfavoritesdir (achar* szfavoritesdir);
According to the Objectarx Reference, "This function provides access to the Windows Favorites directory of the R. "
According to Objectarx's reference, this feature provides the ability to get the current user favorites
Step 1-identify the location of the export.
Fenton Webb, from Devtech EMEA, provided this handy batchfile he uses for just this purpose:
[Copy and paste this to a file named "Findapi.bat", which you so place this into your Autocadapplication folder. You'll need to run FINDAPI from a command prompt whichknows where to find dumpbin.exe-the Visual Studio command Prompt S created oninstalling VS would help you with this. ]
This copy and paste it into a file named "Findapi.bat", and then put this into the CAD application folder. You need to run FINDAPI from the command prompt to find out dumpbin.exe-visual Studio command prompt On create install vs will help you solve this problem
@echo offif "%1" = = "" Goto usage:normalfor%%i in (*.exe *.dll *.arx *.dbx *.ocx *.ddf) do dumpbin/exports%%i | Findstr "%%i%1" goto end:usageecho findapi "function name": End
You can redirect the output to a text file, of course, for example:
C:\Program Files\autocad 2007>findapi acedgetuserfavoritesdir > Results.txt
It ' ll take some time to work, as this batch file chunks through all the DLLs, EXEs, etc. in the AutoCAD application Folder To find the results (it doesn ' t stop when it finds one, either-this enhancement was left as a exercise for the reader; -).
It will take some time to work, this batch file examines all DLLs in the CAD application folder, and EXE to find the results (it does not stop when it finds one, either, this enhancement is left to the reader as an exercise;-).
Opening the text file would allow you to see where the Acedgetuserfavoritesdir () function is exported:
from for - ]dump of File Acad.exe 436 1b0 004b4dc0 [email protected]@[email protected]
A Word of warning: the decorated names for functionsaccepting/returning strings changed between AutoCAD 2006 and Because Weare now using the Unicode for string definition. Here is the previous declarationfor 2004/2005/2006 (which were probably valid for as long as the function wasdefined, back In AutoCAD 2000i, if I recall correctly):
The function accepts a change in the decorated name/return string between AutoCAD 2006 and 2007, because we now use the definition of a Unicode string. This is previously declared 2004/2005/2006 (may be in function definition, as long as valid in AutoCAD 2000 I, if I remember correctly):
from for 2006 ]dump of File Acad.exe 357 16100335140 [email protected]@[email Protected
This is simply because the function signature have changedfrom taking a char* to an achar* (a datatype which now resolves T o A "wide" or Unicode string in AutoCAD 2007). A change in the functionsignature results with a change in the decorated name. This was straightforwardenough, but it was worth bearing in mind the potential migration issue-a heavydependency on Decora Ted function names can leads to substantial migration effortif widespread signature changes is made in a release (as with AutoCAD (Ssupport of Unicode).
This is entirely because the function signature has changed from char * to Achar * (data types are resolved to "wide" or Unicode strings in AutoCAD 2007). Changes in function signatures result in changes in name changes. This is very simple, but it is worth noting that a potential apology problem-heavily dependent on the decorated function name can cause a lot of migration work to be changed in one release (with AutoCAD 2007 support Unicode).
Another warning: you'll find a number of other functions exportedfrom the various dlls/exes that does not have the CO Rresponding declarations in Theobjectarx headers. These functions-while exposed-are not supported. Whichmeans that's able to work out how they can is called, but use them atyour own risk (which can substantial ). Unsupported APIs is liable to change (or even disappear) without notice.
You will find that many of the headers from different DLLs or exe other functions have no related declarations. These features will not be supported even if exposed. This means that you can find out how they can be called, but use their own risk (in essence). Unsupported APIs are very easy to change without notice
Now we ' ve identified where and how the function isexposed, we can create a declaration of this function we can use Code.
Now that we have determined where and how to expose the function, we can create a declaration of this function that we can use in our code.
Step 2-declare the function correctly in your code.
This was going to being slightly different depending on theprogramming language you ' re using.
It will be slightly different depending on the programming language you are using
VB developers is used to using the "Declare" to the set-up p/invoke from their projects. This ends up being translated by Thecompiler into calls to DllImport, which are also used directly in C #.
Introducing keywords, VB using declare C # using DllImport
These declarations should is made at the class level (Notwithin an individual function definition).
Needs to be declared at the class level, no longer defined in the individual
" Acad.exe " " [email protected]@[email protected] " (<marshalas (UNMANAGEDTYPE.LPWSTR) > ByVal sDir as StringBuilder) As Boolean
C#[dllimport ("acad.exe""[email protected]@[email protected] ", CharSet = CharSet.Auto)]publicstaticextern Boolacedgetuserfavoritesdir ([MarshalAs (UNMANAGEDTYPE.LPWSTR)] stringbuildersdir);
Notes:
- It ' Sworth specifying the character set as "Auto"-which is not thedefault setting. The compiler does a good job of working out whether to useunicode or ANSI, so it's easiest to trust it to take care of thi S.
It is worth specifying that the character is set to automatic-this is not the default setting. The compiler is well-judged whether Unicode or ANSI is used, so it is trustworthy.
- Youwill need to use the MarshalAs (UNMANAGEDTYPE.LPWSTR) declaration for unicodestring variables in 2007. This is true whether using Strings or stringbuilders.
You will need to use MarshalAs (UNMANAGEDTYPE.LPWSTR) to declare the Unicode string variable in 2007. This is true whether to use a string or stringbuilders
- Usea StringBuilder for the output string parameter, as standard Strings areconsidered immutable. Strings is fine for input parameters.
With the StringBuilder output string parameter, the standard string is immutable. The string is a pair of input parameters.
Step 3-use the function in your code
[I ' ve omited the standard using/import statements, aswell as the class & function declarations, to improve readabilit Y.]
I've omitted standard usage/import statements, as well as class and function declarations, to improve readability.
= Application.DocumentManager.MdiActiveDocument.EditorDim SDir as New StringBuilder (at 0 then ed. Writemessage ("" + sdir.tostring) End If
=new StringBuilder (n); bool bRet = acedgetuserfavoritesdir (sDir); if 0 ) ed. Writemessage ("" + sdir.tostring ());
Note: wedeclare the StringBuilder variable (sDir) as being-characters long. Autocadexpects us to provide a sufficiently long buffer for the data to be copied intoit.
We declare that the StringBuilder variable (SDIR) is 256 characters in length. AutoCAD expects us to provide a long enough copy of the data to the buffer.
On my system both code snippets resulted in the followingbeing sent to AutoCAD ' s command-line:
Your Favorites folder Is:c:\my documents\favorites
So that's it:youshould now is able to call global Objectarx functions from. NET. This techniquecan also is used to call your own functions exposed from DLLs ... Which is oneway-to-allow-you-to-create fancy UIs with. NET and leverage existing C + + code (thereare others, such as Exposi Ng your own Managed API).
That's it: you should now be able to call the global Objectarx function from. Net. This technique can also be used to call your function from a DLL to expose ... This is an expensive interface that allows you to create an exploit. NET and leveraging existing C + + code (and others, such as exposing your own management API)
For additionalinformation in using P/invoke, particularly with Win32, here is a really greatresource.
2006-7 Valuable Kean Blog--calling Objectarx functions from a. NET application (PInvoke)