SU to VB6.0 (Or there and back again.) :)
-
Figured out how to build a bridge finally.
The answer I came up may not be the only way to go but it is the only one I've found to date.
In this solution I wrote the VB6 application as an ActiveX dll.
I use a stub ruby program with win32ole to instantiate the dll.
I pass whatever instantiated SU object I wish to the dll as a reference through a public sub routine in the dll.From the dll I manipulate SU API object.
A couple of things to note.- Any objects passed back to SU must be passed as variant data types.
If datatypes cannot be converted implicitly you will have to do it manually. - All objects passed must be destroyed in the dll before the sub routine exits. (Set them to nothing)
- if the SU API defines a method as returning a value the VB implementation must do so also.
- Variants and UDT's are mutually exclusive so work arounds will have to be used.
- I only have the VB.NET 2008 Express version at home so I will not be able to test with VB.NET for now. (I assume that the generic 'Object' datatype will stand in for the Variant data type.
Listing 1: SU stub code
require 'sketchup' require 'win32ole' #--- def testbed model = Sketchup.active_model entities = model.entities tb = WIN32OLE.new('TestSUApp.clsTestSUApp') # Pass the entities object to the DLL tb.createblock(entities) end #--- if( not file_loaded?("testbed.rb") ) add_separator_to_menu("Tools") UI.menu("Tools").add_item($exStrings.GetString("Test Bed")) { testbed } end file_loaded("testbed.rb")
Listing 2: VB Dll code (Compile with instancing = multiuse)
Option Explicit Public Sub createblock(ents As Variant) Dim wt As Single Dim dp As Single Dim ht As Single Dim sVals As String Dim s() As String Dim rect As Variant Dim face As Variant Dim vstatus As Variant ' The following dippy dimension entry technique is just for the test. ' No error checking is supplied sVals = InputBox("Enter Width, Depth, Height", "Create Box", "") If sVals = "" Then GoTo CleanUp s = Split(sVals, ",") wt = CSng(Trim(s(0))) dp = CSng(Trim(s(1))) ht = -CSng(Trim(s(2))) rect = To_Rect(To_Pt(0, 0, 0), To_Pt(wt, 0, 0), To_Pt(wt, dp, 0), To_Pt(0, dp, 0)) Set face = ents.add_face(rect) vstatus = face.pushpull(ht, False) CleanUp; Set vstatus = Nothing Set face = Nothing Set ents = Nothing End Sub Private Function To_Rect(ByVal pt1 As Variant, ByVal pt2 As Variant, ByVal pt3 As Variant, ByVal pt4) As Variant Dim v As Variant v = Array(pt1, pt2, pt3, pt4) To_Rect = v End Function Private Function To_Pt(ByVal x As Single, ByVal y As Single, ByVal z As Single) As Variant Dim v As Variant v = Array(x, y, z) To_Pt = v End Function
- Any objects passed back to SU must be passed as variant data types.
-
SU to VB and Back. Part II
a) Added a windows form to the dll. Not a big deal.
b) Made the window a modal dialog. This is to stop the ruby code from falling through to the end of the script.
c) Added a global module to pass the SU API objects and the dll host object into the form. The form may now process SU API objects directly and/or pass properties back to the host. (Where the ruby script can read them.)UI.messagebox( vbdll["propertyname"] )
Utilizing this method we can have a VB form pop up on top of SU and disallow interaction with the SU environment while still driving the SU API from the form real time.
No splats, crashes, or blue screens.
Full power of Visual Basic 6.0 available to SU now.
-
Proved out that VB.NET can talk to SU in the same manner provided you start with a (backwards compatible) COM Project.
As I thought the generic object type may be substituted for the vb6 variant type.
SU does not complain.
Attached is a simple VB.NET dll with a child form that builds a box through the SU API then returns a message to the SU script.
Have fun!
-
Update:
Found we can pass the main Sketchup object to the VB dll.
(Had to create a variable to contain the Sketchup object first. Duh.)This opened up more possibilities. For instance you can load a Ruby script file from your VB program that does not existing in your plugin folder.
Private Sub cmdRunRuby_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdRunRuby.Click Dim status As Object With OpenFileDialog1 .InitialDirectory = "c;\" .AddExtension = True .DefaultExt = "rb" .Filter = "Text files (*.rb)|*.rb" .FileName = "" .ShowDialog() If .ShowDialog() = Windows.Forms.DialogResult.OK Then status = g_oApp.load(.FileName.Replace("\", "\\")) status = Nothing End If End With End Sub
Attached is a flow chart (Poorly made) that attempts to show the process used to drive SU from VB. Also attached is a snapshot of the vb.net testbed from the previous post running.
Determined that the SketchUp API exposed to Windows is not the SketchUp API that is used internally by Ruby. This is somewhat disappointing as it means we cannot do SU API debugging nor do we have Intellisense for the SU objects.
On the up side we have both of those features for data typed variable written in VB.
-
Gruff, thanks for posting. I'm trying to step through your VB.NET example using the files in testbed.zip but I get the following error when I start up StetchUp:
"Error Loading File testbed.rb no such file to load win32ole"
My guess is that the Ruby script in Sketchup cannot find the library win32ole.rb. I downloaded and installed Ruby 1.8 for windows (http://rubyinstaller.org/) because I suspect the win32ole.rb is somewhere in the Ruby installation. If I find win32ole.rb I will copy it to the Plugins folder (C:\Program Files\Google\Google SketchUp 8\Plugins)
However I can't seem to find the required library. The most I can find is C:\Ruby187\lib\ruby\1.8\win32ole\property.rb.
Do you know what files are required for the win32ole to work? Did you have any issues with this?
-
Dean ... you can get the win32ole.so file (it is a compiled "shared object" file, not a rb text script,) ...
here: [Plugin Library] Win32API and Win32OLE so files
And you normally do not just install any odd version of Ruby. SketchUp v8 uses 1.8.6-p287
which you can get here: http://rubyforge.org/frs/download.php/47082/ruby186-27_rc2.exe -
Just starting to connect VB to SkectchUp. As that is taking a little longer than I thought, I thought it mind be helpful for some to use Excel as the "go between" if you need to do something between VB or Acad and SkecthUp, as either of them can connect to Excel as easily as SkecthUp can.
So as an example I did a SkecthUp cafe creator, driven from Excel face point data per row.
Maybe someone will find this useful, or a better way to do it, or improve my Ruby, since I am just starting on the Ruby end.
#Reference standard API hooks. require 'sketchup.rb' require 'win32ole' #Add a menu item to launch our plugin, #in its SketchUp menu default name target, #and the name we are giving our function in the "Tools" menu. UI.menu("Tools").add_item("Get XLTiler") { # UI.messagebox("Ye Excel! come up from hell!") get_xltiler } #define the function that is activated from that added menu item click def get_xltiler #connect to an already open Excel application, use WIN320LE.new to start Excel #.connect to connect to an already open Excel instance application = WIN32OLE.connect('Excel.Application') application.visible = TRUE #Instantiate tile matrix origin for Excel rows and columns reference r = 0 c = 1 #Set row and column count #note cols is the face pts x1,y1,z1; x2,y2,z2... 1 through 4 xyz points; or 12 cols #XL row 1= pt1; 1, 1, 0 pt2; 1, 2, 0 pt3; 2, 2, 0 pt4; 2, 1, 0 #XL row 2= pt1; 2, 1, 0 pt2; 2, 2, 0 pt3; 3, 2, 0 pt4; 3, 1, 0 #and so on... #Rows are face count to create rows = 24 #Columns have all 4 face points cols = 12 # rows is how many face tiles you are creating in SketchUp, 1 face tile, per each row # Get handles to our model and the Entities collection it contains. model = Sketchup.active_model entities = model.entities #THE MAIN FACE CREATING ROUTINE #stepping through rows, as how many tiles you are creating is total rows, #then stepping through cols to populate all 4 face pts per row #step through all the XL rows for step in 1..rows r = r + 1 UI.messagebox(r) c = 1 # and in every row populate the face pts from Excel cell values for step in 1..cols pt1x = application.activesheet.cells(r,c).value pt1y = application.activesheet.cells(r,c + 1).value pt1z = application.activesheet.cells(r,c + 2).value pt1 = pt1x, pt1y, pt1z pt2x = application.activesheet.cells(r,c + 3).value pt2y = application.activesheet.cells(r,c + 4).value pt2z = application.activesheet.cells(r,c + 5).value pt2 = pt2x, pt2y, pt2z pt3x = application.activesheet.cells(r,c + 6).value pt3y = application.activesheet.cells(r,c + 7).value pt3z = application.activesheet.cells(r,c + 8).value pt3 = pt3x, pt3y, pt3z pt4x = application.activesheet.cells(r,c + 9).value pt4y = application.activesheet.cells(r,c + 10).value pt4z = application.activesheet.cells(r,c + 11).value pt4 = pt4x, pt4y, pt4z #add new face per this row new_face = entities.add_face pt1, pt2, pt3, pt4 end #advance loop to next row end end
-
Got an emergency to control SketchUp via a Visual Basic program for testing and design?
Open the SkecthUp console, give it focus manually.
Then just port some Ruby commands in, sending keys to the SU console title.
Private Sub Command5037_Click()
AppActivate ("Ruby Console")
Set WshShell = CreateObject("WScript.Shell")
WshShell.SendKeys "Testing" & vbCr 'etc, etc
End Sub -
@marthmatica said:
So as an example I did a SkecthUp cafe creator, driven from Excel face point data per row.
Maybe someone will find this useful, or a better way to do it, or improve my Ruby, since I am just starting on the Ruby end.
Ruby improved.
See new topic: [Code] Geometry Creation from Excel worksheet data
Advertisement