PDA

View Full Version : dotNet + MXS


Pages : [1] 2 3

erilaz
10-18-2007, 12:53 AM
In light of David Mackenzie's excellent Python+MXS (http://forums.cgsociety.org/showthread.php?f=98&t=509631) thread, I figured it would make sense to have a thread focused on dotNet as well. Admittedly this is mainly because i'm interested in using it right now, but any and all techniques about dotNet can be discussed here!

In addition, don't forget the beautiful piece of work that is Bobo's ongoing work with the Maxscript dotNet Resource (http://www.scriptspot.com/bobo/mxs9/dotNet/index.html) page.

ypuech
10-18-2007, 09:38 AM
dotNet + MXS = MXS++
With the addition of dotNet in MAXScript, you can now develop powerful tools that you never thought possible!

dotNet bridge in MAXScript is very useful to access .Net classes:
- .Net forms controls
- file access
- XML read/write
- GDI+
- DirectX Managed classes (video and audio)
- OS informations
- etc.

You can also create your own .Net classes and use them in script. This can be used to share components with your asset and workflow applications for example. Think also interop between your 3D applications (Maya wit Python, XSI with C# and 3ds Max with dotNet can now share components and communicate more easily).

I've recently released a small Avi Player developed in MAXScript and dotNet : http://ypuechweb.free.fr/avi_player.html. It uses DirectX Managed classes (video and audio) and a HScrollBar control (very useful because there's no equivalent in MAXScript).
I also began the translation to dotNet and GDI+ of the "How To ... Develop a Bitmap Painting Tool In Nine Easy Steps". GDI+ is powerful but sometimes (very) slow.
I'll release this doc and others (about XML access, some .Net forms controls and managed classes creation and use in script) in a couple of days/weeks :).

One of the limitation of the dotNet bridge is the impossibility to create and use managed arrays in MAXScript (corrected in Max 2008?).

PEN
10-18-2007, 12:50 PM
I'll see what I can constribute as well as I have been using dotNet for the project I have been working on and have been using treeView, ListView, calanders, XML and others to get the job done. dotNet is far better then what we had with active X.

PEN
10-18-2007, 03:04 PM
This is a timely thread. Can it please be made sticky?

I have an issue finaly that I can't resolve with a simple dotNetControl "system.windows.forms.textBox"

Some of the properties are not working as they should. The ones that I'm having issues with are acceptsTab and acceptsReturn, neither are having any affect on the control. multiLine has worked and I have also added scrollbars.

Any one used this before and have a solution?

ypuech
10-18-2007, 03:29 PM
I would suggest to call Focus() on the TextBox. I had such problems with a RichTextBox control (other solution, useful to format and colour the text) and resolved them by calling Focus().
If it's a multiline TextBox make sure the Multiline property is set to true.

PEN
10-18-2007, 03:34 PM
ypuech (http://forums.cgsociety.org/member.php?u=174808), can you explain to me what managed arrays are?

ypuech
10-18-2007, 04:35 PM
ypuech (http://forums.cgsociety.org/member.php?u=174808), can you explain to me what managed arrays are?
Managed arrays are the arrays from .Net framework. In MAXScript you can't handle them. For example:

local Array = dotNetObject "System.Windows.Forms.TreeNode[]" 5
-- With a previously defined TreeNode object
Array.Add Node -- Not possible to call Add method

PEN
10-18-2007, 05:59 PM
Thanks for the explanation on the arrays.

As for the focus() it didn't help at all.

Here is what I have...

rollout test "Test"
(
dotNetControl tb "system.windows.forms.textBox" height:80

on test open do
(
tb.multiLine=true
sb=dotNetClass "System.Windows.Forms.ScrollBars"
tb.scrollBars=sb.vertical
tb.acceptsReturn=true
tb.acceptsTab=true
tb.wordWrap=true
tb.focus()
)
)
createDialog test


Can any one get that to work?

Light
10-18-2007, 09:56 PM
Hi Paul,

Are you trying to set the focus to the textbox? If so, it works here.




Light

ypuech
10-18-2007, 10:06 PM
Well, in fact the Enter and Tab keys aren't working in the TextBox. Yes, the focus is set but we cannot go to the next line with Enter and use the Tab key. I *think* the messages are intercepted by the main window of 3ds Max.

erilaz
10-19-2007, 12:51 AM
This is a timely thread. Can it please be made sticky?


No worries. I actually thought I already had! :D

erilaz
10-19-2007, 01:15 AM
One thing i've been focusing on is the use of message boxes and all their meanings. Although I can call a messagebox (http://msdn2.microsoft.com/en-us/library/system.windows.forms.messagebox.aspx)with a simple text call via:

message = dotNetClass "System.Windows.Forms.MessageBox"
message.Show "Test"

I can't work out the call of the buttons. Do I need to have a separate object call to define the button properties in .Show? I think i'm getting the syntax confused.

specxor
10-19-2007, 07:41 AM
In light of David Mackenzie's excellent Python+MXS (http://forums.cgsociety.org/showthread.php?f=98&t=509631) thread, I figured it would make sense to have a thread focused on dotNet as well. Admittedly this is mainly because i'm interested in using it right now, but any and all techniques about dotNet can be discussed here!

In addition, don't forget the beautiful piece of work that is Bobo's ongoing work with the Maxscript dotNet Resource (http://www.scriptspot.com/bobo/mxs9/dotNet/index.html) page.


I don't no that I would say excellent! but ill take any complements I can get so thanks Martin. I am very excited about the this thread as I am using dotnet more and more in my scripts and am sure I will have lots of questions...

Moving on DotNet, I have some trouble creating a SQL connection in MXS. I have been trying to use System.Data.Odbc but have had no luck Im sure there is something simple i have to do to get this to work but I'm having a mental blank!

I am presuming that it should be some thing like db = dotNetClass "System.Data.Odbc"
but all I get is undefined... Any help would very much appreciated!


Cheers
Dave

ypuech
10-19-2007, 09:15 AM
Moving on DotNet, I have some trouble creating a SQL connection in MXS. I have been trying to use System.Data.Odbc but have had no luck Im sure there is something simple i have to do to get this to work but I'm having a mental blank!

I am presuming that it should be some thing like db = dotNetClass "System.Data.Odbc"
but all I get is undefined... Any help would very much appreciated!


Cheers
Dave
System.Data.Odbc is a namespace name, not a class name.

I've not much experience with Database usage but I looked at the MSDN documentation and found some examples.

Here is one:
connectionString = "Driver={SQL Native Client};Server=(local);Trusted_Connection=Yes;Database=AdventureWorks;"

connection = dotNetObject "System.Data.Odbc.OdbcConnection" connectionString
connection.Open()

You can have a look at :
the namespace documentation : http://msdn2.microsoft.com/en-us/library/system.data.odbc.aspx
this tutorial : http://www.functionx.com/vbnet/odbc/paradox.htm

PEN
10-19-2007, 12:06 PM
Hi Paul,

Are you trying to set the focus to the textbox? If so, it works here.
Light

Thanks but it is the tab and enter and I think that I have come to the same conclusion as ypuech, Max must be interfering with the operation. I'm just going to live with it at the moment as I have bigger things to deal with.

ypuech
10-19-2007, 03:07 PM
Thanks but it is the tab and enter and I think that I have come to the same conclusion as ypuech, Max must be interfering with the operation. I'm just going to live with it at the moment as I have bigger things to deal with.
It's a strange bug because if you print the key pressed in the KeyPressed event you can see the Enter and Tab keys:

on tb keyPress senderArg keyPressEventArgs do
(
print keyPressEventArgs.keyChar
)

Light
10-19-2007, 04:17 PM
Maybe give Windows.Forms a try instead of maxscript dialogs? I might solve it I think, although I never tried.




Light

PEN
10-19-2007, 07:32 PM
Maybe give Windows.Forms a try instead of maxscript dialogs? I might solve it I think, although I never tried.

Light

I am using "system.windows.forms.textBox" Are you thinking of something else?

Kameleon
10-19-2007, 08:20 PM
specxor:

You have to do dotnet.loadassembly "System.Data" first. I have some code at work that may be of use to you.

And by the way... does anyone knows why the listbox doesnt display any info in a dataset?

I've sucessefully created a dataset, a table adapter, I can access the values on the rows, but after assigning the Datasource and Displaymember, the listbox remains empty... cant figure that out.

I dont have Max 9 here so I'll write what I can remember :D It's something like this

(
rollout rollmain "dotnet"
(
dotnetcontrol lst_test "System.Windows.Forms.Listbox" width:290 height:290 align:#center

on rolmain open do
(
dotnet.loadassembly "System.Data"

constring="data source=.\SQLEXPRESS;Initial Catalog=YOUR_DATABASE_HERE;Integrated Security=True;Connect Timeout=30"
con=dotnetobject "System.Data.SqlClient.SqlConnection" constring

dataset=dotnetobject "System.Data.Dataset"
tableadapter=dotnetobject "System.Data.SqlClient.SqlDataAdapter" "SELECT * FROM tasks" constring

tableadapter.Fill dataset "tasks"

--At this point you have your data into the dataset created before
--Now the problem seems to be with the listbox databinding... cant understand why

lst_test.Datasource=dataset.tables["tasks"]
lst_test.DisplayMember="taskname" --This is the column name used for displaying data and I thing the problem is here somewhere...
lst_test.ValueMember="id_task" -- Primary key column

--if you want to confirm the data in your dataset you could do this loop. This shows that the problem is not getting the data into the dataset but displaying it in the listbox

for i=0 to dataset.tables["tasks"].rows.count do -- it's this or dataset.tables["tasks"].rows.items.count, can't quite remember
(
print dataset.tables["tasks"].rows.item[i].item["taskname"] --I'm not sure about this one, but a ShowProperties on dataset.tables["tasks"] should help a little
)

)
)
createdialog rollmain 300 300
)


And that's about it, hope this helps and if someone knows why the listbox is not displaying my data please say something! Cyas!

Light
10-19-2007, 08:48 PM
Yes, I was thinking about:

frmMain = dotNetObject "System.Windows.Forms.Form"
frmMain.Show()

Doesn't have some abilities of the maxscript rollout like docking inside the Max UI, but it behaves like a standalone UI.




Light

ypuech
10-19-2007, 11:19 PM
Yes, I was thinking about:

frmMain = dotNetObject "System.Windows.Forms.Form"
frmMain.Show()

Doesn't have some abilities of the maxscript rollout like docking inside the Max UI, but it behaves like a standalone UI.

Yes it can be a solution.
Here is a way of creating a .Net form containing a TextBox that looks visually similar to a a MAXScript dialog. One of the main difference is that the form cannot get messages when the main Max window is minimized, maximized, resized etc. It's always displayed even if Max is minimized for example.You can set the parent if you create this form in C++/CLI in a plugin but not in MAXScript (it would be interesting to create a small patch to the dotNet bridge...).

Here is the code:
(
-- Create TextBox
hTextBox = dotNetObject "System.Windows.Forms.TextBox"
hTextBox.Location = dotNetObject "System.Drawing.Point" 10 10
hTextBox.Width = 280
hTextBox.Height = 280
hTextBox.Visible = true
hTextBox.MultiLine = true
ScrollBars = dotNetClass "System.Windows.Forms.ScrollBars"
hTextBox.ScrollBars = ScrollBars.Vertical
hTextBox.AcceptsReturn = true
hTextBox.AcceptsTab = true
hTextBox.WordWrap = true

-- Create Form
hForm = dotNetObject "System.Windows.Forms.Form"
hForm.Size = dotNetObject "System.Drawing.Size" 310 335
hForm.Text = ".Net 2.0 Form with TextBox"
hForm.Controls.Add(hTextBox)
hForm.TopMost = true
FormBorderStyle = dotNetClass "System.Windows.Forms.FormBorderStyle"
hForm.FormBorderStyle = FormBorderStyle.FixedDialog
hForm.ShowInTaskbar = false
hForm.MinimizeBox = false
hForm.MaximizeBox = false

-- Set appropriate Form background color
maxBackColor = colorMan.getColor #background
Color = dotNetClass "System.Drawing.Color"
hForm.BackColor = Color.FromArgb (maxBackColor[1] * 255.0f) (maxBackColor[2] * 255.0f) (maxBackColor[3] * 255.0f)

-- Show application Form
hApp = dotNetClass "System.Windows.Forms.Application"
hApp.Run hForm
)

Also, App.Run() is better than Form.Show() because it initializes well the dialog and the keyboard handling. With Form.Show(), Max intercepts all the keyboard messages when writting in the TextBox...

relief7
10-22-2007, 01:22 AM
Hi !

I am following Erilaz's suggestion from another thread about message boxes. He asked me to paste a small test of mine with .NET standard dialog boxes into this thread as well. It is very basic and self-explanatory and could be useful if one needs those "fancy" icons or more functionality than the standard MaxScript messageBox(). :)

Overall I am just getting into the whole .NET thing and I really love it ! It is so easy to get more functionality without all the cryptic ActiveX stuff. I remember that we used a RegEx class as well in C# some time back. Imagine having regular expressions in MaxScript or easy Database access, XML writing/parsing in MAXScript. Yay !!! :bounce:

Ok so here is my humble contribution. I hope it helps someone get started... :)

/*
----------------------------------------------------------
System.Windows.Forms.MessageBoxButtons (Enumeration)
----------------------------------------------------------
.AbortRetryIgnore
.OK
.OKCancel
.RetryCancel
.YesNo
.YesNoCancel

----------------------------------------------------------
System.Windows.Forms.MessageBoxDefaultButton (Enumeration)
----------------------------------------------------------
.Button1
.Button2
.Button3

----------------------------------------------------------
System.Windows.Forms.MessageBoxIcon (Enumeration)
----------------------------------------------------------
.Asterisk
.Error
.Exclamation
.Hand
.Information
.None
.Question
.Stop
.Warning

----------------------------------------------------------
MessageBox.show (Method)
----------------------------------------------------------
MessageBox.show ( text, caption, buttons, icon, defaultButton )

*/

(
-- setup dotnet classes / objects
local mb = dotNetClass "System.Windows.Forms.MessageBox"
local buttons = dotNetClass "System.Windows.Forms.MessageBoxButtons"
local icons = dotNetClass "System.Windows.Forms.MessageBoxIcon"
local defaultButton = dotNetClass "System.Windows.Forms.MessageBoxDefaultButton"
local dialogResult = dotNetClass "System.Windows.Forms.DialogResult"

local result = mb.show "Do you want to save before quitting ?" "Quit" buttons.YesNoCancel icons.Information defaultButton.Button3

-- evaluate result of messageBox (which button has been pressed by the user)
if ( result == dialogResult.Yes ) then
(
format "YES\n"
)
else if ( result == dialogResult.No ) then
(
format "NO\n"
)
else if ( result == dialogResult.Cancel ) then
(
format "CANCEL\n"
)

)

Btw, is anybody using a version control system for their scripts ? I recently setup a SVN and Apache server and I organized all my scripts into a system-independent directory structure. This way I can check out everything that is needed ( encrypted over SSH ) wherever the work place is (of course web access is required). It is pretty practical and wonder now why I have not installed something like that for such a long time... No more synchronisation between different computers required.

Just as a hint for someone who ( like me ) struggled organizing their files ! :) If someone has other thoughts about organizing their tools I would really love to hear how you handle it. No thread hijacking intended though.

Kameleon
10-22-2007, 02:00 PM
Here's the code for displaying data in a listbox.... But I still can't use DataSource and DisplayMember... it simply doesn't work, any help on that would be great!



(

rollout rolmain "Dotnet"

(



dotNetControl lst_test "System.Windows.Forms.Listbox" width:250 height:150 align:#center



on rolmain open do

(

dotnet.loadassembly "System"

constring = "data source=.\SQLEXPRESS;Initial Catalog=YOUR_DATABASE_HERE;Integrated Security=True;Connect Timeout=30"

con = dotNetObject "System.Data.SqlClient.SqlConnection" constring



dataset = dotNetObject "System.Data.Dataset"

tableadapter = dotNetObject "System.Data.SqlClient.SqlDataAdapter""SELECT * FROM tasks" constring

tableadapter.fill dataset "tasks"



--lst_test.DataSource = dataset.tables.item["tasks"]

--lst_test.DisplayMember = dotNetObject "System.String" "taskname"



for i=0 to dataset.tables.item["tasks"].rows.count-1 do

(

lst_test.items.Add (dotnetobject "System.String" dataset.tables.item["tasks"].rows.item[i].item["taskname"])

)

)

)



createDialog rolmain 300 300

)

Kameleon
10-22-2007, 06:37 PM
Well I think I've found something, I've created a form and used the listbox there, with the datasource, displaymember etc etc and it worked just fine... seems like a limitation when using the listbox inside a rollout or something...

PEN
10-23-2007, 07:59 PM
This is all realy good information guys. Looks like dotNet has some limitations if you include them with Max rollouts. Right now my tool is to far along to go back as I have to get it done but I will try a full dotNet UI next time and see what can be done.. or not.

thatoneguy
10-24-2007, 08:18 PM
Does anybody know of a resource online that lists a whole gaggle of different .net interface items all in one script with a simple action for each? Kind of like in the Maxscript documentation with every single interface item.

I would like to redo the Volumes interface in .net but I don't really know where to start. If I can see a working script I'm very adept at reverse engineering.

PEN
10-25-2007, 02:40 PM
There is information in the Max help that covers how to set up .net controls. Have a look for converting axcontrols to .net and you should find it.

To get a list of everything that you can do with .net you will need to visit MSDN and look for the .net class library. Specificly to locate the UI items you will need to look up system.windows.forms and go from there. Here is a direct link to it.

http://msdn2.microsoft.com/en-us/library/system.windows.forms.aspx

Do the help files in the Max scritp help and then start looking at MSDN and it will start to make some sense.

JHN
10-25-2007, 04:04 PM
Btw, is anybody using a version control system for their scripts ? I recently setup a SVN and Apache server and I organized all my scripts into a system-independent directory structure. This way I can check out everything that is needed ( encrypted over SSH ) wherever the work place is (of course web access is required). It is pretty practical and wonder now why I have not installed something like that for such a long time... No more synchronisation between different computers required.

Just as a hint for someone who ( like me ) struggled organizing their files ! :) If someone has other thoughts about organizing their tools I would really love to hear how you handle it. No thread hijacking intended though.

I created a new thread (http://forums.cgsociety.org/showthread.php?p=4733970#post4733970) about code management, I'm very interrested in your setup, as I use turtoise svn for my code.

-Johan

thatoneguy
10-25-2007, 07:09 PM
Is it possible to use a visual .Net forms tool and then import that code into Max? A .net IDE of some sort?

ypuech
10-25-2007, 09:20 PM
Is it possible to use a visual .Net forms tool and then import that code into Max? A .net IDE of some sort?
The code generated by a Form designer is in C# or VB.NET so you have to convert it to MAXScript. The conversion is generally easy to implement; cf. the code I posted above.

thatoneguy
10-25-2007, 10:04 PM
Yeah that's actually the part I'm having the most trouble with right now. I don't really know C#, JScript or Vbasic so converting the syntax is challenging :D

I did find this. And it's handy. Some form items like radiobuttons are pretty obvious but what to call a spinner based on a picture is useful.

http://www.oreillynet.com/wireless/2004/01/07/graphics/image002.jpg

Anywhere I see "new" in C# or VJ# I should replace that with 'dotnetobject'? Seems to be working as a general rule so far...


Edit:
Good DataGrid reference:
http://samples.gotdotnet.com/quickstart/aspplus/samples/webforms/ctrlref/webctrl/datagrid/doc_datagrid.aspx

ypuech
10-25-2007, 10:18 PM
Some form items like radiobuttons are pretty obvious but what to call a spinner based on a picture is useful.

http://www.oreillynet.com/wireless/2004/01/07/graphics/image002.jpg
Spinner in .Net Forms are called NumericUpDown.

Anywhere I see "new" in C# or VJ# I should replace that with 'dotnetobject'? Seems to be working as a general rule so far...
Yes, this is a good rule. And you have to use dotNetClass to get static classes, enumerations.

thatoneguy
10-25-2007, 11:38 PM
Ok I'm really stuck.

I can't for the life of me figure out how to insert columns (or rows) into a datagrid.

I did get tabs working but can't figure out how to fill out my datagrid.


(
Color = dotNetClass "System.Drawing.Color"
ScrollBars = dotNetClass "System.Windows.Forms.ScrollBars"

-- Create Tabs Container
tabControl1 = dotnetobject "system.windows.forms.TabControl"
tabControl1.size = dotnetobject "system.drawing.size" 395 195
tabControl1.Location = dotnetobject "System.Drawing.Point" 0 0

--Create Tabs
tabPage1 = dotnetobject "System.Windows.Forms.TabPage"
tabPage1.text = "Goodbye World"
tabPage2 = dotnetobject "System.Windows.Forms.TabPage"
tabPage2.text = "Hello World"
tabPage1.backColor = color.fromArgb 200 200 200
tabPage2.backColor = color.fromArgb 200 200 200

-- Create Datagrid


DGrid1 = dotnetobject "System.Windows.Forms.DataGrid"
DGrid1.Location = dotNetObject "System.Drawing.Point" 10 10
DGrid1.Width = 365
DGrid1.Height = 120
DGrid1.Visible = true


-- Add Some Columns to the Datagrid
dt = dotnetobject "system.data.datatable"
Column1 = dotnetclass "System.windows.data.DataColumn"

-- Create TextBox
TB1TextBox = dotNetObject "System.Windows.Forms.TextBox"
TB1TextBox.Location = dotNetObject "System.Drawing.Point" 10 10
TB1TextBox.Width = 365
TB1TextBox.Height = 120
TB1TextBox.Visible = true
TB1TextBox.MultiLine = true
TB1TextBox.ScrollBars = ScrollBars.Vertical
TB1TextBox.AcceptsReturn = true
TB1TextBox.AcceptsTab = true
TB1TextBox.WordWrap = true

-- Create Buttons
button01 = dotnetobject "System.Windows.Forms.button"
button01.text = "goodbye"
button01.Location = dotNetObject "System.Drawing.Point" 300 138

-- Create Form
TabForm = dotNetObject "System.Windows.Forms.Form"
TabForm.Size = dotNetObject "System.Drawing.Size" 400 225
TabForm.Text = "Title"
TabForm.TopMost = true
FormBorderStyle = dotNetClass "System.Windows.Forms.FormBorderStyle"
TabForm.FormBorderStyle = FormBorderStyle.FixedDialog
TabForm.ShowInTaskbar = false
TabForm.MinimizeBox = true
TabForm.MaximizeBox = false
Tabform.helpbutton = true

-- Add UI elements to Tabs
tabpage1.controls.add(TB1textbox)
tabpage1.controls.add(button01)
tabpage2.controls.add(DGrid1)

-- Add Tabs to Tab Container
tabcontrol1.controls.add(tabpage1)
tabcontrol1.controls.add(tabpage2)
-- Add Tab Container to UI Form
TabForm.Controls.Add(tabcontrol1)
-- Show application Form
TTApp = dotNetClass "System.Windows.Forms.Application"
TTApp.Run TabForm
)

Kameleon
10-26-2007, 04:46 PM
There you go dude, I've managed to add columns and rows, although I figured out how to use the System.Data.Datarow to declare a row and ended up using the NewRow... but after that I could't change the values as in something like row.items["id"]=i that didnt work, dont know why... and I ended up creating an array and adding that up to the datatable, seems to work fine. Cya and if anyone knows how to declare that row thingie please explain!


(

dotnet.loadassembly "System.Data"



Color = dotNetClass "System.Drawing.Color"

ScrollBars = dotNetClass "System.Windows.Forms.ScrollBars"



-- Create Tabs Container

tabControl1 = dotnetobject "system.windows.forms.TabControl"

tabControl1.size = dotnetobject "system.drawing.size" 395 195

tabControl1.Location = dotnetobject "System.Drawing.Point" 0 0



--Create Tabs

tabPage1 = dotnetobject "System.Windows.Forms.TabPage"

tabPage1.text = "Goodbye World"

tabPage2 = dotnetobject "System.Windows.Forms.TabPage"

tabPage2.text = "Hello World"

tabPage1.backColor = color.fromArgb 200 200 200

tabPage2.backColor = color.fromArgb 200 200 200



-- Add Some Columns to the Datagrid

dt = dotnetobject "system.data.DataTable""Test"

Column1 = dotnetobject "System.Data.DataColumn" "id" (dotnetclass "System.Int32")

Column2 = dotnetobject "System.Data.DataColumn" "Name" (dotnetclass "System.String")

dt.columns.add Column1

dt.columns.add Column2



for i=0 to 2 do

(

row=#(dotnetobject "System.Int32" i,dotnetobject "System.String" (i as string))

dt.rows.add row

)



-- Create Datagrid

DGrid1 = dotnetobject "System.Windows.Forms.DataGrid"

DGrid1.Location = dotNetObject "System.Drawing.Point" 10 10

DGrid1.Width = 365

DGrid1.Height = 120

DGrid1.Visible = true

DGrid1.DataSource = dt



-- Create TextBox

TB1TextBox = dotNetObject "System.Windows.Forms.TextBox"

TB1TextBox.Location = dotNetObject "System.Drawing.Point" 10 10

TB1TextBox.Width = 365

TB1TextBox.Height = 120

TB1TextBox.Visible = true

TB1TextBox.MultiLine = true

TB1TextBox.ScrollBars = ScrollBars.Vertical

TB1TextBox.AcceptsReturn = true

TB1TextBox.AcceptsTab = true

TB1TextBox.WordWrap = true



-- Create Buttons

button01 = dotnetobject "System.Windows.Forms.button"

button01.text = "goodbye"

button01.Location = dotNetObject "System.Drawing.Point" 300 138



-- Create Form

TabForm = dotNetObject "System.Windows.Forms.Form"

TabForm.Size = dotNetObject "System.Drawing.Size" 400 225

TabForm.Text = "Title"

TabForm.TopMost = true

FormBorderStyle = dotNetClass "System.Windows.Forms.FormBorderStyle"

TabForm.FormBorderStyle = FormBorderStyle.FixedDialog

TabForm.ShowInTaskbar = false

TabForm.MinimizeBox = true

TabForm.MaximizeBox = false

Tabform.helpbutton = true



-- Add UI elements to Tabs

tabpage1.controls.add(TB1textbox)

tabpage1.controls.add(button01)

tabpage2.controls.add(DGrid1)



-- Add Tabs to Tab Container

tabcontrol1.controls.add(tabpage1)

tabcontrol1.controls.add(tabpage2)

-- Add Tab Container to UI Form

TabForm.Controls.Add(tabcontrol1)

-- Show application Form

TTApp = dotNetClass "System.Windows.Forms.Application"

TTApp.Run TabForm

)

erilaz
10-30-2007, 12:35 AM
This is sort of spinning off from another thread (http://forums.cgsociety.org/showthread.php?f=98&t=555276), but it seems best to discuss it here. Can we talk about overall dotNet declaration?

A standard way to access a method is to call it's class:

myFile = dotNetClass "System.IO.File"
myFile.methodInQuestion


The tricky part is handling all the things that go along with that. For example, relief7 has a large list of local class declarations for interface elements before anything can be build with the messagebox .show() method:

-- setup dotnet classes / objects
local mb = dotNetClass "System.Windows.Forms.MessageBox"
local buttons = dotNetClass "System.Windows.Forms.MessageBoxButtons"
local icons = dotNetClass "System.Windows.Forms.MessageBoxIcon"
local defaultButton = dotNetClass "System.Windows.Forms.MessageBoxDefaultButton"
local dialogResult = dotNetClass "System.Windows.Forms.DialogResult"


Is there a simple explanation of when you need to call something as an object, property or method as opposed to just accessing it via a call you made previously?

Seeing as it was an interesting exercise, here's the thread that resolved my issue in regards to reading tick values from a LastWriteTime property:
http://forums.cgsociety.org/showthread.php?f=98&t=555276

ypuech
10-30-2007, 10:19 AM
A standard way to access a method is to call it's class:

myFile = dotNetClass "System.IO.File"
myFile.methodInQuestion


The tricky part is handling all the things that go along with that. For example, relief7 has a large list of local class declarations for interface elements before anything can be build with the messagebox .show() method:

-- setup dotnet classes / objects
local mb = dotNetClass "System.Windows.Forms.MessageBox"
local buttons = dotNetClass "System.Windows.Forms.MessageBoxButtons"
local icons = dotNetClass "System.Windows.Forms.MessageBoxIcon"
local defaultButton = dotNetClass "System.Windows.Forms.MessageBoxDefaultButton"
local dialogResult = dotNetClass "System.Windows.Forms.DialogResult"


Is there a simple explanation of when you need to call something as an object, property or method as opposed to just accessing it via a call you made previously?
MessageBoxButtons, MessageBoxIcon, MessageBoxDefaultButton and DialogResult are enumerations so it's not needed to create an object; just get their values. It's the same for the static Show() method of a MessageBox.
A static member belongs to the class rather than to the objects of the class. Static members are also known as class members and non-static members are known as instance members.

dotNetObject is used in the same manner than C# constructor new() :

C# code
FileInfo fileInfo = new FileInfo(fileName);

Equivalent MAXScript code:
fileInfo = dotNetObject "System.IO.FileInfo" fileName

So, when a value is returned from a method, there's no need to worry about its creation.

ypuech
10-30-2007, 11:43 PM
I just discovered that in 3ds Max 2008 there's a .Net SDK including an assembly that contains specific UI controls for use in Max. And a MaxForm class was developed so now we can use it in Max 2008 instead of standard "System.Windows.Forms.Form".

My previously example with the .Net Form TextBox (http://forums.cgsociety.org/showpost.php?p=4722595&postcount=21) can now be coded as this under Max 2008:

(
-- Load MaxCustomControls assembly
-- This assembly contains UI components built on the .NET Framework for use in 3ds Max
dotNet.loadAssembly "MaxCustomControls.dll"

-- Create TextBox
hTextBox = dotNetObject "System.Windows.Forms.TextBox"
hTextBox.Location = dotNetObject "System.Drawing.Point" 10 10
hTextBox.Width = 280
hTextBox.Height = 280
hTextBox.Visible = true
hTextBox.MultiLine = true
ScrollBars = dotNetClass "System.Windows.Forms.ScrollBars"
hTextBox.ScrollBars = ScrollBars.Vertical
hTextBox.AcceptsReturn = true
hTextBox.AcceptsTab = true
hTextBox.WordWrap = true

-- Create Max Form
hMaxForm = dotNetObject "MaxCustomControls.MaxForm"
hMaxForm.Size = dotNetObject "System.Drawing.Size" 310 335
hMaxForm.Text = "Max Form with TextBox"
hMaxForm.Controls.Add(hTextBox)
hMaxForm.TopMost = true
FormBorderStyle = dotNetClass "System.Windows.Forms.FormBorderStyle"
hMaxForm.FormBorderStyle = FormBorderStyle.FixedDialog
hMaxForm.ShowInTaskbar = false
hMaxForm.MinimizeBox = false
hMaxForm.MaximizeBox = false

-- Show MaxForm
hMaxForm.ShowModeless()
)


All the UI events from Max main window (it's the parent window of the form) are now correctly handled by the MaxForm.

This is a first example of the use of these assemblies primarly developed for use in plugin code but I think they are also very useful at scripting :).

Light
10-31-2007, 12:05 AM
Autodesk guys wrote these assemblies for Scene Explorer which is mostly coded in C# but hooked into Max using C++/SLI.




Light

RustyKnight
10-31-2007, 01:14 AM
I recently came across the problem of needing to let the artests in out studio select multiple files to perform operations on within my script.

I started out using the max getOpenFileName function, but soon discovered that it does not provide for multiple selections...a bit of a problem when dealing with a large number of files...So I thought I'd see what dn could do for me.

So after some time spent reading through the msdn docs, I came up with this...
local ofd = dotnetobject "System.Windows.Forms.OpenFileDialog"
ofd.Filter = "XML Files (*.xml)|*.xml"
ofd.RestoreDirectory = false
ofd.multiselect = true

if ofd.showDialog() == (dotNetClass "System.Windows.Forms.DialogResult").OK then (
local sFile = ofd.fileNames
-- Process the file array here...
)It seems to have worked quite well for what I need.

I hope it helps some one :)

Shane

PEN
10-31-2007, 01:11 PM
I would like to compile a list of dotNet controls and classes that people are finding usful here and post it on my site with the test code that is being shown here. Does any one have a problem with me using the test code right from here so that I don't have to rewrite it? I will post links to the origainal authors of the code if they have sites as well.

It would be good if we had a reference page of useful tid bits that others can start to reference.

erilaz
10-31-2007, 01:22 PM
I would like to compile a list of dotNet controls and classes that people are finding usful here and post it on my site with the test code that is being shown here. Does any one have a problem with me using the test code right from here so that I don't have to rewrite it? I will post links to the origainal authors of the code if they have sites as well.

It would be good if we had a reference page of useful tid bits that others can start to reference.

I'd prefer it to be translated over to the cgWiki (http://wiki.cgsociety.org/) like the geometrical calculations thread has been, but it's your call. It would be great to be able to cross-reference it with stuff like this.

JHN
10-31-2007, 03:15 PM
Why not do it both? I like Pauls site and have it under my favourites... I never seem to get around wiki's, don't understand the navigation of these things... :shrug:

-Johan

erilaz
10-31-2007, 03:46 PM
Why not do it both? I like Pauls site and have it under my favourites... I never seem to get around wiki's, don't understand the navigation of these things... :shrug:

-Johan

I certainly have no problem with that, I'm just doing my job as a wiki/max moderator. :D

Kameleon
10-31-2007, 08:28 PM
While my brain was melting after a major commercial I did this to include in my scripts, it's a .ms file with class declarations to help the programming of .Net stuff, after that I've created a small script to enumerate all the variables assigned in that file... the files are quite self-explanatory.

I also added a variable called New that executes the string "dotNetObject" so when we want to create some object we can do something simple as textbox = new dotNetTextBox. There's still so much thing to add but that's the basic stuff I've seen on MSDN.

I'll add more as I need and you can also do the same, just keep the same structure, so when you run the Enumerate script it creates a .txt file with all the correct declarations and it's easier to share with others updated versions of the file. Hope you like it and feel free to download and improve it! Cya

PS - Both files need to be in the same directory.

RustyKnight
10-31-2007, 11:30 PM
I would like to compile a list of dotNet controls and classes that people are finding usful here and post it on my site with the test code that is being shown here. Does any one have a problem with me using the test code right from here so that I don't have to rewrite it? I will post links to the origainal authors of the code if they have sites as well.

It would be good if we had a reference page of useful tid bits that others can start to reference.Knock yourself out! I think it's great idea...the forum can get a little messy from time to time

Shane

thatoneguy
11-02-2007, 05:17 PM
Yes Please. I have a maxscript file which I'm making with as much .net as humanely possible in one script as I learn so that I have a clipboard to copy paste code snipets from and reference.

A community effort would be very useful since .net is very very sparsely documented in the help and translating C# into maxscript syntax is for me a trial and error process.

Anubis
12-03-2007, 10:42 AM
Has anyone gotten something like a contextual menu to work?

I can do something like:
contextMenu = dotNetObject "System.Windows.Forms.ContextMenu"

But when it comes to creating it, I am unsure how to do that

contextmenu.Show(trackview,arg.location)

CE

ypuech
12-03-2007, 10:58 AM
Has anyone gotten something like a contextual menu to work?

I can do something like:
contextMenu = dotNetObject "System.Windows.Forms.ContextMenu"

But when it comes to creating it, I am unsure how to do that

contextmenu.Show(trackview,arg.location)
A .NET Forms ContextMenu can only be shown over a .NET Forms control. Is trackview a .NET Forms control ?

Anubis
12-03-2007, 11:42 AM
I have this working, but I don't know how to get the selected item back.. will update when i figure it out.

on tv nodeMouseClick arg do
(
if arg.button == tv.mousebuttons.right then
(
contextMenu = dotNetObject "System.Windows.Forms.ContextMenu"
contextMenu.MenuItems.Add("Select all children")
contextMenu.MenuItems.Add("Expand branches")
pointTest = (dotNetObject "System.Drawing.Point" arg.x arg.y)
contextmenu.Show tv pointTest
)
)
http://ChrisEvans3D.com/temp/contextual.png

Anubis
12-03-2007, 06:51 PM
Got it with some help from my friend MarcoK!

fn OnClick sender args =
(
--print sender.Text
case sender.Text of
(
"Expand branches": if tv.selectedNode != undefined then tv.selectedNode.ExpandAll()
)
)

on tv nodeMouseClick arg do
(
if arg.button == tv.mousebuttons.right then
(
contextMenu = dotNetObject "System.Windows.Forms.ContextMenu"
contextMenu.MenuItems.Clear()
dotnet.addeventhandler (contextMenu.MenuItems.Add("Select all children")) "Click" OnClick
dotnet.addeventhandler (contextMenu.MenuItems.Add("Expand branches")) "Click" OnClick
pointTest = (dotNetObject "System.Drawing.Point" arg.x arg.y)
contextmenu.Show tv pointTest
)
)

JHN
12-06-2007, 03:38 PM
I finally went on and picked up on dotnet. It's not as hard as I thought :)
But I do have a refresh problem. I do an label edit and with the "AfterLabelEdit" eventhandler I update the listview i have. The problem I have is that
listview.items.clear() works but appearantly not for the label that was edited...!?

I create an extra refresh button and after pressing that it does work... The edited label simply renames an object. It looks like after renaming the script is faster to update the labels than max with renaming the object... any suggestions?

Also, is listview the right way to go when I want to also edit the other fields in a row? It looks like I can't but maybe I'm missing something?

Thanx!
-Johan

RustyKnight
12-06-2007, 07:57 PM
I finally went on and picked up on dotnet. It's not as hard as I thought :)
But I do have a refresh problem. I do an label edit and with the "AfterLabelEdit" eventhandler I update the listview i have. The problem I have is that
listview.items.clear() works but appearantly not for the label that was edited...!?

I create an extra refresh button and after pressing that it does work... The edited label simply renames an object. It looks like after renaming the script is faster to update the labels than max with renaming the object... any suggestions?

Also, is listview the right way to go when I want to also edit the other fields in a row? It looks like I can't but maybe I'm missing something?

Thanx!
-JohanFor the label edit, I don't have an immediate solution...as for editing the other columns, you can't do it...well actually there is a hack, but I don't think we have enough access into dotnet via maxscript to get it to work.

The listview only allows for the editing of the first column. If you want to update the other columns, I suggest having a look at one of the grids. That should provide you with the ability to edit the cells.

I've been poking at the idea of writting my user interfaces in Java and using the COM access to send commands back to Max. I know the COM part works, but I've not had much time to look into the rest...but this is for a very particular idea...

Shane

PEN
12-06-2007, 08:23 PM
To edit the other fields you can get the placment of the mouse over the field and determine which it is. Then move and editText field to that location for the user to imput information into.

A hack but it works.

RustyKnight
12-06-2007, 10:09 PM
To edit the other fields you can get the placment of the mouse over the field and determine which it is. Then move and editText field to that location for the user to imput information into.

A hack but it works.How do you get a reference to the editfield? Do you create own? How do you place it within the control??

All the code I've seen that does this seems to rely on obtaining window handles...?!?

Shane

JHN
12-07-2007, 09:48 AM
Hi Paul / Shane, thanks for that I will look into it! If it isn't what I want or too much of a hack, which datagrid object would you suggest? The thing I need is almost like the new max2008 scene explorer.

Here's a script snippet, too demonstrate that the label is not updating.. any suggestions are welcome!

http://scripts.subd.nl/?f=JHN_dotnetCamList.ms

Create some camera's, run the script. Rename camera via label by clicking a label and wait a sec. Then edit and hit enter or click outside. The object gets renamed properly, the list gets updated and the renamed object moves to the right location. Although the labelplace where the object was doesn't seem to follow along... bit hard to exlpain, please have a look.

Cheers,
-Johan

(I'll be gone for 2 days so if I don't respond it's not because I don't care, cause I do ;) )

PEN
12-12-2007, 08:22 PM
I have been using "system.IO.file" for managing files how ever I'm stuck on setting permissions on a file and how to set it to readOnly. Any one know where I should be looking?

PEN
12-12-2007, 08:23 PM
Oh and does any one know where I can down load the .net library from MSDN so speed up searches?

RustyKnight
12-12-2007, 10:22 PM
I have been using "system.IO.file" for managing files how ever I'm stuck on setting permissions on a file and how to set it to readOnly. Any one know where I should be looking?You'll have to forgive the code, I pulled it directly from the MSN docs, butFile.SetAttributes(path, File.GetAttributes(path) Or FileAttributes.ReadOnly) should be able to set the attribute
andIf (File.GetAttributes(path) And FileAttributes.ReadOnly) = FileAttributes.ReadOnlyThenshould return true if the file is readonly.

Shane

RustyKnight
12-12-2007, 10:23 PM
Oh and does any one know where I can down load the .net library from MSDN so speed up searches?I know a version comes with Visual Studio, it's what I use. If someone can tell me if I'm allowed to "upload" it here, I will.

Shane

PEN
12-12-2007, 10:31 PM
I'll have a poke, thanks.

Kenzor
12-13-2007, 09:43 PM
I been updating my code to use dotNet, and found an easy way to get the index of the subitem clicked


--lv is the DotNetListView object

fn subItemAtMousePos =
(
pos = lv.mousePosition -- screen position
pos = lv.PointToClient pos -- position in listview window

li = lv.getItemAt pos.x pos.y

si = li.getSubItemAt pos.x pos.y
#( li.index , (li.subitems.indexof si) )
),

on lv click arg do
(
theCell = subItemAtMousePos()
format "cell index X: % Y: %" theCell[1] theCell[2]

)

scorpion007
12-14-2007, 01:28 AM
Do you mean the documentation for the library? If so, I'm pretty sure either the Platform SDK or the .NET SDK docs come with it. I think the .NET SDK actually comes with the platform SDK, so if you get that, you should get a local copy of all the docs.
(The Platform SDK actually got renamed to Windows SDK recently, so check either search term if you don't find it)

RustyKnight, uploading it is a bit big ain't it? 600 or so MB?

PEN
12-17-2007, 05:22 PM
K another one that I cant sus out from MSDN, "system.dateTime" I want to be able to create a date time of my choosing.

I can use it to get the .now property but I want to set a dateTime from string values that I have. I would like to build it with year, month, day, hour, min, sec values.

Any idea on how I go about that?

ypuech
12-17-2007, 10:16 PM
K another one that I cant sus out from MSDN, "system.dateTime" I want to be able to create a date time of my choosing.

I can use it to get the .now property but I want to set a dateTime from string values that I have. I would like to build it with year, month, day, hour, min, sec values.

Any idea on how I go about that?
Take a look at all the constructors available for a DateTime value at http://msdn2.microsoft.com/en-us/library/system.datetime.datetime(VS.80).aspx. You can build your own date value from these methods.

For example, this example uses the constructor DateTime (Int32, Int32, Int32) (year/month/day):
today = dotNetObject "System.DateTime" 2007 12 17

RustyKnight
12-17-2007, 10:31 PM
K another one that I cant sus out from MSDN, "system.dateTime" I want to be able to create a date time of my choosing.

I can use it to get the .now property but I want to set a dateTime from string values that I have. I would like to build it with year, month, day, hour, min, sec values.

Any idea on how I go about that?Hi Pen!

The typical method I would use would be to parse the string to a date value...obviously, the question is how.

I had a quick look at System.DateTime and found a number of parse methods.

Unfourtantly, I don't know how to call static methods from inside max, so I took a look at the constructor values. I found the following constructor that would suit your needs:

DateTime (http://forums.cgsociety.org/T_System_DateTime.htm)(year, month, day, hour, minute, second)


And the test code...
local dnDateTime = dotNetObject "System.DateTime" 1972 03 08 18 30 0

-- prints "8/03/1972 6:30:00 PM" -- Australian
format "%\n" (dnDateTime.toString())
Hope it helps

Shane

ypuech
12-17-2007, 11:20 PM
I had a quick look at System.DateTime and found a number of parse methods.

Unfourtantly, I don't know how to call static methods from inside max.
The Parse static method (http://msdn2.microsoft.com/en-us/library/1k1skd40(VS.80).aspx ) from DateTime can be used like that:

DateTime = dotNetClass "System.DateTime"
date = DateTime.Parse "8/03/1972 6:30:00 PM"
print (date.ToString())

I used "8/03/1972 6:30:00 PM" to reverse the date creation from the previous example.

RustyKnight
12-17-2007, 11:35 PM
The Parse static method (http://msdn2.microsoft.com/en-us/library/1k1skd40(VS.80).aspx (http://msdn2.microsoft.com/en-us/library/1k1skd40%28VS.80%29.aspx) ) from DateTime can be used like that:

DateTime = dotNetClass "System.DateTime"
date = DateTime.Parse "8/03/1972 6:30:00 PM"
print (date.ToString())

I used "8/03/1972 6:30:00 PM" to reverse the date creation from the previous example.DotNetClass!!! *smacks head against brick wall*

So bloody obvious!!

I'm so jelious, you guys get to play with the good stuff. I'm stuck sitting between max 8 and max 9 (32 & 64) and it is driving me crazy...

max 8-9 (32) will talk to activex, max9 (32) and max 9 (64) will talk to dotnet but I need to bridge across max 8 to max 9 (64)...I want to die

note - max9 (64) will talk to activex, but windows 64 does not, by default, seem to include the all important listview control...on our installs any way...

I'm so annoyed I'm even thinking of developing a com server to do my UI work instead...but I think that is just a little over the edge

scorpion007
12-17-2007, 11:40 PM
I'm so annoyed I'm even thinking of developing a com server to do my UI work instead...but I think that is just a little over the edge
Why not just code your UI in Win32 or MFC? That'll save you from doing that, and lets you use all the UI stuff you want.

PEN
12-18-2007, 01:25 AM
Thanks guys, I was so close, I kept trying to pass in the date values in an array as that is what is looked like it wanted. I should have looked closer as I do know that is how you pass values to function in other languages ie;(val,val,val) I should have guessed it was just the same as passing values to a function in Max. As for the parse method that might work for me as well. I'm slowely building up a list of dotNet controls in a Doc and will format them with small help tid bits at some point and post it all on my site. I have worked a great deal with XML, listview and treeviews at this point as well as several others.

PEN
12-18-2007, 01:28 AM
Why not just code your UI in Win32 or MFC? That'll save you from doing that, and lets you use all the UI stuff you want.

How is this done?

PEN
12-18-2007, 01:40 AM
Yep, dotNetClass got me, it is dotNetObject, that is another reason that I wasn't even getting close.

scorpion007
12-18-2007, 01:46 AM
Well, simply put, Win32 is the fundamental C API for the windows platform.

.NET stuff (and MFC) is just a wrapper around it, in a higher level language.

If Max8 for example doesn't expose some .NET stuff that you need (RustyKnight mentioned a ListView), you can code it using the Win32 API. (MFC is fine apparently, but I don't have experience with it). BTW, MFC is basically a C++ wrapper around Win32 C API.

In other words, Win32 can do *everything*, MFC can do *most* stuff, and the stuff it can't you, you can fall-back to Win32. .NET can do whatever things that got implemented in it, provided Max lets you use them, but I don't have any experience with it either.

To answer "How to use Win32 API, and the ListView custom control", you'll need some preliminary knowledge with C, and some time to read a Win32 book. I'm not saying you 'should' do it, you may not need to -- if you already know .NET and you can use the ListView, and you're happy with it, great.

But if you can't for whatever reason, like what RustyKnight mentioned, you could definitely use Win32 code.

PS. I purposely didn't go into too much detail about the "How", because I don't want to overload you with low level details if you're not interested, or don't have the prerequisite knowledge. If you want more details, then let me know.

PEN
12-18-2007, 02:39 AM
That is great, just what I was looking for. I don't know C but I have worked with C++. Just wonder where you were going with it. dotNet so far has worked well in Mxs and I'm able to do most of what I would like so far.

RustyKnight
12-18-2007, 06:13 AM
Well, simply put, Win32 is the fundamental C API for the windows platform.

.NET stuff (and MFC) is just a wrapper around it, in a higher level language.

If Max8 for example doesn't expose some .NET stuff that you need (RustyKnight mentioned a ListView), you can code it using the Win32 API. (MFC is fine apparently, but I don't have experience with it). BTW, MFC is basically a C++ wrapper around Win32 C API.

In other words, Win32 can do *everything*, MFC can do *most* stuff, and the stuff it can't you, you can fall-back to Win32. .NET can do whatever things that got implemented in it, provided Max lets you use them, but I don't have any experience with it either.

To answer "How to use Win32 API, and the ListView custom control", you'll need some preliminary knowledge with C, and some time to read a Win32 book. I'm not saying you 'should' do it, you may not need to -- if you already know .NET and you can use the ListView, and you're happy with it, great.

But if you can't for whatever reason, like what RustyKnight mentioned, you could definitely use Win32 code.

PS. I purposely didn't go into too much detail about the "How", because I don't want to overload you with low level details if you're not interested, or don't have the prerequisite knowledge. If you want more details, then let me know.I think the intention is to develope a cross platform API ... so you could walk from max 8 through max 9 (32 & 64) without tearing you hair out or kill any junior artiests...

Would you need to code it as a plugin or can you incorprate these controls directly into max script?

I've been working on an idea to use the com functionality of max to setup a server and pass and xml based document between max and my app...this would allow me to do alot of the ui outside of max (and get some OO going), while still getting access to the internals of max.

This is obviously for "large" scale apps, not simple ones...

Malkalypse
01-10-2008, 05:56 AM
Okay, I'm not sure if the problem I am having is DotNet related or not, but it deals with the "Converting ActiveX ... to DotNet ..." tutorials files. Forgive me if the answer is obvious, I am still very new to this stuff. (Thanks Bobo, PEN, RustyKnight for getting me this far).

I am basically creating a split screen that shows a TreeView of objects and modifiers on one side, and a ListView of properties on the other. What I am stuck on is getting properties to update in the ListView from the scene. The code I have so far looks like this:


if (splitViewRollout != undefined) and (splitViewRollout.isDisplayed) do (destroyDialog splitViewRollout)
global splitViewRollout
rollout splitViewRollout " Modifiers"
(
-- TreeView
fn initTreeView tv =
(
tv.checkboxes = true
tv.sorted = true
)
fn addModifiers theNode theModifiers =
(
for m in theModifiers do
(
newNode = theNode.nodes.add m.name
newNode.tag = dotNetMXSValue m
newNode.checked = m.enabled
)
)
fn addObjects theNode theObjects =
(
for c in theObjects do
(
newNode = theNode.nodes.add c.name
newNode.tag = dotNetMXSValue c
newNode.checked = not c.isHidden
newNode.forecolor = (dotNetClass "System.Drawing.Color").fromARGB 200 0 0

addModifiers newNode c.modifiers
)
)
fn fillInTreeView tv =
(
theRoot = tv.nodes.add "(Objects)"
rootNodes = for o in objects collect o
addObjects theRoot rootNodes
)
-- ListView
fn initListView lv =
(
lv.gridLines = true
lv.view = (dotNetClass "System.Windows.Forms.View").Details
lv.fullRowSelect = true

layoutDef = #(#("Property", 120), #("Value", 60))

for i in layoutDef do (lv.columns.add i[1] i[2])
)
fn fillInSpreadsheet lv =
(
lv.items.clear()
theRange = #()

if selection.count == 1 and myNode != undefined do
(
propNamesArray = getPropNames myNode

for i = 1 to propNamesArray.count do
(
li = dotNetObject "System.Windows.Forms.ListViewItem" ((propNamesArray[i]) as string)
sub_Li = li.subItems.add ((getProperty myNode propNamesArray[i]) as string)

append theRange li
)
lv.items.addRange theRange
)
)

dotNetControl tv "TreeView" width:290 height:490 pos:[5,5]
dotNetControl lv_Properties "System.Windows.Forms.Listview" width:290 height:490 pos:[305,5]

on tv Click arg do
(
hitNode = tv.getNodeAt (dotNetObject "System.Drawing.Point" arg.x arg.y)

if hitNode != undefined do
(
try
(
if superClassOf hitNode.tag.value == modifier then (select hitNode.parent.tag.value)
else (select hitNode.tag.value)

global myNode = hitNode.tag.value
)
catch (max select none)

fillInSpreadsheet lv_Properties
)
)
on splitViewRollout open do
(
initTreeView tv
fillInTreeView tv

initListView lv_Properties
fillInSpreadsheet lv_Properties
)
)
createDialog splitViewRollout 600 525 style:#(#style_sysmenu, #style_titlebar, #style_toolwindow)
callbacks.addScript #preNodeGeneralPropChanged "splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties"


Of course any general advice is appreciated, but I am trying to focus on one thing at a time until I get this working properly :)

RustyKnight
01-10-2008, 06:31 AM
Okay, I'm not sure if the problem I am having is DotNet related or not, but it deals with the "Converting ActiveX ... to DotNet ..." tutorials files. Forgive me if the answer is obvious, I am still very new to this stuff. (Thanks Bobo, PEN, RustyKnight for getting me this far).

I am basically creating a split screen that shows a TreeView of objects and modifiers on one side, and a ListView of properties on the other. What I am stuck on is getting properties to update in the ListView from the scene. The code I have so far looks like this:

I don't know IF this actually fixes it, but, I added a beginUpdate and endUpdate call on the lv on the fillInSpreadSheet...ie

fn fillInSpreadsheet lv =
(
lv.beginUpdate()

.
.
.

lv.endUpdate()
)


And that seemed to work okay...for me...

Of course any general advice is appreciated, but I am trying to focus on one thing at a time until I get this working properly :)

Well, while you're asking ;), I throw in myNode = undefined just before the call to createDialog...

Shane

ps - If nothing else works, you could try lv.redrawItems startIndex endIndex invalidateOnly...use "false" for the invalidateOnly

Malkalypse
01-11-2008, 01:53 AM
The lv.beginupdate...lv.endupdate didn't work on my end. Are you sure that's all you did?

I added the myNode = undefined as you suggested, and even better I understand why :D

ps - If nothing else works, you could try lv.redrawItems startIndex endIndex invalidateOnly...use "false" for the invalidateOnly

Hm.. okay, you're going to have to guide me on the usage here, such as where I put it and what goes in the parameters.

Shouldn't I just be able to use some kind of callback or change handler for this?

----
NOTE: speaking of change handlers, I tried

when parameters myNode changes do splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties

yesterday and it didn't work. Today I tried it again and it did, but I got very inconsistent results. If I am interpreting what is happening correctly (unlikely) it seems to work only after the second time the script is run, and does NOT work with either modifiers or any objects that have them.

----
EDIT:

I figured out what was going on. The way its set up, it needs an object to be selected when the script is run; then that object will automatically update on all subsequent times the script is run. Once this is repeated for every object, it works fine.

Anyway, I am sure I can get it to work using change handlers (maybe a function to go through each object and property in the scene and set up a change handler for each one).* However, despite the fact that I am not noticing any significant slowing down in the small scenes I am testing with, I would really like to come up with a cleaner solution.

*Actually, I did set this up:

for o in objects do
(
when parameters o changes do splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties

for m in o.modifiers do
(
when parameters m changes do splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties
)
)

I really don't understand why

callbacks.addScript #preNodeGeneralPropChanged "splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties"

does not work, or why there doesn't seem to be a corollary for what I am trying to do?

----
(Okay, I have got to stop editing this, but I haven't been able to leave it alone...)

I get now why the #preNodeGeneralPropChanged callback doesn't work, I guess that refers to general NODE properties, and not "properties in general" XD

What bugs me is they have (pre/post)Node(Bone/General/Gi/MentalRay/User)PropChanged callbacks, but there doesn't seem to be that corrolary I mentioned for the "parameters window/showProperties) properties.

RustyKnight
01-11-2008, 03:51 AM
The lv.beginupdate...lv.endupdate didn't work on my end. Are you sure that's all you did?
Pretty much...
Hm.. okay, you're going to have to guide me on the usage here, such as where I put it and what goes in the parameters.So pretty much, any time you want to redraw a region of the list, calllv.redrawItems 0 lv.items.count falseThis is pretty heavy duty, so use with care, but it should completely redraw the list

Shouldn't I just be able to use some kind of callback or change handler for this?

*Actually, I did set this up:

for o in objects do
(
when parameters o changes do splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties

for m in o.modifiers do
(
when parameters m changes do splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties
)
)
I'd be VERY careful here as this could really hurt. I hope you are deregistering these callbacks when the object selection is changing, you could end up with a right mess...

You should be doing something like...
on selection changed, remove old callbacks, fill in spreadsheet, add new callbacks...

I really don't understand why

callbacks.addScript #preNodeGeneralPropChanged "splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties"

does not work, or why there doesn't seem to be a corollary for what I am trying to do?I'd imagine that the "splitViewRollout" is unknow by max and it cannot resolve it...but that's a pure guess...it may not like trying to resolve to a rollout...

Malkalypse
01-11-2008, 06:53 AM
I'd imagine that the "splitViewRollout" is unknow by max and it cannot resolve it...but that's a pure guess...it may not like trying to resolve to a rollout...

No no no no... What I am saying is that I want the fillInSpreadSheet function called every time ANY property of ANY scene object or modifier is changed. (That was what I was saying earlier about this not necessarily being a DotNet issue. I mentioned my problem here initially because the script itself is built on DotNet controls, and I figured the people here would be the most likely to understand what I am trying to do.)

I'd be VERY careful here as this could really hurt. I hope you are deregistering these callbacks when the object selection is changing, you could end up with a right mess...



Oh don't worry, I commented that part out as soon as I got it working. I REALLY don't intend to use that in the actual script, I just wanted to have SOMETHING as a backup if I can find no other solution.

Also, getting back to the topic of the thread.. sorting TreeViews alphabetically is quite simple, but how does one do the same in a ListView?

RustyKnight
01-11-2008, 07:11 AM
Also, getting back to the topic of the thread.. sorting TreeViews alphabetically is quite simple, but how does one do the same in a ListView?

sortOrder = DotNetClass "System.Windows.Forms.SortOrder"
lv.sorting = sortOrder.Ascending
Obviously, SortOrder.Descending or SortOrder.None

Shane

Malkalypse
01-12-2008, 04:15 AM
In my script I am using

on tv Click arg do
(
hitNode = tv.getNodeAt (dotNetObject "System.Drawing.Point" arg.x arg.y)
.
.
.
)


to get the script to react when I click on TreeView items.

What would I use to get the script to react when I click on a ListView item?

RustyKnight
01-12-2008, 04:34 AM
In my script I am using

on tv Click arg do
(
hitNode = tv.getNodeAt (dotNetObject "System.Drawing.Point" arg.x arg.y)
.
.
.
)


to get the script to react when I click on TreeView items.

What would I use to get the script to react when I click on a ListView item?Something like:local colSelectedItems = lv.selectedItemsWill give you a collection of selected items.

You might want to take a look at the NET_ListViewWrapper.ms in the MAX\stdplugs\stdscripts folder for an example of how to access a dot net collection

Shane

Malkalypse
01-12-2008, 04:55 AM
Wow, this is really weird. I just got finished looking at that .ms file between the time I posted my question and the time you answered. I had even found the GtLvSelection function which uses the selectedItems property you mentioned.

However, I am still stuck on getting at the specific items within that array. I keep getting the error


No ""get"" function for dotNetObject:System.Windows.Forms.ListView+SelectedListViewItemCollection


anytime I try something like (for example) "item_one = colSelectedItems[1]"

My immediate goal is to be able to access the text of the various fields by clicking on them, and sending that text out as a string.

RustyKnight
01-12-2008, 08:06 AM
anytime I try something like (for example) "item_one = colSelectedItems[1]"dot net collections are zero based (i'm sure this was mentioned in the sample code ;))...so, it should actually read:
item_one = colSelectedItems.items[0]The dot net collection is NOT an array, in the scense that maxscript understands them, they are actully containers, as such, you can not access them like you would an array, you need to use there published interface/properties/methods

For example, to get the size of the selection (ie the number of items selected), you would:selectionCount = colSelectedItems.countto convert a dot net collection to an array you could domaxArray = #()
selectionCount = colSelectedItems.count - 1
maxArray = for i = 0 to selectionCount collect ( lv.selectedItems.item[i] )This is the actual code from the GetLvSelection function in the NET_ListViewWrapper.ms

Shane

Malkalypse
01-12-2008, 09:18 PM
Okay.. I'm still stuck using the change handlers, which is annoying but I can live with it for now. (I have the script as it stands below.. once again, if anyone has any suggestions to make on how to improve it, I would love to hear them.

Now, my next question:
Is it possible to make the ListView values interactive? In other words, to change values in the ListView and make them affect the scene?

-- the script so far:

if (splitViewRollout != undefined) and (splitViewRollout.isDisplayed) do (destroyDialog splitViewRollout)
global myNode

global splitViewRollout

rollout splitViewRollout " Modifiers"
(
fn initTreeView tv =
(
tv.checkboxes = true
tv.sorted = true
)

fn addModifiers theNode theModifiers =
(
for m in theModifiers do
(
newNode = theNode.nodes.add m.name
newNode.tag = dotNetMXSValue m
newNode.checked = m.enabled
) -- end m loop
) -- end fn

fn addObjects theNode theObjects =
(
for c in theObjects do
(
newNode = theNode.nodes.add c.name
newNode.tag = dotNetMXSValue c
newNode.checked = not c.isHidden
newNode.forecolor = (dotNetClass "System.Drawing.Color").fromARGB 200 0 0

addModifiers newNode c.modifiers
) -- end c loop
) -- end fn

fn fillInTreeView tv =
(
theRoot = tv.nodes.add "(Objects)"
rootNodes = for o in objects collect o
addObjects theRoot rootNodes
)

fn initListView lv =
(
lv.gridLines = true
lv.view = (dotNetClass "System.Windows.Forms.View").Details
lv.fullRowSelect = true

layoutDef = #(#("Property", 120), #("Value", 160))

for i in layoutDef do (lv.columns.add i[1] i[2])

-- Sort ListView alphabetically
sortOrder = dotNetClass "System.Windows.Forms.SortOrder"
lv.sorting = sortOrder.Ascending
)

fn fillInSpreadsheet lv =
(
deleteAllChangeHandlers()

lv.items.clear()
theRange = #()

if selection.count == 1 and myNode != undefined do
(
propNamesArray = getPropNames myNode

for i = 1 to propNamesArray.count do
(
li = dotNetObject "System.Windows.Forms.ListViewItem" ((propNamesArray[i]) as string)
sub_Li = li.subItems.add ((getProperty myNode propNamesArray[i]) as string)

append theRange li
) -- end i loop

lv.items.addRange theRange
) -- end if

for o in objects do
(
when parameters o changes do splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties
for m in o.modifiers do
(
when parameters m changes do splitViewRollout.fillInSpreadsheet splitViewRollout.lv_Properties
) -- end m loop
) -- end o loop

) -- end fn

dotNetControl tv "TreeView" width:290 height:490 pos:[5,5]
dotNetControl lv_Properties "System.Windows.Forms.Listview" width:290 height:490 pos:[305,5]

on tv click arg do
(
hitNode = tv.getNodeAt (dotNetObject "System.Drawing.Point" arg.x arg.y)

if hitNode != undefined do
(
try
(
if superClassOf hitNode.tag.value == modifier then (select hitNode.parent.tag.value)
else (select hitNode.tag.value)

myNode = hitNode.tag.value
)
catch (max select none)

fillInSpreadsheet lv_Properties
) -- end if
) -- end on

on lv_Properties click do
(
colSelectedItems = lv_Properties.selectedItems

selectionCount = colSelectedItems.count - 1
selectionArray = for i = 0 to selectionCount collect (lv_Properties.selectedItems.item[i])

print selectionArray[1].text
)

on splitViewRollout open do
(
initTreeView tv
fillInTreeView tv

initListView lv_Properties
fillInSpreadsheet lv_Properties
)
on splitViewRollout close do deleteAllChangeHandlers()
)

createDialog splitViewRollout 600 525 style:#(#style_sysmenu, #style_titlebar, #style_toolwindow)

RustyKnight
01-12-2008, 10:32 PM
Now, my next question:
Is it possible to make the ListView values interactive? In other words, to change values in the ListView and make them affect the scene?
Yes...but only the "first" column, if i remember correctly, is used by the name of the property, not it's value...

In order to get to this to work they way you want, you will need to use an "inline" editing hack...which I'm not sure if anyone has yet perfected...I personally haven't had the time...

Shane

Malkalypse
01-13-2008, 12:20 AM
I'm game to give it a try (despite having no idea what I am doing). Tell me how it works in theory, and maybe suggest what DotNet and/or MaxScript methods and events should be used.

I realize this is probably over my head, but how else am I going to learn anything. Besides, I have been known to suprise people ;P

RustyKnight
01-13-2008, 02:53 AM
I'm game to give it a try (despite having no idea what I am doing). Tell me how it works in theory, and maybe suggest what DotNet and/or MaxScript methods and events should be used.

I realize this is probably over my head, but how else am I going to learn anything. Besides, I have been known to suprise people ;PThe basic idea is, in theory, is that when you detect a "editable" event, you place a pre-defined edit field "over" the cell you want to edit...

Then you need to watch for an "accept" and "cancel" event and based on that action perform any updates as required...in theory...

So you need to decide what dictates an edit event...something like a double click or pressing f2 (although keyboard shortcuts can be hard to implement).

You need to determine the x/y location on the form of the cell to edit, you need to create a control of the right size of the cell and place, ontop of the listview, at the x/y poisition of the cell...

You then need to determine the "accept" action, usually a enter key or lose of focus and the "cancel" event, simething like the escape key or lose of focus.

Basically, in theory...

Shane

PEN
01-13-2008, 04:18 PM
I have not tested this as it was done here http://forums.cgsociety.org/showthread.php?f=98&t=551473&page=5&pp=15 but this should get the item that was clicked on even if it is a sub item. Form there do as shane describes and place an editText field or other dotnet control over the cel. You can get the position and size of the cell and control the editText field with that. Once the data is entered replace the text and data in the node that holds that cel.

Malkalypse
01-14-2008, 08:09 PM
I gave up on using the ListView for this particular purpose. I was able to get the functionality I needed just using MaxScript. It was a bit cumbersome, but it sounds like the ListView solution would have been equally so. I'm still using the TreeView, and have it playing nice with the standard subRollout next to it, so I am happy. If anyone is interested, I will post the script here or elsewhere. (It's "done" as far it goes, still going to need some other features if it is actually going to be of much use though.)

This is not to say I am not interested in learning more about using ListView or other DotNet functions.

I think that the biggest obstacle for me right now is the lack of documentation for DotNet within MaxScript. On the MSDN resource library, they show syntax for Visual Basic, C#, Visual C++ etc., and all of course are slightly different. Sadly MaxScript is not on the list. Is there some kind of guide to general DotNet usage in MaxScript that I am not aware of? Which of the different languages on the syntax list would be the closest to the MaxScript syntax?

RustyKnight
01-14-2008, 08:23 PM
I gave up on using the ListView for this particular purpose. I was able to get the functionality I needed just using MaxScript. It was a bit cumbersome, but it sounds like the ListView solution would have been equally so. I'm still using the TreeView, and have it playing nice with the standard subRollout next to it, so I am happy. If anyone is interested, I will post the script here or elsewhere. (It's "done" as far it goes, still going to need some other features if it is actually going to be of much use though.)

This is not to say I am not interested in learning more about using ListView or other DotNet functions.

I think that the biggest obstacle for me right now is the lack of documentation for DotNet within MaxScript. On the MSDN resource library, they show syntax for Visual Basic, C#, Visual C++ etc., and all of course are slightly different. Sadly MaxScript is not on the list. Is there some kind of guide to general DotNet usage in MaxScript that I am not aware of? Which of the different languages on the syntax list would be the closest to the MaxScript syntax?I believe both Bobo and PEN have been putting together some documentation on DotNet and maxscript, so I'd do a search for them and see what it comes up with.

As for the MSDN, I, personally, find that C#/C++ is most useful, having said that, I can read most of the C#/C++ code anyway and I've learnt what parts are most relevent to maxscript.

Shane

Malkalypse
01-16-2008, 05:05 AM
As I've moved the majority of the script I'm developing into pure MaxScript rather than DotNet, I don't think that discussions about it belong in this thread anymore. However, if any of you are curious about it and willing to give me more advice or comments, I have moved further development to this thread:

http://forums.cgsociety.org/showthread.php?f=98&t=584598

Kenzor
01-16-2008, 12:51 PM
I'm writing a dotnet mouse window control in C#

I'll release all the code as I go along

Click here to see the thread. (http://forums.cgsociety.org/showthread.php?f=98&t=568496)

PEN
01-16-2008, 01:48 PM
What will this do then Ken?

ypuech
01-21-2008, 02:12 PM
An area member just figured out today how to fill a .NET array.

Here is the code:
-- .NET arrays indexes start at 0!

-- Create a .NET array of 10 integers
intArray = dotNetObject "System.Int32[]" 10

-- Fill array
for idx = 1 to 10 do
(
intValue = dotNetObject "System.Int32" (random 1 100)
intIndex = dotNetObject "System.Int32" (idx-1)
intArray.SetValue intValue intIndex
)

-- Print array data
for idx = 1 to 10 do
(
intIndex = dotNetObject "System.Int32" (idx-1)
print (intArray.GetValue intIndex)
)

PEN
01-21-2008, 03:13 PM
Nice one, what can we do with this that we can't with Max arrays?

ypuech
01-21-2008, 03:48 PM
Nice one, what can we do with this that we can't with Max arrays?
Some functions in the .NET framework and in other assemblies espects .NET arrays.
The array created is of class System.Array (http://msdn2.microsoft.com/en-us/library/system.array_members(VS.80).aspx).

I don't know if they are better and faster than MAXScript built-in arrays. I'll do some tests.

EDIT: I've done some tests and .NET arrays are very much slower than MAXScript arrays. Not surprising.

PEN
01-21-2008, 04:14 PM
So do they provide any other reasons to use them? Are there cases with some dotNet objects that need the dotNet array and will not accept MXS arrays?

ypuech
01-21-2008, 04:39 PM
So do they provide any other reasons to use them? Are there cases with some dotNet objects that need the dotNet array and will not accept MXS arrays?
Yes, there's many situations like that and as there's no implicit conversion from MXS to dotNet array, it needs to be built by hand.

PEN
01-21-2008, 06:45 PM
OK writting an XML file to a string stream or string? I don't want to write it to the drive just store it as a string.

Any ideas? I'm looking around .writeTo but I'm not getting anywhere.

ypuech
01-21-2008, 11:21 PM
OK writting an XML file to a string stream or string? I don't want to write it to the drive just store it as a string.
I think you can create an XmlWriter that outputs to a StringBuilder then convert it to a string.

See XmlWriter.Create Method (StringBuilder, XmlWriterSettings) ( http://msdn2.microsoft.com/en-us/library/ms162619(VS.80).aspx)

PEN
01-22-2008, 01:40 AM
OK I will play with that more as I have not had success with it as of yet. I'll let ever one know if I find an answer.

RustyKnight
01-22-2008, 02:52 AM
Hi Pen!

I haven't tried it, but the StringBuilder approach seems like the way to go for what you want.

Shane

PEN
01-22-2008, 03:46 PM
I'm just not following this at all.


dotNet.loadAssembly "system.xml.dll"
xmlDoc=dotNetObject "system.xml.xmlDocument"
xmlDoc.loadXml testStr
cpi = xmlDoc.createProcessingInstruction ("xml") ("version=\"1.0\" encoding = \"Windows-1252\"")
xmlDoc.AppendChild cpi

xmlWriter=dotNetClass "System.Xml.XmlWriter"
stringBuilder=dotNetClass "System.Text.StringBuilder"

--NOW WHAT?

PEN
01-22-2008, 04:01 PM
It is always the bloody obviouse isn't it...


dotNet.loadAssembly "system.xml.dll"

xmlDoc=dotNetObject "system.xml.xmlDocument"
cpi = xmlDoc.createProcessingInstruction ("xml") ("version=\"1.0\" encoding = \"Windows-1252\"")
xmlDoc.AppendChild cpi
root = xmlDoc.createElement "Root"

new=xmlDoc.createElement "Test"
new.setAttribute "userName" sysInfo.username
new.setAttribute "computerName" sysInfo.computerName
root.AppendChild new
xmlDoc.AppendChild root

xmlDoc.OuterXml


Now I need to know how to read that back in.

PEN
01-22-2008, 04:49 PM
Don't over complete it things is what I always say and what do I always do:S


--Create XML doc

dotNet.loadAssembly "system.xml.dll"

xmlDoc=dotNetObject "system.xml.xmlDocument"
cpi = xmlDoc.createProcessingInstruction ("xml") ("version=\"1.0\" encoding = \"Windows-1252\"")
xmlDoc.AppendChild cpi
root = xmlDoc.createElement "Root"

new=xmlDoc.createElement "Test"
new.setAttribute "userName" sysInfo.username
new.setAttribute "computerName" sysInfo.computerName
root.AppendChild new
xmlDoc.AppendChild root

--Store the xml as a string
xmlString=xmlDoc.OuterXml


--Create a new xmlDoc
xmlInDoc=dotNetObject "system.xml.xmlDocument"
--Read in the string.
xmlInDoc.loadXml xmlString
xmlInDoc.OuterXml


Now last step, getting it to format correctly so that it is readable.

PEN
01-22-2008, 05:11 PM
OK it looks as though I'm back to having to use xmlWriter or something of the sort. This is what I just can't get to work. If I want the format to be formated instead of just one long string that is returned.

This isn't so bad because if I want to save it to file I can read it in as an xml and then save the xml doc and it is formated. But for readability this isn't all that good if I just print the string.

Any help if you can.

ypuech
01-22-2008, 10:30 PM
Hi Paul, I quickly searched the web and I found that you can create a XmlWriter with a StringWriter argument.

Here is an example code:
-- Do not forget to load the assembly
dotnet.LoadAssembly "System.Xml.dll"

-- Create the XmlWriter class
XmlWriter = dotNetClass "System.Xml.XmlWriter"

-- Create StringWriter
StringWriter = dotNetObject "System.IO.StringWriter"

-- Create XmlWriterSettings and fill info
XmlWriterSettings = dotNetObject "System.Xml.XmlWriterSettings"
XmlWriterSettings.Indent = true
XmlWriterSettings.OmitXmlDeclaration = false
XmlWriterSettings.NewLineOnAttributes = true

-- Create new XmlWriter in the StringWriter with the specified settings
Writer = XmlWriter.Create StringWriter XmlWriterSettings

-- Write the name of each geometry in the current scene

Writer.WriteStartElement "geometries"
for object in geometry do
(
Writer.WriteElementString "geometry" object.name
)
Writer.WriteEndElement()

-- Release Xml resources
Writer.Flush()
Writer.Close()

StringWriter.ToString()

Beware though that writing to StringWriter will always produce UTF-16 encoded
XML. If you need different encoding use MemoryStream.

RustyKnight
01-22-2008, 10:45 PM
I'm just not following this at all.


dotNet.loadAssembly "system.xml.dll"
xmlDoc=dotNetObject "system.xml.xmlDocument"
xmlDoc.loadXml testStr
cpi = xmlDoc.createProcessingInstruction ("xml") ("version=\"1.0\" encoding = \"Windows-1252\"")
xmlDoc.AppendChild cpi

xmlWriter=dotNetClass "System.Xml.XmlWriter"
stringBuilder=dotNetClass "System.Text.StringBuilder"

--NOW WHAT?
Given the fact that you have found another way, this might not be needed, however:
clsXMLWriter=dotNetClass "System.Xml.XmlWriter" -- We don't need an instance, as one will be created via the create method
stringBuilder=dotNetObject "System.Text.StringBuilder" -- We do need an instance so we can work with it later

-- Stolen from the docs...
xmlSettings = dotNetObject "System.Xml.XmlWriterSettings"
xmlSettings.Indent = true
xmlSettings.OmitXmlDeclaration = true
xmlSettings.NewLineOnAttributes = true;

-- Create and instance of the writer to output to our stringbuilder
xmlWriter = clsXMLWriter.create stringBuilder xmlSettings

-- write away...
-- Stolen from the docs...
xmlWriter.WriteStartElement "order"
xmlWriter.WriteAttributeString "orderID", "367A54"
xmlWriter.WriteAttributeString "date", "2001-05-03"
xmlWriter.WriteElementString price", "19.95"
xmlWriter.WriteEndElement();

xmlWriter.flush()

/**
Should produce:
<order
orderID="367A54"
date="2001-05-03">
<price>19.95</price>
</order>*/

-- Not stolen from the docs...
xmlString = stringBuilder.toString()
Now...if when you want to reparse the document, you would use XMLDocument.loadXML xmlString...

xmlDoc=dotNetObject "system.xml.xmlDocument"
xmlDoc.loadXML xmlString
-- Process away...
You can also load a doucment from a file via one of the various "load" methods

I've gone a little overboard as I'm trying to help with more then one post :P and I've not tested any of this...so good luck

Shane

PEN
01-23-2008, 12:55 AM
I have been using xml files alot as of late using .xmlDocument how ever I have not read from strings before. I have that working now. You don't need the writer for creating xml elements as you can do that with .xmlDocument with .createElement.

I wonder if there any advantage to using xmlWriter? Any way where did you guys find the help on it? I didn't get anything that I can make heads or tails of. And thanks for the help.

RustyKnight
01-23-2008, 01:22 AM
I have been using xml files alot as of late using .xmlDocument how ever I have not read from strings before. I have that working now. You don't need the writer for creating xml elements as you can do that with .xmlDocument with .createElement.

I wonder if there any advantage to using xmlWriter? Any way where did you guys find the help on it? I didn't get anything that I can make heads or tails of. And thanks for the help.Hi Paul!

I would surmise that the XMLWriter is good for creating formatted documents where as XMLDocument is a "object" representation of a XML document...if that makes scense. So, if you don't ever really need users to be able to read the xml document themselves, then XMLDocument is fine. If you need a well formatted (beyond the markup) document, then I would use the XMLWriter.

I basically looked up the dotnet help docs and wadded my way through them.

I'm like you. I tend just to use the XMLDocument class as my output is generally only needed by the programs and needed for reading by the user.

It would be interesting to see how other parsers deal with the result though.

Shane

ypuech
01-23-2008, 08:53 AM
I wonder if there any advantage to using xmlWriter? Any way where did you guys find the help on it? I didn't get anything that I can make heads or tails of.
XmlWriter is faster than XmlDocument because it's working on a stream whereas XmlDocument uses DOM and consumes a lot of memory.

XmlDocument description from MSDN:
The XmlDocument class is an in-memory or cached tree representation of an XML document. You can use it to edit and navigate the document. While XmlDocument is easy to use, it is very resource-intensive. You should generally use XmlReader and XmlWriter for better performance.

XmlWriter description from MSDN:
The XmlWriter abstract base class is used to generate a stream of XML. The .NET Framework provides an implementation in the form of the XmlTextWriter class. You use this class as a fast, noncached, forward-only way to generate streams or files that contain XML data.

If your application needs to generate XML, you can write XML by using the XmlDocument or the XmlTextWriter classes. The XmlTextWriter class performs better, but you should use XmlDocument if you need to manipulate the XML in memory before you write the XML to a byte stream.

See Improving XML Performance (http://msdn2.microsoft.com/en-us/library/ms998559.aspx) and Best Practices for Representing XML in the .NET Framework (http://msdn2.microsoft.com/en-us/library/ms950765.aspx).

PEN
01-23-2008, 02:33 PM
Well this is all good to know. I will look into using writer and reader instead but not really sure that it will make all the difference in this current tool.

RustyKnight: when you use .save from xmlDocument it out puts a well formated xml doc that can be read. In the last tool that I created I wanted the objected based methods as I was storing reference to those elements so that I could get to them directly without having to re-read the doc. Writting in new elements with writer looks like I would have to re-read the doc again with xmlDoc to do get the objects. Is this the case?

I'll play with it and see what I come up with.

RustyKnight
01-23-2008, 10:51 PM
It also depends on what you want to do with all this data in the long run.

Readers and writers are great if all you need to is get data from one format to another, but when you actually want to do something with that data (lets say build a scene), XMLDocument is a better choice.

It allows you to navigate the document in a number of different ways, I particularly like there implementation of XPath, simple to setup and use...My god MS designed something useful!!

I would also imagin that XMLDocument uses both the reader and writer at some level to do it's work anyway.

Shane

RustyKnight
01-23-2008, 11:08 PM
In the last tool that I created I wanted the objected based methods as I was storing reference to those elements so that I could get to them directly without having to re-read the doc. Writting in new elements with writer looks like I would have to re-read the doc again with xmlDoc to do get the objects. Is this the case?If all you want is to access a single object element you will either need to parse the document yourself...which is reading the document anyway, or allow XMLDocument to do it for you...basically it is the samething...

However, XMLDocument will read the ENTIRE document in order to build it's tree, before you even get a chance to look at it...

The benifit here is that you get access to the DOM's search mechanisms, making it very easy to track down any number of elements that you want, particularly with MS's implementation of XPath (basically a query language for XML).

You also have the ability to add, remove and edit individual elements of the document quite easily.

If all this is to much, you could look for an implementation of a SAX parser. This will parse the document, but give you immediate feedback on each parse event (ie when an element is encounted, you get notified), so you can actually do work inline with parser. The SAX parser won't cache the information as it works, making it a more memory friendly. This is more complicated to setup but if you really don't want to manipulate the document, it is a better solution...unfourtantly, I don't think dotNet ships with an implementation...

Shane

PEN
01-24-2008, 12:03 AM
I have not heard of xPath so I will look that up. After playing around I don't think that read write will be what I want. I want the nodes and the information in them. It is very easy to get with xmlDoc as well as it is to set elements to any other element and build trees. I'll keep playing and see what I end up with.

Thanks for the input.

Dmaxer
02-02-2008, 05:12 PM
moved this post sorry

clc
02-04-2008, 08:05 AM
Hello, All,

I'm trying to talk with a C# app outside Max using the dotNet integration in Max 2008, but I'm having a lot of trouble getting the syntax right. I think I've managed to create a socket using this code:


socket = dotNetObject "System.Net.Sockets.Socket" (dotnetclass "System.Net.Sockets.AddressFamily").InterNetwork (dotnetclass "System.Net.Sockets.SocketType").Stream (dotnetclass "System.Net.Sockets.ProtocolType").Tcp


The next step is to open a connection to the other end, but I'm having no luck getting the syntax right to construct an ip address object. I've tried arrays and shifts and everything else I could think to try. I've found some other messages that lead me to believe that Byte[] arrays don't work properly in MXS yet, but it seems to me that shifting should work:


--ip = #(192, 168, 1, 100)
--ip = ( bit.shift 192 24 ) + ( bit.shift 168 16 ) + ( bit.shift 1 8 ) + 100
--endPoint = dotNetObject "System.Net.IPEndPoint" ip 0xc0



Here's what the constructors expect for IPEndPoint and IPAddress:


dotNet.showConstructors "System.Net.IPEndPoint"
System.Net.IPEndPoint <System.Net.IPAddress>address <System.Int32>port
System.Net.IPEndPoint <System.Int64>address <System.Int32>port

dotNet.showConstructors "System.Net.IPAddress"
System.Net.IPAddress <System.Byte[]>address
System.Net.IPAddress <System.Int64>newAddress
System.Net.IPAddress <System.Byte[]>address <System.Int64>scopeid



Can anyone point me to a working example of network communication or recommend an alternative approach? At this point, I'm starting to think that I'd make more progress doing the low-level messaging in C++ and reserve MXS for the high-level code.

Thanks for any help you can give me,
Chris

RustyKnight
02-04-2008, 08:35 AM
Hello, All,

I'm trying to talk with a C# app outside Max using the dotNet integration in Max 2008, but I'm having a lot of trouble getting the syntax right. I think I've managed to create a socket using this code:


socket = dotNetObject "System.Net.Sockets.Socket" (dotnetclass "System.Net.Sockets.AddressFamily").InterNetwork (dotnetclass "System.Net.Sockets.SocketType").Stream (dotnetclass "System.Net.Sockets.ProtocolType").Tcp


The next step is to open a connection to the other end, but I'm having no luck getting the syntax right to construct an ip address object. I've tried arrays and shifts and everything else I could think to try. I've found some other messages that lead me to believe that Byte[] arrays don't work properly in MXS yet, but it seems to me that shifting should work:


--ip = #(192, 168, 1, 100)
--ip = ( bit.shift 192 24 ) + ( bit.shift 168 16 ) + ( bit.shift 1 8 ) + 100
--endPoint = dotNetObject "System.Net.IPEndPoint" ip 0xc0



Here's what the constructors expect for IPEndPoint and IPAddress:


dotNet.showConstructors "System.Net.IPEndPoint"
System.Net.IPEndPoint <System.Net.IPAddress>address <System.Int32>port
System.Net.IPEndPoint <System.Int64>address <System.Int32>port

dotNet.showConstructors "System.Net.IPAddress"
System.Net.IPAddress <System.Byte[]>address
System.Net.IPAddress <System.Int64>newAddress
System.Net.IPAddress <System.Byte[]>address <System.Int64>scopeid



Can anyone point me to a working example of network communication or recommend an alternative approach? At this point, I'm starting to think that I'd make more progress doing the low-level messaging in C++ and reserve MXS for the high-level code.

Thanks for any help you can give me,
ChrisI'm going to point out VERY quickly, there maybe a way to cheat!

The Socket.connect method allows for a String as an address, so it might be possible tonetSocket.connect "localhost" iPort

Your main issue is trying to convert the address to a dot net array. ypuech posted an example of how this might be achieved, check out here (http://forums.cgsociety.org/showpost.php?p=4899360&postcount=95) for details.

Shane

ypuech
02-04-2008, 08:37 AM
At this point, I'm starting to think that I'd make more progress doing the low-level messaging in C++ and reserve MXS for the high-level code.
I think it would be better to do the low-level stuff in C# (or VB.NET) with an intermediate assembly.

Your main issue is trying to convert the address to a dot net array. ypuech posted an example of how this might be achieved, check out here for details.
Unfortunately, I'm not sure that it can work even if you build the array as the method expects an array of bytes and MAXScript can only send integer; maybe the method will not recognize the parameter...
It's a limitation of .NET in MAXScript :D.

U.S.S. Speed
02-04-2008, 05:00 PM
BitArray?

Not sure to understand everything... But MXS can return array of bits...

Dmaxer
02-04-2008, 09:16 PM
Im not having much luck trying to pass a float array from my function in C#/dot net to maxscript ? are you guys saying maxscript cant do this and I will have to use an integer array ?

Also is there someplace I can read up on more things like this,as all I can find in the maxscript help has to do with making tree views and stuff to do with xml , there does not seem to be much info if any at all on passing data to and from functions in C#.

And one more thing could I write my functions in C++ as I know C++ and dont know C# that well at all ..

Thanks for reading and sorry for asking so much but I so badly want to learn this dotnet stuff

all the best :)

ypuech
02-04-2008, 11:14 PM
Im not having much luck trying to pass a float array from my function in C#/dot net to maxscript ? are you guys saying maxscript cant do this and I will have to use an integer array ?

Also is there someplace I can read up on more things like this,as all I can find in the maxscript help has to do with making tree views and stuff to do with xml , there does not seem to be much info if any at all on passing data to and from functions in C#.
See "MAXScript / DotNet Value Conversions" in the Reference to understand what I said.

And one more thing could I write my functions in C++ as I know C++ and dont know C# that well at all ..
If you want to write C++ code with .NET Framework you have to use C++/CLI. This is an extension to C++ to support managed code. But I think it's better to write assemblies (.NET DLL) in C# or VB.NET because these languages are very good and easy to understand.

Dmaxer
02-05-2008, 12:22 AM
Thanks for the reply I will readup DotNet Value Conversions :) and spend a bit more time on c# I will get my head round it Im sure , thanks again :)

RustyKnight
02-06-2008, 03:12 AM
I have not heard of xPath so I will look that up. After playing around I don't think that read write will be what I want. I want the nodes and the information in them. It is very easy to get with xmlDoc as well as it is to set elements to any other element and build trees. I'll keep playing and see what I end up with.

Thanks for the input.Hi Paul! I meant to do this sometime go ago but overwhelmed by otherthings...

If you're interested, checkout http://www.w3schools.com/xpath/default.asp and http://msdn2.microsoft.com/en-us/library/ms256086.aspx

This will give you start...yet, another query language to learn :P

Shane

PEN
02-06-2008, 02:42 PM
Thanks Shane. I should have stuck with being a modeler, would just need to learn the odd new piece of software from time to time instead of five new languages each week.

RustyKnight
02-07-2008, 05:38 AM
Thanks Shane. I should have stuck with being a modeler, would just need to learn the odd new piece of software from time to time instead of five new languages each week.Another language I can deal with (almost)

I'm writing a script that needs to run in max 8 and max 9 x64...so i need to swap between activex and dotnet...and the xml api is NOT THE BLOODY SAME...it almost is, just enough to lure you in ... and when you feel safe...bame...this property is unknown...

Going cross eyed trying to get it to work... :P

erilaz
02-11-2008, 01:26 AM
Hey gang,

I've been scrounging around trying to find the access to the Summary Info tab for windows files, but I can only find a COM reference. Any clues?

RustyKnight
02-11-2008, 02:42 AM
Hey gang,

I've been scrounging around trying to find the access to the Summary Info tab for windows files, but I can only find a COM reference. Any clues?Do you want the tab or the file info??

Shane

erilaz
02-11-2008, 02:56 AM
Do you want the tab or the file info??

Shane

I want to write details into the Summary fields (ie. When you right-click for properties in explorer and get the Author, Comments, Keywords etc).

I want to write a basic script to add details to an exported mesh.

ypuech
02-11-2008, 11:15 AM
I want to write details into the Summary fields (ie. When you right-click for properties in explorer and get the Author, Comments, Keywords etc).

I want to write a basic script to add details to an exported mesh.
You don't need .NET or COM to do that. See "3ds Max Scene File Properties" in the MAXScript Reference and the sample example.

erilaz
02-11-2008, 11:29 PM
You don't need .NET or COM to do that. See "3ds Max Scene File Properties" in the MAXScript Reference and the sample example.

Unfortunately that only works for max scene file properties. I'm doing this for other files, ie. Exports and textures.

clc
02-26-2008, 02:44 AM
Hello, I'm having trouble loading an xml doc from a string in MXS. This code


dotNet.loadAssembly "system.xml.dll"
message ="<?xml version=\"1.0\" encoding = \"Windows-1252\"?><bookstore></bookstore>"
xmlInDoc=dotNetObject "system.xml.xmlDocument"
xmlInDoc.loadXml message


produces "undefined" in the listener on the loadXml line.

The code in post #106 ( http://forums.cgsociety.org/showpost.php?p=4901788&postcount=106 ) also produces "undefined" for me when it tries to run the loadXml method.

Can anyone suggest a way around this?

Thanks,
Chris

RustyKnight
02-26-2008, 04:51 AM
Hay Chris!

I can see why this might be confusing. There is actually nothing wrong...

Try this, addxmlInDoc.OuterXmlto the end of your code and see what you get

Shane

clc
02-27-2008, 04:54 AM
Wow. I plainly need to learn more XML & .NET. Thanks for the help -- it works perfectly, of course!
Chris

JHN
02-29-2008, 04:19 PM
Hi all,

I'm posting a code snippet which might be of use to someone, utilising the TableLayoutPanel control :



(
tv = dotNetObject "System.Windows.Forms.TableLayoutPanel"

tv.layoutSettings.RowCount = 12
tv.layoutSettings.ColumnCount = 6
tv.BorderStyle = (dotNetClass "System.Windows.Forms.BorderStyle").None
tv.CellBorderStyle = (dotNetClass "System.Windows.Forms.TableLayoutPanelCellBorderStyle").Single

tv.width = tv.layoutSettings.ColumnCount * 32
tv.height = tv.layoutSettings.RowCount* 32

for i = 0 to tv.layoutSettings.RowCount - 1 do
for j = 0 to tv.layoutSettings.ColumnCount - 1 do
(
btn = (dotNetObject "System.Windows.Forms.Button")
--dotShow
btn.Width = 25
btn.Height = 25
btn.Text = (i+j) as string
tv.Controls.Add btn i j
)


hForm = dotNetObject "System.Windows.Forms.Form"
hForm.Size = dotNetObject "System.Drawing.Size" (tv.Width + 10) (tv.Height + 30)
hForm.Text = ".Net TableLayoutPanel"
hForm.Controls.Add(tv)
hForm.TopMost = true
FormBorderStyle = dotNetClass "System.Windows.Forms.FormBorderStyle"
hForm.FormBorderStyle = FormBorderStyle.FixedDialog
hForm.ShowInTaskbar = false
hForm.MinimizeBox = false
hForm.MaximizeBox = false


-- Show application Form
hApp = dotNetClass "System.Windows.Forms.Application"
hApp.Run hForm
)



If you want it as control in a dialog replace
tv = dotNetObject "System.Windows.Forms.TableLayoutPanel"
with
dotNetControl tv "System.Windows.Forms.TableLayoutPanel"

I hope this is of help to anyone, cause the tablecell take all sorts of objects, not just buttons.. Allthough I'm having some slow downs building large grids with buttons inside a dialog, don't know what it is yet.

-Johan

JHN
02-29-2008, 07:14 PM
An observation:

I see a lot of code looking like this

newNode.forecolor = (dotNetClass "System.Drawing.Color").fromARGB 200 0 0

instancing a new dotNetClass... but in this example newNode.forecolor itself is a reference to to the same class right...?!

So wouldn't

newNode.forecolor = newNode.forecolor.fromARGB 200 0 0

be better and even more logical! I assume it's faster cause the class is already loaded and doesn't need a new pointer to it. At least I find it more readable and logic.

Am I on the right track here?

-Johan

Pjanssen
03-01-2008, 11:28 PM
I'm having some problems with the (keyboard) focus when using dotnet controls. I want to be able to use the regular 3dsmax shortcuts while using dotnet controls. Either by removing the focus each time an action is applied on the control, or through some other way. But I can't seem to figure out how to do this.
Calling "setFocus" on the rollout from the dotnet control doesn't seem to work...

Any ideas?

ypuech
03-02-2008, 09:45 PM
I'm posting a code snippet which might be of use to someone, utilising the TableLayoutPanel control :
Interesting code sample John! TableLayoutPanel seems useful to create dynamic UI. There's also FlowLayoutPanel that dynamically lays out its contents horizontally or vertically.

An observation:

I see a lot of code looking like this

newNode.forecolor = (dotNetClass "System.Drawing.Color").fromARGB 200 0 0

instancing a new dotNetClass... but in this example newNode.forecolor itself is a reference to to the same class right...?!

So wouldn't

newNode.forecolor = newNode.forecolor.fromARGB 200 0 0

be better and even more logical! I assume it's faster cause the class is already loaded and doesn't need a new pointer to it. At least I find it more readable and logic.

Am I on the right track here?
In fact, it's the same in the two situations because FromARGB() is a static method. So, its behaviour doesn't depend on the object it's executed.

JHN
03-04-2008, 09:46 AM
In fact, it's the same in the two situations because FromARGB() is a static method. So, its behaviour doesn't depend on the object it's executed.


Okay, I still have to learn a lot I see :) Thanks for clarifying this, although I think I'm going to stick with my method since it makes more sense to me and doesn't require me typing a new string.... copy paste will do... yes I'm lazy.

I keep thinking it would be good to have an maxscript V2 or some other langauge in max that's more conform to OOP. Just like actionscript you have 3 flavours.. I'd settle for 2 or maybe python or something.. I really feel UI building is lacking severly in mxs...

-Johan

PEN
03-24-2008, 03:03 PM
OK I'm having some issues getting dotNet.loadAssembly "Microsoft.Win32.Registry" to work. Is it not supported or am I doing something wrong?

I want to be able to read and write reg keys.

PEN
03-24-2008, 03:06 PM
Never mind, I'm a bone head. Must have miss typed my frist test of
reg=dotNetClass "Microsoft.Win32.Registry"
reg.localMachine

This works fine so far.

PEN
03-24-2008, 04:08 PM
OK I still need a bit of help on this. I can create new keys but I can't sort out how to create values.


reg=dotNetClass "Microsoft.Win32.Registry"

reg.LocalMachine.GetSubKeyNames()

softWare=reg.LocalMachine.OpenSubKey "SOFTWARE" true --Opens key and makes it writable.
pen=softWare.CreateSubKey "Pen" --Creates a new key.

--This isn't working. Can any one shed any light on it?
pen.SetValue "Version" 1.0 --Errors

pen.close()
softWare.close()

RustyKnight
03-24-2008, 07:49 PM
OK I still need a bit of help on this. I can create new keys but I can't sort out how to create values.


reg=dotNetClass "Microsoft.Win32.Registry"

reg.LocalMachine.GetSubKeyNames()

softWare=reg.LocalMachine.OpenSubKey "SOFTWARE" true --Opens key and makes it writable.
pen=softWare.CreateSubKey "Pen" --Creates a new key.

--This isn't working. Can any one shed any light on it?
pen.SetValue "Version" 1.0 --Errors

pen.close()
softWare.close()
Hi Pen! My first filling would be that .net can't convert the value "1.0" to an appropriate "object" value (as setValue is expecting a Object value). Using something likesetValue("DWordValue", 42, RegistryValueKind.DWord)might help...Obviously you will need to "pre-load" the registerValueKind enumeration struct...

Using the "setValue" method as you have implies a RegisterValueKind.Unknown, which might be the reason you are having problems.

The only other thing that comes to mind is trying to convert the value to a .net double, but .net doesn't have a "object" representation of it's primitive types, so I'm not sure if it will really work...but you could use something likeSystem.Double.TryParse "1.0" (obviously I've not loaded the assembly, but simply used the calling convention here)

I will have a closer look at it when I get to work this morning...:P

Shane

PEN
03-24-2008, 08:23 PM
Thanks Shane but I'm still getting errors with lines like this.

pen.SetValue "Version" "1.0" (dotNetClass "Microsoft.Win32.RegistryValueKind").String --Errors

I might have to resort to doing it with DOS but that is just a pain.

RustyKnight
03-24-2008, 10:17 PM
Forgive me if I don't accept that as a valid workaround... reg=dotNetClass "Microsoft.Win32.Registry"

reg.LocalMachine.GetSubKeyNames()

softWare=reg.LocalMachine.OpenSubKey "SOFTWARE" true --Opens key and makes it writable.
pen=softWare.CreateSubKey "Pen" --Creates a new key.

dnStr = dotNetObject "System.String" "1.0"

--This isn't working. Can any one shed any light on it?
pen.SetValue "Version" dnStr --Errors

format "%\n" (pen.GetValue("Version"))

pen.close()
softWare.close()This didn't throw any errors. Can't say for 100% that it worked, but at least it didn't cry...

Shane

RustyKnight
03-24-2008, 10:20 PM
Verified(
reg=dotNetClass "Microsoft.Win32.Registry"

reg.LocalMachine.GetSubKeyNames()

softWare=reg.LocalMachine.OpenSubKey "SOFTWARE" true --Opens key and makes it writable.
pen=softWare.OpenSubKey "Pen"

format "%\n" (pen.GetValue("Version"))

pen.close()
softWare.close()
)Produces "1.0"

PEN
03-24-2008, 11:18 PM
Interesting. So this is only a string how ever. now I'm wondering how it will take a integer as I don't see a way yet in dotNet to make an int object.

Thanks for the help.

RustyKnight
03-24-2008, 11:37 PM
Oh, i've been banging my head against a wall over that one to...

First I triedlocal dValue = (dotnetclass "System.Convert").toDouble("1.1")Now that does SOMETHING, but when you try and pass through the setValue method MAX has a whinge that it can't find an appropriate method...

Presumably, .net's primative's are also a special type of "object" that max doesn't recognise...oh joy

Now, I'm probably missing something, but I've not yet had any luck with trying to use numbers...

edt: ps - Oh the joys of not coding in a pure OO language...I'm going to get flammed for that aren't I...;)

RustyKnight
03-25-2008, 01:35 AM
I've been reading through a whole bunch of documentation and it would appear that, from my perspetive, I'm reasonable right...always room for improvement. But at least from max's point of view I'm right.

We can't pass a "primitive" type to a dotnet class requiring an "Object" type, because the cross over implementation does not allow for converstion between them.

Having said that, it is possible to be done, inside dotnet. Basically, the suggested method is to create an "Object", then point the object at the value and pass the object to the class...double dValue = 1.1
Object o = new Object()
o = dValue
we can't do that...I've tried.

The only other thing I can think off is to write a "wrapper" object which does it for you...but that kinda defeats the purpose...

Shane

PEN
03-25-2008, 01:20 PM
Well Shane thanks for the info again. So it is a Max limitation with dotNet? A limitation with dotNet it self or a bit of both? I gather it is more Max then dotNet if we could do it in dotNet. I will put in a request to see if it can be corrected.

PEN
03-25-2008, 03:03 PM
Thanks go to Grant Adam for this one Shane...

dValue = dotNetObject "System.Double" 32
pen.SetValue "Double" dValue

RustyKnight
03-25-2008, 10:41 PM
I tried doing something like that but couldn't get it to work...obviously missed something...also the fact that "Double" is listed as struct without constructors in the docs makes it little obscure...

Nice to know though!

Shane

ypuech
03-26-2008, 08:24 AM
Such pure conversion to .NET type is sometimes required, for example in the use of a .NET array:

-- Create a .NET array of 10 integers
intArray = dotNetObject "System.Int32[]" 10

-- Fill array
for idx = 1 to 10 do
(
intValue = dotNetObject "System.Int32" (random 1 100)
intIndex = dotNetObject "System.Int32" (idx-1)
intArray.SetValue intValue intIndex
)

-- Print array data
for idx = 1 to 10 do
(
intIndex = dotNetObject "System.Int32" (idx-1)
print (intArray.GetValue intIndex)
)

Kameleon
03-26-2008, 01:12 PM
Can anyone show me an example of reading a XML file or string ? Thanks in advance

PEN
03-26-2008, 01:24 PM
Here is a thread where I have posted information about writting XML files. This should get you started.

http://forums.cgsociety.org/showthread.php?f=98&t=590934&page=2&highlight=xml

Reading XML is just as easy, it will allow you to read in each node as an object and get the properties for it. You then can recursively search and read all the objects in the XML file.

PEN
03-26-2008, 01:26 PM
Nice one. I'm still working very slowely on a Dot Net page for my site, mind if I use this example? Full credit of course.

Such pure conversion to .NET type is sometimes required, for example in the use of a .NET array:

-- Create a .NET array of 10 integers
intArray = dotNetObject "System.Int32[]" 10

-- Fill array
for idx = 1 to 10 do
(
intValue = dotNetObject "System.Int32" (random 1 100)
intIndex = dotNetObject "System.Int32" (idx-1)
intArray.SetValue intValue intIndex
)

-- Print array data
for idx = 1 to 10 do
(
intIndex = dotNetObject "System.Int32" (idx-1)
print (intArray.GetValue intIndex)
)

ypuech
03-26-2008, 01:46 PM
Nice one. I'm still working very slowely on a Dot Net page for my site, mind if I use this example? Full credit of course.
You can use it as you want but the credit goes to an Area member : KoichiSenada (http://area.autodesk.com/index.php/forums/viewthread/3651/#11557). I don't know if he is a CGTalk member.
I never succeed in working with .NET arrays before his post and now I can use more advanced methods of .NET framework.

I'm also working (very slowely :)) on adding new pages and articles about using .NET in MAXScript. I'll post these on my web when I'll have time.

KoichiSenada
04-03-2008, 11:57 AM
Uh!
Hello everybody, ypuech especially!
I was just wondering what's going on these days in this thread, and was really surprised to see the same issues that I was working with. :)
For example, reading XML files.
If anyone is still intrested in more samples, I can provide a link to my macroscript, that I've developed with Yannick Puech:
KoichiSenada / 3dsMax / 3dsMaxConvertXml (http://www.4shared.com/dir/5807782/1c394251/KoichiSenada.html)

KoichiSenada
04-03-2008, 12:05 PM
Hello everybody and ypuech especially!
I was just wondering what's going on in this thread lately.
And I was quite suprised to see that those are things I was working on earlier.
If anyone still wants more examples of reading XML files, check out macroscript that I have written with Yannick Puech:
KoichiSenada / 3dsMax / 3dsMaxConvertXml (http://www.4shared.com/dir/5807782/1c394251/KoichiSenada.html)

ypuech
04-03-2008, 12:53 PM
Hello everybody and ypuech especially!
I was just wondering what's going on in this thread lately.
And I was quite suprised to see that those are things I was working on earlier.
If anyone still wants more examples of reading XML files, check out macroscript that I have written with Yannick Puech:
KoichiSenada / 3dsMax / 3dsMaxConvertXml (http://www.4shared.com/dir/5807782/1c394251/KoichiSenada.html)
Hi Koichi,

Glad to see you here on CGTalk!
And thanks for sharing!

About .NET, I'm currently working on some articles about using GDI+ and some media classes of the framework in MAXScript. Stay tuned!

RustyKnight
04-03-2008, 11:12 PM
Hi KoichiSenada! Thanks for the share!!

I actually did a wrapper recently between the ActiveX and .Net XML implementations to help with the transition between max 8 and 9. Lots-o-fun...:P

I'd love to have more time to play around with it, but have other things I'm suppose to be doing...:P

I like that fact that people are able to build there own assembilies!! This makes extending the platform so much eaiser the writting physical plugins (as an assembily can be written once and, in theory, work in many versions of max!!)

I would say though, that implementing .net into max script (while required for the move to 64bit) was a awsome idea on the part of the 3ds engineers!! It's nice to be working within a standardised API (well more so then the ActiveX API ever was ;))

Shane

KoichiSenada
04-04-2008, 06:23 AM
Uh, I'm glad that my post was useful!
I'm also glad that 3dsMax now has .NET Framework support with assemblies allowed (running on x32 and x64, by the way).
Actually, the .NET assembly is what I'm most thankful to ypuech! Without his support I would probably never end up with an assembly, lacking which my script was too slow and even hanging while parsing Base64 encoded strings containing textures.

Well, about XML parsing.
I'm sure there's some advanced script to be done, for traversing XML structures based on node names and node parameters, and also merging numberous XML files based on links, and also smooth converting data from an XML node into 3dsMax struct.
Though, this idea is quite raw, and I'm hoping someone advanced with XML parsing would offer a complete idea or even some script for that.
An idea would be great enough, becouse I'd be more than happy to implement it when possible.

Koichi Senada, Russia.

RustyKnight
04-04-2008, 06:40 AM
I don't know about merging, but it should be possible. As for traversing, depending on what your needs are, look up XPath, the .net XML implementation provides a rather good XPath implementation.

Basically, it's a query language for XML, allows you to perform some rather complex queries against XML documents, based on node names, parameter values and even node values...

Worth a look
Shane

KoichiSenada
04-04-2008, 06:50 AM
I've tried to traverse XML files by queries, but haven't succeeded with that.
The only working result I've achived was to iterate though children nodes enumeration.

Though, I also think it's worth some more R&D, probaby it can be done.
Even if it's not, traversing through children nodes enumeration is still good enough, since what should be done is to check if nodes are present, and what types (based on names and xsi:type parameters) they are. When a match is found, populate 3dsMax structs with node data. Sure, the structs and objects are to be linked as nodes are.

Probably someone has another ideas which I'd be glad to know. :)

RustyKnight
04-04-2008, 08:14 AM
Oh god....I use to do that...

I want some obscure node, in the middle of the tree, who's parent has some value, but not some other...and excuse me if spending the next two hours trying to write the code to do that makes me want to gouge my own brain out with an icy pole stick...again...sorry...

When everyone else was jumping up and down like Japanese school girls at phone accessory stand over XML when it was first released...I spent my time trying to figure out how the hell I was going to get what I wanted out of it in simple, concise and consistent manner...without 2 million lines of code...

Don't get me wrong, I love XML as file format/data structure, it rocks...but as far as it’s navigation mechanism, it left a lot to be desired :P

Then I found xPath, and while I have to admit, I still don't fully understand how it works, it is a life saver (and saves me from sticking icy pole sticks up my nose, which I can assure you, the other developers appreciate).

I would encourage you to spend some time figuring it out, even if it only does the "mundane", "everyday" queries, that has to be a MASSIVE saving in time and effort.

But that's just what I think ;)

Shane


ps - I hate admitting it, but the .net xPath implementation is rather good.

KoichiSenada
04-04-2008, 08:32 AM
RustyKnight, alright, I've got it that you use it and you like it and it works.
Seems like I've been doing something wrong or something else but xPath.
Can you please present some small script of using xPath? :)

Koichi Senada, Russia.

Kameleon
04-04-2008, 12:13 PM
Hi guys! I'm also starting up with XML and wrote a simple script, here's a little bit of code where I used xPath in a very simple form, but I guess it's not very dificult to implement more complex querys.


fn load_xml thefilename =
(
lst_xml.items.clear()
xml=dotnetobject "System.Xml.XmlDocument"

xml.load thefilename

xpath="//Arch___Design__mi"
fnode=xml.SelectNodes xpath
for i=0 to fnode.count-1 do
(
xel=fnode.item(i)
lst_xml.items.insert i xel.firstchild.innertext
)
theloadedfile=thefilename
)


Cyas!

KoichiSenada
04-04-2008, 12:40 PM
Kameleon, thank you for your code!
I'll definitely use it next time I'll be working with XML files.
Though, most of my time I needed to parse every node's every child.
Thanks for sharing!

Kameleon
04-04-2008, 01:02 PM
And here's the MSDN link to XPath Syntax.

http://msdn2.microsoft.com/en-us/library/ms256471(VS.85).aspx

KoichiSenada
04-04-2008, 01:19 PM
Uh, sure!
I would just never comply any .NET Framework using script without MSDN Library ...
http://msdn2.microsoft.com/en-us/library/
Thanks for the direct link, Kameleon!

RustyKnight
04-04-2008, 11:18 PM
Kameleon, thank you for your code!
I'll definitely use it next time I'll be working with XML files.
Though, most of my time I needed to parse every node's every child.
Thanks for sharing!My current code is a little coupled together at the mo, but given a structure simular to this
<ToolBar>
<item name="Setup Crimson Editor" catagory="Tools" parent="shanew" key="9">
<source>RegisterOLEControl.ms</source>
</item>
<item name="Point Cache 2 Wizard - v02.00" catagory="01_Animation" parent="shanew" key="12">
<macro offset="34328" length="814" catagory="Personal" name="zoPointCacheWizard"/>
</item>
</ToolBar>One could search for nodes using something like this-- Search query
local sXPath = "//item[@key='" + (iKey as string) + "']"

-- Find the specified node
local xmlNode = rootNode.selectSingleNode sXPath
This will search for all items, starting at the top of the document (or current node) whose property named "key" has the specified value.

I've done some more complex searches then this, using a chain of parent nodes to find all the child nodes, simular to a file/directory structure. Makes like SOOO mych easier!

Shane

Shane

Mr-BlueSummers
04-06-2008, 09:58 AM
Hey,

I realize I don't post here much, but I wrote something recently that I'd like to add to the DotNet pile. It's a lean executable that converts the 3dsMax native icon strips and alphas into individual .png files with premultiplied alphas. This way you can use the native 3dsMax icons in DotNet forms quickly and directly.

P.S. I'm unsure if it works in an 64-bit install...

>>www.mrbluesummers.com (http://www.mrbluesummers.com)

Cheers

RustyKnight
04-07-2008, 12:08 AM
Hay Mr-BlueSummers, with something that cool, you should post more often!!

Cheers
Shane

specxor
04-07-2008, 12:47 AM
Hi Guys,

I know there has been allot of talk about XML in this thread, here is my very small contribution to the great info here. I wrote two structs that wrap dotNets xml classes, they are very simple but make it a little easier to work with xml. I mostly use these for saving settings and writing configs etc.

There are two structs XMLDocument for working with xml files and XMLNode I have provided a test at the end of the ms file.

Cheers
Dave

KoichiSenada
04-07-2008, 07:57 AM
Thanks for your sharing, guys!
All those things are greatly useful. :)

By the way, can someone land me a hand on modifying texture coordinates for my script?
I just have a small annoying issue with flipped and 180 degrees rotated textures.
Users told me that they fix it manually via modifiers, though I'd want to fix it automatically.
If anyone is familiar with texture coordinates and effects on changing them, please pm me or give me a link here... Thanks!

Kameleon
04-17-2008, 06:59 PM
Hi guys, I'm having trouble setting the value for a numericupdownspinner in Max 2008, it works in Max 2009, it says it should be Decimal, but even when I try to declare it as Decimal or convert it to decimal, it says it should be Int32... some weird sh*t!

Here's the code:


nm_slot=dotnetobject "System.Windows.Forms.NumericUpDown"
nm_slot.size = dotNetObject "System.Drawing.Size" 40 10
nm_slot.Location=dotNetObject "System.Drawing.Point" 40 312
nm_slot.Value=1
nm_slot.Minimum=1
nm_slot.Maximum=24


Any word on this?

KoichiSenada
04-18-2008, 06:02 AM
Kameleon, hi there!
So, 3dsMax 2009 works better with autoconversion, then.
Well, youcould try some direct dotNetObject creation or some SetValue() to make them what you want them to be (Decimal).
Which variable (object) behaves wrong?

Kameleon
04-18-2008, 09:56 AM
Hey Koichi, thanks for the reply! Yeah 3dsmax2009 works definitely better. I've already tried converting it to decimal using (dotnetobject "System.Decimal" 1) but then it gives another error, saying the variable cant be converted from Decimal to Int32 or something like that, very very weird! I've also tried using ((dotnetclass "System.Convert").ToDec 1) but then it just gives me another error with something concerning UInt64.

It really seems that Max2008 cant handle at least Decimal conversions very well. The values in cause are those last 3, Value, Minimum and Maximum, all 3 decimal values. About the setValue() I dont know how to work with it, can you explain it to me? Thanks!

KoichiSenada
04-18-2008, 10:23 AM
Kameleon, alright, try this piece:
clearListener()
dotnet.loadassembly "System"
uint64 = dotNetObject "System.UInt64" 50
dec = dotNetObject "System.Decimal" uint64
format "uint64: %\n" uint64
format "dec: %\n" dec
In my case it has produced:
uint64: dotNetObject:System.Int64
dec: dotNetObject:System.Decimal
Also, your properties (Value, Minimum, Maximum) have accepted the dec object.
Is that the it?

Kameleon
04-18-2008, 11:35 AM
It worked flawless! Thanks alot man, and now that I see how you did it, I did understand it... hehe it makes perfect sense, once again thanks!!!

KoichiSenada
04-18-2008, 11:37 AM
Kameleon, good for you! :)
Aren't you goint to show your tool when it's done?

Kameleon
04-18-2008, 11:42 AM
Sure Koichi, as the matter of fact I've already posted it, but it doesnt seem to get any atention hehe, here it is:

http://forums.cgsociety.org/showthread.php?f=98&t=618821

It's a XML Importer/Exporter for mentalray materials.

Kameleon
04-23-2008, 08:26 PM
Also, App.Run() is better than Form.Show() because it initializes well the dialog and the keyboard handling. With Form.Show(), Max intercepts all the keyboard messages when writting in the TextBox...

I've found that by using this, the Max Viewport doesnt redraw correctly, only when the form is closed, is there anyway to do this instead of going back to the hForm.Show() ?

KoichiSenada
04-24-2008, 06:06 AM
Kameleon, I've also had this trouble, but haven't managed to work it out.
I've seen I great macro Outliner (http://www.scriptspot.com/3ds-max/outliner) by Pier Janssen.
It works inside of 3dsMax rollout floater, which is great about docking it.
I tried to use that, since it draws the form and scene at once, but this method doesn't draw DataGridView control, the DataTable is just not populated. All the other controls seem to work fine.
I think you could try it, maybe even with DataGridView if you can do the hack.
Probably the DataTable population can be handled with separate .NET assembly.

Kameleon
04-24-2008, 09:53 AM
Hi Koichi, actually I dont have any trouble with hForm.Show yet, that I know of, I just used hApp.Run because I saw here that was the best method, but since it has that redraw problem with the viewports, I'll just stick to hForm.Show, do you have trouble using that?

KoichiSenada
04-24-2008, 09:59 AM
Kameleon, well, yes, it doesn't draw DataGridView when used within a rollout floater.
The only working method for me still is Application.Run()
Good for you if you don't need DataGridView. :)
Though, the control is very useful, I just can't replace it with any other control now...

Kameleon
04-24-2008, 10:05 AM
Hmmm I dont quite understand, I dont use rollout floaters either! And everyone needs DataGridView hehe :) I just use dotnet forms, I dont use any of Max controls, but instead of doing:


hApp = dotNetClass "System.Windows.Forms.Application"
hApp.Run hForm


I just do hForm.Show and voila :P Maybe I' beeing stupid here, sorry for that :D

Kameleon
04-24-2008, 05:10 PM
Yeah, I was being stoopid :P Thank god there's yupech :)


See here : http://forums.cgsociety.org/showpost.php?p=4745704&postcount=37

Theres a dotNetObject "MaxCustomControls.MaxForm" that does the trick.

JHN
04-30-2008, 09:34 PM
I finally installed visual c# express and made a dll to try out if I can make a simple dotnet object.
It's quite simple, got a working dll in 20 minutes or something. I just did some tests to see if I could speed up some stuff... but what I was trying was not really faster.
I wanted to fill an array with string and concatenate them to a large string, since I know max is very memory hungry with strings..

script:

(
itt = 10000

start = timeStamp()

dotnet.loadAssembly "$scripts\\jhn\\jhnOps.dll"
hw = dotNetObject "jhnOps.ls_build"

for i=1 to itt do hw.addVal (dotnetObject "System.String" (i as string))
s = (dotnetObject "System.String" (hw.getValue()))
print (s.ToString())
end = timeStamp()


format ".NET | Processing took % seconds\n" ((end - start) / 1000.0)

/*###########################################*/


start = timeStamp()

arr = #()
str = ""
arr = for i=1 to itt collect (i as string)
for ss in arr do str += ","+ss
print str

end = timeStamp()

format "MXS | Processing took % seconds\n" ((end - start) / 1000.0)
)
/*
gc()
*/


for those interested
dll = http://scripts.subd.nl/?f=jhnOps.dll
src = http://scripts.subd.nl/?f=jhnOps.cs

My findings are with 10.000 itterations adding an integer as string:
.NET | Processing took 3.094 seconds
MXS | Processing took 2.657 seconds

Memory consumption was different, I don't have exact figures but with .Net processing I saw my memory increase some megabytes, with MXS I saw it go up a ~ 300/400 MB's!

So for this type of situation it's a tradeoff, memory vs speed...

My questions are these:
1. Can I make custom classes, like a Key (keyframe) class in .NET and directly apply it back to a controller?
2. Which functions really would benefit from a dotnet implementation?
3. Would it be wise to do a lot of processing in a .NET object and in the end execute all the data as 1 big string?

Thanks,
-Johan

KoichiSenada
05-04-2008, 06:28 AM
Yeah, I was being stoopid :P Thank god there's yupech :)


See here : http://forums.cgsociety.org/showpost.php?p=4745704&postcount=37

Theres a dotNetObject "MaxCustomControls.MaxForm" that does the trick.
Kameleon, thank you for that link! I've missed that before.
I really should to try it (MaxForm) with DataGridView. :)
Is there any screenshot of what MaxForm looks like?

Mr-BlueSummers
05-04-2008, 06:52 AM
Hey guys,

I asked this on another thread, but it has to do with .net also so I might as well ask here.

Is there any way to bind the isChecked functionality of a macroscript (like "Box") such that I can get my .net form buttons to stay down when the macroscript functionality it calls (again, like "Creating a Box") is in use?

KoichiSenada
05-04-2008, 08:37 AM
Mr-BlueSummers, I wanted that functionality with a .NET control, but haven't found it while doing my script.
Later, I've found out that System.Windows.Forms.Checkbox (http://msdn.microsoft.com/en-us/library/system.windows.forms.checkbox.aspx) has Appearance (http://msdn.microsoft.com/en-us/library/system.windows.forms.checkbox.appearance.aspx) property which displays it as a toggle button when set to "Button" instead of default "Normal" value which displays it as a standard checkbox square.
Is that what you want?

KoichiSenada
05-04-2008, 08:45 AM
My questions are these:
1. Can I make custom classes, like a Key (keyframe) class in .NET and directly apply it back to a controller?
2. Which functions really would benefit from a dotnet implementation?
3. Would it be wise to do a lot of processing in a .NET object and in the end execute all the data as 1 big string?
Thanks,
-Johan
Well, the best advice I can give is to try it for yourself.
I just can tell you about my own experience.
I was trying to work with huge arrays [2048x2048x4] of texture data parsed as integer/string.
3dsMax hangs with that, while doing ok with small [128x128x4] arrays.
That's why the only way out was to create an assembly which took a single string to parse it into bytes and then into bitmaps.
I think it's wise to do all this dirty work by a .NET object, when it doesn't involve special 3dsMax classes like keyframe.
I'm happy with parsing strings, integers, files, etc by .NET objects.
But I can't tell the same before 3dsMax SDK is learned.
Though, I suppose it's possible, otherwise writing plugins would be a hell.

Mr-BlueSummers
05-05-2008, 06:09 PM
Mr-BlueSummers, I wanted that functionality with a .NET control, but haven't found it while doing my script.
Later, I've found out that System.Windows.Forms.Checkbox (http://msdn.microsoft.com/en-us/library/system.windows.forms.checkbox.aspx) has Appearance (http://msdn.microsoft.com/en-us/library/system.windows.forms.checkbox.appearance.aspx) property which displays it as a toggle button when set to "Button" instead of default "Normal" value which displays it as a standard checkbox square.
Is that what you want?

Hey Koichi!

That's close. I've already got a .net button that will respond to toggling (stay down, pop up on a boolean). My trouble comes from the maxscript/DotNet connection itself. How can I get it to toggle down when the user starts using the macroscript tool, but toggle up when the user puts down the tool.

In the case of the Box macroscript:

on execute do StartObjectCreation Box
on isChecked return (mcrUtils.IsCreating Box)


Does that isChecked line suggest that when the user stops creating a box, the expression in parens will return false, causing the button to pop-up? How could I do this connection with a .Net button instead of a Maxscript button?

Mr-BlueSummers
05-05-2008, 06:14 PM
I wonder if it's possible to pass a reference across the DotNet bridge...
For example, when the button (or checkbox) is pressed, you can pass a reference to the return value of the macroscript into the parameter of the checkbox that controls "IsPressed".

Think that might do the trick?

EDIT: Here's some code for testing this stuff...

(
fn whenCheckboxIsPressed a b =
(
-- This links us to the "OnExecute" event, which returns
-- OK and throws an error.

-- We want to link to the "OnChecked" event...
a.checked = (Macros.run 22615)
)

--Create a DotNet Checkbox
mCheckbox = dotNetObject "System.Windows.Forms.Checkbox"
mCheckbox.text = "BIG DotNet Button"
mCheckbox.size = dotNetObject "System.Drawing.Size" 160 160
mCheckbox.location = dotNetObject "System.Drawing.Point" 60 60

--Create a DotNet Form
hForm = dotNetObject "System.Windows.Forms.Form"
hForm.controls.add mCheckbox --add the Button to the Form
hForm.topmost = true
--Add an Event Handler for the click event:
dotNet.addEventHandler mCheckbox "click" whenCheckboxIsPressed

hForm.show() --show the Form with the Checkbox
)


Maybe if there was some way to access the OnChecked aspect of the macroscript and pass that back to the .net checkbox IsChecked parameter...

Mr-BlueSummers
05-05-2008, 09:09 PM
Looks like it's more difficult than I thought.

I tried storing the MCRUtils.IsCreating Box block in the mCheckbox.checked property, but it stored the result, not a reference. I tried passing &Variable but that failed too. =(

KoichiSenada
05-06-2008, 05:43 AM
Mr-BlueSummers (http://forums.cgsociety.org/member.php?u=116527), it's not really clear what you want.
I guess you want to have "Checked" property to be changed everytime a user "starts using"/"puts down" some tool.
In that case you have to set it directly while parsing those user events.
Sure thing the properties store the result, not a reference.
You are handling "Click" event of the CheckBox, but you have to handle those "start using"/"put down" events as well. Is that a problem?

Mr-BlueSummers
05-06-2008, 06:47 AM
Exactly!

I'm trying to replicate the Macroscript button functionality in a DotNet control.

When the user clicks the button, it should be "checked" for as long as the user is using the tool (or window) associated with that button.

Would I have to evaluate that all the time, or is there some way to have it bind automatically as though it were a macroscript button? Again, I'm assuming that it is the "OnChecked" event handler that is associated with controlling whether the button is "checked" or not.

KoichiSenada
05-06-2008, 07:03 AM
Mr-BlueSummers, first we have to make things clear - which event is supposed to fire what?

When toggling the button should show/close another Form, use CheckBox events like "CheckBox.CheckedChanged (http://msdn.microsoft.com/en-us/library/system.windows.forms.checkbox.checkedchanged.aspx)" or "CheckBox.CheckedStateChanged (http://msdn.microsoft.com/en-us/library/system.windows.forms.checkbox.checkstatechanged.aspx)" to fire Form.Show() or Form.Close().

When showing or closing the form should change the CheckBox.Checked, use Form events like "Form.Shown (http://msdn.microsoft.com/en-us/library/system.windows.forms.form.shown.aspx)" or "Form.Closed (http://msdn.microsoft.com/en-us/library/system.windows.forms.form.closed.aspx)"

What's the problem actually?

Mr-BlueSummers
05-06-2008, 05:56 PM
The issue comes up when we're trying to bind DotNet form elements to macroscripts. Each default macroscript contains two sets of functionality; one that conducts the purpose of the maxscript and one that conducts how the button shoud be pressed/unpressed.

I use "Box" as an example because it's very simple. My goal is to create a DotNet button that will operate like the "Box" macroscript button. On pressed, it will run "StartObjectCreation Box". However, it will only stay depressed until "MCRUtils.IsCreating Box" returns false.

While it's easy to get the DotNet checkbox to invoke "StartObjectCreation Box", I'm finding it much harder to have the checkbox respond immediatly when "MCRUtils.IsCreating Box" turns false.

Mr-BlueSummers
05-09-2008, 06:39 AM
Any thoughts on how this might be accomplished?

Next attempt: Setting a timer to tick and update the UI...

Mr-BlueSummers
05-09-2008, 07:14 PM
PEN and I sorted it out on another forum. Kudos to him and his excellent brain meats!
Looks like just updating the UI's "checked" params is enough to give the appearance of responsivness. I did some tests using 3 UI items and a tick-rate of 200x per second, and I saw no render performance hit.


global hForm, mCheckbox, thisTimer

(
fn whenCheckboxIsPressed a b =
(
if MCRUtils.IsCreating Box
then (Max Select; try((hForm.controls.item(0)).checked = false) catch())
else Macros.run 26615
)

fn updateUI =
(
try(
(hForm.controls.item(0)).checked = MCRUtils.IsCreating Box
) catch()
)

--Create a DotNet Checkbox
mCheckbox = dotNetObject "System.Windows.Forms.Checkbox"
mCheckbox.appearance = (dotnetClass "System.Windows.Forms.Appearance").Button
mCheckbox.text = "Box Button"
mCheckbox.location = dotNetObject "System.Drawing.Point" 0 0

--Create a DotNet Form
global hForm = dotNetObject "System.Windows.Forms.Form"
hForm.topmost = true
hForm.controls.add mCheckbox --add the Button to the Form

thisTimer = dotNetObject "System.Windows.Forms.Timer"
thisTimer.interval = 10
thisTimer.start()

--Add an Event Handler for the click event:
dotNet.addEventHandler mCheckbox "click" whenCheckboxIsPressed
dotNet.addEventHandler thisTimer "tick" updateUI

hForm.show() --show the Form with the Checkbox
)


No viewport hit either.

Eric-Harvey
05-29-2008, 06:48 PM
I am wondering if anyone knows how to change the position of items in a .net listview. I dont mean changing their order in terms of rows and columns, but within each cell of the listview I would like to move the position of the text. By default the text is always just left justified.

Thanks

PEN
05-29-2008, 07:29 PM
I gather you mean horizontaly Eric? I don't see any way to justify the text but you acn just add spaces to move it over. What is it you are trying to do?

Eric-Harvey
05-29-2008, 07:37 PM
hey Paul,

basically what I am trying to do is have the position be editable, or be able to be centered based on the size of the supplied text.

RustyKnight
05-29-2008, 11:11 PM
I am wondering if anyone knows how to change the position of items in a .net listview. I dont mean changing their order in terms of rows and columns, but within each cell of the listview I would like to move the position of the text. By default the text is always just left justified.

ThanksHi Eric!

I was going to suggest to have a look at the ListView.Alignment property, but after more reading, I don't think it will do what you want.

I think in this instance, you really need to look towards customising the control directly in .net. Either through the owner draw method or the layout engine property...although I'd like to be proved wrong...

Shane

JHN
06-16-2008, 02:03 PM
Have a look at this thread, dynamicly compiling a dotnetObjects during maxscript runtime

http://area.autodesk.com/index.php/forums/viewthread/13286/


-Johan

ypuech
06-16-2008, 02:34 PM
Have a look at this thread, dynamicly compiling a dotnetObjects during maxscript runtime

http://area.autodesk.com/index.php/forums/viewthread/13286/


-Johan
This code looks very interesting and useful.

f97ao
06-17-2008, 09:02 AM
My questions are these:
1. Can I make custom classes, like a Key (keyframe) class in .NET and directly apply it back to a controller?
2. Which functions really would benefit from a dotnet implementation?
3. Would it be wise to do a lot of processing in a .NET object and in the end execute all the data as 1 big string?

Thanks,
-Johan

Just a quick question Johan. When you were using the dot Net, did you compile to Runtime or was it in Debug?
Runtime is WAY faster than debug so I'm thinking maybe you were running in debug mode. I really expect NET to be faster than MaxScript.

Cheers!
/Andreas

JHN
06-17-2008, 11:20 AM
Andreas, I'm afraid I don't really know. I build a simple dll in Visual Studio, I don't know how to set it to debug or not.. I left everything as default.. today I looked at it again and couldn't find a option that discribes it.

I did add some code and do a runtime compile, but it was still slower, consider the following


(
itt = 20000

--dotnet.loadAssembly "$scripts\\jhn\\jhnOps.dll"
dotnet.loadAssembly "C:\\_script_Depot\\Visual C# 2008\\jhnOps\\jhnOps\\bin\\Release\\jhnOps.dll"
hw = dotNetObject "jhnOps.ls_build"

start = timeStamp()

--for i=1 to itt do hw.addVal (dotnetObject "System.String" (i as string))
for i=1 to itt do hw.addVal (i as string)
s = (dotnetObject "System.String" (hw.getValue()))
--print (s.ToString())
end = timeStamp()


format ".NET | Processing took % seconds\n" ((end - start) / 1000.0)

/*###########################################*/


start = timeStamp()

arr = #()
str = ""
arr = for i=1 to itt collect (i as string)
for ss in arr do str += ","+ss
--print str

end = timeStamp()

format "MXS | Processing took % seconds\n" ((end - start) / 1000.0)

/*###########################################*/

fn CreateAssembly src =
(
/*
code compilation based on an example from Kim David Hauser
click on the link (http://www.codeproject.com/KB/cs/evalcscode.aspx)
*/
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.CompilerOptions = "/t:library"
compilerParams.GenerateInMemory = true
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(src)

if (compilerResults.Errors.Count > 0 ) then
(
errs = stringstream ""
for i = 0 to (compilerResults.Errors.Count-1) do
(
err = compilerResults.Errors.Item[i]
format "Error:% Line:% Column:% %\n" err.ErrorNumber err.Line \
err.Column err.ErrorText to:errs
)
MessageBox (errs as string) title: "Errors encountered while compiling C# code"
return undefined
)

a = compilerResults.CompiledAssembly
)

fn CompileByteArrayTools =
(
sb = "using System;\n"
sb += "using System.Collections;\n"
--sb += "using System.Collections.Generic;\n"
--sb += "using System.Linq;\n"
sb += "using System.Text;\n"

sb += "public class ls_build\n"
sb += "{\n"

sb += " private ArrayList bulk = new ArrayList();\n"
sb += " public string rebulk = \"\";\n"

sb += " public ls_build() { }\n"

sb += " public bool addVal(string val)\n"
sb += " {\n"
sb += " this.bulk.Add(val);\n"
sb += " return true;\n"
sb += " }\n"

sb += " public string getValue()\n"
sb += " {\n"
sb += " foreach (string n in this.bulk)\n"
sb += " {\n"
sb += " this.rebulk += \",\"+n;\n"
sb += " }\n"

sb += " return this.rebulk;\n"
sb += " }\n"
sb += " } \n"
a = CreateAssembly sb
a.CreateInstance "ls_build"
)

global jhn = CompileByteArrayTools()

start = timeStamp()

for i in 1 to itt do
jhn.AddVal (i as string)

jhn.getValue()

end = timeStamp()

format "Runtime .Net | Processing took % seconds\n" ((end - start) / 1000.0)

)
/*
gc()
*/



at 10.000 iterations mxs is faster, but with 5000 it's slower... I can't figure out why exactly.. I can only see mxs is very very memory hungry. You can use the same dll as I posted below... funny thing this runtime compile... you can simply have a .cs beside your script and feed it to the compile function... this will make VS absolete, althoughg no debugging...

Sorry not a concrete answer, and maybe I'm using .Net wrongly... haven't invested any more time in it, since I couldn't use max classes directly in .Net... I really want a extension which I can pass in a spline and gets me an array of vertex positions, fast.

-Johan

KoichiSenada
06-18-2008, 06:20 AM
I am wondering if anyone knows how to change the position of items in a .net listview. I dont mean changing their order in terms of rows and columns, but within each cell of the listview I would like to move the position of the text. By default the text is always just left justified.Thanks
Hi Eric!
I am not sure if my method is ListView compatible, but here's what I did in my 3dsMaxConvertXml to position DataGrivView cells' items, shifting them right to 10 px:

offsetLeft = 10
paddingOffset = dotNetObject "System.Windows.Forms.Padding" offsetLeft 0 0 0
hDataGridView.Rows.Item[idRow].Cells.Item[idCell].Style.Padding = paddingOffset

This is what I do to have background and content to be drawn.
When the background is drawn, script draws more items, then content is drawn by handling the event:
fn paintingDataGridViewCell hDGV args = (
...
args.PaintBackground args.CellBounds true
...
/* background is drawn, drawing more items above the background, and then content is drawn */
...
args.PaintContent args.CellBounds
args.Handled = true
...
)
dotNet.addEventHandler hDataGridView "CellPainting" paintingDataGridViewCell

ypuech
06-18-2008, 08:40 AM
'm afraid I don't really know. I build a simple dll in Visual Studio, I don't know how to set it to debug or not.. I left everything as default.. today I looked at it again and couldn't find a option that discribes it.
On the toolbar there's a dropdownlist where you can choose the compilation mode : Debug or Release. Always distribute your binaries in Release mode.

PEN
06-18-2008, 02:35 PM
Have a look at this thread, dynamicly compiling a dotnetObjects during maxscript runtime
http://area.autodesk.com/index.php/forums/viewthread/13286/
-Johan

This is interesting, what advantages is this getting us instead of just creating a compiled DLL? Would this not be slower to load the first time then a DLL? I already see a major slow down when ever I need to call a .net object of class when a tool loads for the first time. It can be a bit of a pain if there are several of them. Would this cause more of a slow down?

JHN
06-18-2008, 05:25 PM
I haven't noticed any bigger slowdowns then compiled.. offcourse a compiled c# is also not bytecode it's gets compiled as well, just in time... so my guess is it isn't twice as slow.. but I only tried small objects... I think it's really a case of testing...

-Johan

PEN
06-18-2008, 06:05 PM
Advantages then?

magicm
06-18-2008, 10:25 PM
Advantages then?

I think the only advantage is that you don't need to include an external library with your script. Oh, and I guess it could be handy for debugging purposes as well. No need to rebuild/reload your library.

Martijn

JHN
06-19-2008, 08:13 AM
Exactly, and no need to quit max everytime you do a rebuild of the dll. Run and test the object and the maxscript in one go.

biddle
06-19-2008, 08:33 PM
FWIW, I've updated the original example on the Area to include an method that will convert an integer array to a byte array directly.

http://area.autodesk.com/index.php/forums/viewthread/13286/

.biddle

milo(6)
06-24-2008, 03:12 PM
Does anyone have any experience controlling excel through dotnet? I'm mainly interested in being able to write values out to a spread sheet, however I'm sure reading values back in would be more than useful to a lot of people.

The Maxscript help has references to opening excel spread sheets through active-x, however there is no documentation on how this can be achieved though dotnet.


Any help would be appreciated,

Milo

ypuech
06-24-2008, 04:50 PM
Does anyone have any experience controlling excel through dotnet? I'm mainly interested in being able to write values out to a spread sheet, however I'm sure reading values back in would be more than useful to a lot of people.

The Maxscript help has references to opening excel spread sheets through active-x, however there is no documentation on how this can be achieved though dotnet.
You can query or and modify an Excel worksheet through ADO.net. It is easily possible treating the excel file just like a database. ADO.net supports both 64bit and 32bit. So it's not necessary to interact directly with the Excel application.

Please visit this link:
http://www.knowdotnet.com/articles/exceldatasource.html

JHaywood
06-27-2008, 11:30 PM
I found a way (with a bit of help) to start a command line process and redirect its output stream directly to Max, as opposed to redirecting to a file and then reading that file. This lets you display the results in real time without having to wait for the process to finish. I just thought I'd share.

global processOutput_RLT
try (destroyDialog processOutput_RLT) catch()

rollout processOutput_RLT "Results" width:640 height:350
(
dotnetControl text_RTB "RichTextBox" width:640 height:350 offset:[-14,-4]

on processOutput_RLT open do
(
text_RTB.BorderStyle = text_RTB.BorderStyle.None
text_RTB.BackColor = text_RTB.BackColor.WhiteSmoke
text_RTB.ReadOnly= true
)
)

createDialog processOutput_RLT


fn outputDataReceivedHandler obj evt =
(
if evt.data != undefined then
(
processOutput_RLT.text_RTB.text += (evt.data + "\n")
format "%\n" evt.data
)
)

fn errorDataReceivedHandler obj evt =
(
if evt.data != undefined then
(
processOutput_RLT.text_RTB.text += ("Error: " + evt.data + "\n")
format "Error: %\n" evt.data
)
)

fn onExitHandler obj evt =
(
processOutput_RLT.text_RTB.text += "Finished!"
format "Finished!\n"
)

proc = dotNetObject "System.Diagnostics.Process"
proc.EnableRaisingEvents = true
-- add program info here
proc.StartInfo.WorkingDirectory = <folder string>
proc.StartInfo.FileName = <program string>
proc.StartInfo.Arguments = <argument string>
--
proc.StartInfo.UseShellExecute = false
proc.StartInfo.RedirectStandardOutput = true
proc.StartInfo.RedirectStandardError = true
proc.StartInfo.CreateNoWindow = true

dotNet.AddEventHandler proc "OutputDataReceived" outputDataReceivedHandler
dotNet.AddEventHandler proc "ErrorDataReceived" errorDataReceivedHandler
dotNet.AddEventHandler proc "Exited" onExitHandler

proc.Start()

proc.BeginErrorReadLine()
proc.BeginOutputReadLine()

PEN
07-01-2008, 08:22 PM
What is the best way to check if an XML doc that is beoing loaded is formated as an xml doc so that I don't get errors if the file has been hand formated and is not correct?

RustyKnight
07-02-2008, 12:22 AM
How do you mean? If you parse a document which is not a valid XML file, you should get an error which you should be able to catch..

Are you looking for a file that is purely NOT an XML file?? ie It does not have an <XML> tag??

You could read the first line and double check it for a valid value??

Or, if you have a schema, I picked up this code from the web, you will need to convert it to maxscript though
// I know it's possible, but I can't remeber of my head how you would set this up
ValidationEventHandler veh = new ValidationEventHandler(xvr_ValidationEventHandler);

// Read's the schema
XmlSchema schema = XmlSchema.Read(new XmlTextReader("../../productschema.xsd"), veh);


FileStream fs = File.Open("../../productcataloginstance.xml", FileMode.Open);
XmlDocument xdoc = new XmlDocument();
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add(schema);
settings.ValidationType = ValidationType.Schema; //this line is neccessary for validation to work

settings.ValidationEventHandler += new ValidationEventHandler(xvr_ValidationEventHandler);

XmlReader reader = XmlReader.Create("../../productcataloginstance.xml", settings);

xdoc.Load(reader);You could also wrap some of the code in your own assembly and use that as your validator, returning a valid XML file or undefined...or what ever it is you need to do...I'd think that would be the simplest method off hand...

Also check out http://www.codeguru.com/csharp/csharp/cs_data/xml/article.php/c6737/ although I think the method they use might be depreciated...

Shane

PEN
07-02-2008, 12:38 PM
Thanks Shane I will poke around at that. Might just leave it as everything I see looks like way more work then I want to bother with.

RustyKnight
07-03-2008, 01:10 AM
Thanks Shane I will poke around at that. Might just leave it as everything I see looks like way more work then I want to bother with.

Hay Paul. Sorry I don't have more time at the mo or I'd have a play around with it myself as it would be rather useful. Once were done upgrading our pipeline I might have more time (at lets face, I see a lot of XML parsing coming my way in the near future...)

Shane

decapitator
07-15-2008, 07:37 PM
Started with my first conversion of ActiveX listview to a DotNet version (ye late I know, but im not scripting for that long) but is there a way for a doubleclick to not toggle the checkbox? because I kinda want to use it for something else..
And god why does it trigger ItemCheck(ed) when initializing (well I know that but whats the way to just get the mouse related ones)..

erilaz
07-16-2008, 08:28 AM
Started with my first conversion of ActiveX listview to a DotNet version (ye late I know, but im not scripting for that long) but is there a way for a doubleclick to not toggle the checkbox? because I kinda want to use it for something else..


I'm not sure about the checkbox (I'm not using checkboxes), but i'm using the DoubleClick event to open files in ListView; would this example help you?


on lv_Files DoubleClick item do
(
mFileName = lv_Files.SelectedItems.Item[0].text
mFilePath = (thisProjectFolder)+"\\"+lv_Files.SelectedItems.Item[0].SubItems.Item[1].text
loadMaxFile (mFilePath + mFileName)
)

PEN
07-16-2008, 12:16 PM
Do a search, I think that some one else was having issues with the check boxes when launching.

decapitator
07-16-2008, 01:03 PM
PEN: I couldnt find anything searches for 'dotnet listview checkbox' just returned bogus threads for what I saw. But the checkbox initializing check isnt a real problem anymore just checked if state != thething.enabled set true/false so that it skips that instead of resetting the state. Though its still silly there isnt something for mouse state changes (or maybe check if mousebutton is down? sound silly though)

erilaz: It all works fine (the double click selects some objects, that wasnt the big problem) except for the double click also changing the state of the check, and I just want it to do what I tell it to do because im using the checkstate for enable/disable :(

PEN
07-16-2008, 01:56 PM
PEN: I couldnt find anything searches for 'dotnet listview checkbox' just returned bogus threads for what I saw. But the checkbox initializing check isnt a real problem anymore just checked if state != thething.enabled set true/false so that it skips that instead of resetting the state. Though its still silly there isnt something for mouse state changes (or maybe check if mousebutton is down? sound silly though)

erilaz: It all works fine (the double click selects some objects, that wasnt the big problem) except for the double click also changing the state of the check, and I just want it to do what I tell it to do because im using the checkstate for enable/disable :(

Does on doubleClick arg still work when you are over the checkBox? If so you could check to see if doubleClick has been called and set the checkBox back to what it was. A pain but a work around. Also you might be able to get the states of the mouse so right clicking on it would do something or you could use the keyBoard.shiftPressed and do it with that as well.

decapitator
07-16-2008, 02:40 PM
Does on doubleClick arg still work when you are over the checkBox? If so you could check to see if doubleClick has been called and set the checkBox back to what it was. A pain but a work around. Also you might be able to get the states of the mouse so right clicking on it would do something or you could use the keyBoard.shiftPressed and do it with that as well.The double click doesnt work over checkboxes, so I could use that but I've just tried it and its not realy an option because when it swaps the state and then swaps it back it also updates (by triggering the itemCheck event) the objects which can get quite heavy when there are actually more then just my few test objects.

And since even Google tells me I cant do it (besides one topic http://www.dotnetjunkies.com/WebLog/jonne_kats/archive/category/11.aspx , but I dont see that going to work in MXS) I gues im gonna add a rcmenu or something there and just remove the doubleclick stuff I had. Thanks for the help though :)

PEN
07-16-2008, 02:49 PM
Popup menus are a nice work flow for artists anyway as it is more obvious there are options.

decapitator
07-23-2008, 09:56 PM
Ok im back.. This time im trying to invoke a javascript command in a webbrowser control.
rollout webbrowser_rollout "Web Test" width:150 (
button javascript1 "Call Function"
button javascript2 "Call Function With Param"
dotNetControl wb "System.Windows.forms.WebBrowser" width:130 height:130

on webbrowser_rollout open do wb.url = dotNetObject "System.Uri" @"I:\Temp\invoke.html"

-- .<System.Object>InvokeScript <System.String>scriptName
on javascript1 pressed do wb.document.invokeScript "alertMe" --works but the param isnt specified

-- .<System.Object>InvokeScript <System.String>scriptName <System.Object[]>args
on javascript2 pressed do wb.document.invokeScript "alertMe" (dotnetobject "System.string" "moo") --this fails to call the param in the javascript function
)
createdialog webbrowser_rolloutThe error I keep getting is>> MAXScript Rollout Handler Exception: -- Runtime error: No method found which matched argument list <<When I do justx = (dotnetobject "System.string" "moo")
x.toString() It returns "moo" so i dont see whats wrong and why it returns that error becouse it looks fine to me.

I've included the html page im using its just a javascript function that pops up an alert.

RustyKnight
07-23-2008, 10:28 PM
Hi decapitator!

The invokeScript method is expecting a Object array, not a single string as the parameter value...InvokeScript(String, Object[]) (http://msdn.microsoft.com/en-us/library/4b1a88bz.aspx)

You will need to first create an array and then insert the value you want to pass into it and the invoke the method...

Somewhere in this thread is an example of how to create native .net arrays...

Hope this helps
Shane

decapitator
07-24-2008, 12:42 PM
Ah yes thanks got it working! using a small html page now to play video's or is there a better way to do something like that.
I've spend hours looking on google for playing video's using dotnet but couldnt see anything. The only thing what I can think of would be to create a dll to handle MCI (http://msdn.microsoft.com/en-us/library/ms704979%28VS.85%29.aspx) (Media Control Interface) but I cant program in anything like C#/Java/etc :banghead: And this was actually a quite simple scripting sollution (know javascript since I came from web side scripting (and its realy easy))

Maybe I can also fix my flash GUI scripts using this method since the cancelation of activex in x64 or does anyone have any other suggestions using dotnet.

thatoneguy
07-24-2008, 08:07 PM
Sorry this is a crosspost but I put the original question in the wrong forum.

Anybody know how to *quickly* convert a SQLReaderObject into a NxN maxarray?

I'm using a "while read do append" method right now but it's taking 3 or 4 seconds for a 15x2700 item array. Which is aggrevating since the ExecutReader() command and response only takes 15 ms to get the data into the readerobject.

Do I need to write (or find a developer to write) a .NET dll? Would that run faster and maybe return like a stringstream with the array definition? Any ideas on how to get the data out orders of magnitude faster?

biddle
07-25-2008, 06:53 PM
Do you need to have the data in a max array, or can you leave it as a .NET array and access it directly?

I'm not set up to create SQL queries, so the following is just an idea based on my interpretation of the docs...

.biddle


datamatrix = #()
numCols = readerObj.FieldCount
while (readerObj.Read()) do
(
rowdata = dotnetObject "System.Object[]" numcol
if (readerObj.GetValues &rowdata) == numCols then
(
append datamatrix rowdata
)
)

numRows = datamatrix.count
for row = 1 to numRows do
for col = 1 to numCols do
item = (datamatrix[row].get (col-1))

Vsai
07-25-2008, 07:46 PM
this may be more of a dotnet question than maxscript ;) i'm poking together a bit of a sysadmin tool as a learning process here, and came across a few snags.

I'm trying to check whether certain services are running or not, and can do it by the books according to msdn, but I'm not sure how to get the final status out of it in max
Its using the servicecontroller enum, which i'm not sure how to get the actual value out of ;)

http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontrollerstatus(VS.80).aspx

Link wont paste right, just remove the space it adds randomly between the 8 and 0 :(

http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontroller.aspx



fn checkService ServiceName =
(
dotnet.loadassembly "System.ServiceProcess"
sc = dotNetObject "System.ServiceProcess.ServiceController"
scServices = sc.GetServices()
for scTemp in scServices do
(
if (scTemp.ServiceName == ServiceName) do
(
print scTemp.ServiceName
print scTemp.Status
)
)
)

--checking windows update servers for shits and giggles.
checkService "wuauserv"

/*
output:
"wuauserv"
"dotNetObject:System.ServiceProcess.ServiceControllerStatus"
*/

Vsai
07-25-2008, 07:57 PM
Jumped the gun on the post it seems.. you can just do a

print (scTemp.Status.ToString())

instead!

thatoneguy
07-25-2008, 08:43 PM
Do you need to have the data in a max array, or can you leave it as a .NET array and access it directly?

I'm not set up to create SQL queries, so the following is just an idea based on my interpretation of the docs...

.biddle



Thanks mike I'll give that a try but I suspect it'll hit the same performance snag.

The problem is the Maxscript while loop is taking too long. (Less than 1ms per loop but still too long. :D)

I'm hoping there is a .net method of converting it to a dataformat inside of .net that Max can understand since it would skip the Maxscript bottleneck.

ActiveX had the SafeWrapper datastructure which you could convert to an array almost instantaneously. In that case I would do a SQL Query through ODBC to the SafeWrapper and then convert that to an array. The whole operation even for thousands of records would take about 50ms.

Is there a .net nxn array which can be converted similarly into a max nxn array? That would at least give me a .net datastructure target to attempt to achieve.

thatoneguy
07-25-2008, 10:19 PM
dotnetobject "System.object[]" numcol cannot be resolved.

What exactly are you attempting to do there?

It looks like you're trying to pull an entire row at once into an array. Is that possible? I think you can only get one column from the row at a time. (hence the enormous bottle neck building a new row one item at a time, one row at a time.)

PEN
07-25-2008, 10:21 PM
How does system.object work? On another project using a treeView I was able to place data in the form of a struct into the .tag property of treeView nodes. This allowed me to store reference to several things that I needed to know about those nodes. I'm not working with pictureBox and it isn't allowing the struct, says it is not a system.object. I can place strings and floats in and even an array but once I place any of the data that I want to store it give me this error.

Any suggestions?

thatoneguy
07-25-2008, 10:34 PM
Just a sidenote. I wrote a script which generates and executes a CSV file 6 times faster than using the .getvalue or .item array building approach. Ughhhh. There's got to be a faster way to get that data out.

Maybe I'll just have to hand it off to python and back really fast. I was really hoping to keep everything native max.

thatoneguy
07-25-2008, 10:56 PM
Further performance testing:


I tried the exact same code except instead of assigning "readerobject.item[x]" I just used an existing array as the source and it ran 8x faster. So the slowdown is in the readerobject.item[x] part of the code. Everytime you make a .item[x] or .getvalue[x] it slows down a bit.

Could it be Maxscript attempting to translate the .net value being returned into a maxscript value? If it is it would further reinforce my idea that the less .net data exchanges the better.

biddle
07-25-2008, 11:11 PM
Thats odd. I was suggesting you try reading the values into a .NET array

On my system (max9) the following test of a 2 element array:

arry = dotnetobject "system.object[]" 2
arry.set 0 (dotnetobject "System.Int32" 42)
arry.set 1 (dotnetobject "System.String" "Forty Two")
arry.get 0
arry.get 1

generates...

dotNetObject:System.Object[]
undefined
undefined
42
"Forty Two"

thatoneguy
07-25-2008, 11:21 PM
There it goes. that worked. : /

Ok I'll try and fidget it about some more. Thanks.

EDIT: Ha! The error message just meant it was getting passed undefined data. "Numcols" was misspelled.

EDIT2: Ok your script successfully gets the data out of the reader and into .net arrays about 5-6x faster than building max arrays. But... the time it takes to execute all the array.get col loops puts it back to where it started with performance. Is there a fast way to convert a .net array to a max array all at once?

biddle
07-25-2008, 11:54 PM
How does system.object work? ....

I hope you mean how do they work in the context of Maxscript? It would take a book (or a least the first chapter of a book) to detail the .NET class system :)

From a Maxscript point of view, the "System.Object" is the ultimate 'superClassOf()' every other .NET class.

biddle
07-26-2008, 01:27 AM
Is there a fast way to convert a .net array to a max array all at once?

Unfortunately I have simple routines that call 'Array.ConvertAll' to go from a .NET array of one type to a .NET array of another type, (System.Object[] to System.Int32[] for example) but nothing like SafeArrayWrapper that will go to/from maxscript arrays.

biddle
07-26-2008, 03:36 AM
I'm not working with pictureBox and it isn't allowing the struct, says it is not a system.object. I can place strings and floats in and even an array but once I place any of the data that I want to store it give me this error.

Any suggestions?

I imagine that trying to pass a MXS struct as the data to store in the tag fails because the MXS data type is not derived from a System.Object and the code in the mxsdotnet.dlx isn't sophisticated enough to automagically box it up in some sort of proxy.

Did you try storing the data you want to keep in the tag in a .NET container class, like a HashTable?

ht = dotnetObject "System.Collections.HashTable"

http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx

You could also experiment with creating a "System.Object[]" array of the correct size, fill it will the values in your struct and then assign that to the tag.

A peculiarity I found when working with System.Object[] arrays (other than being 0-based) is that you must call the .get and .set methods directly (the standard [] array syntax won't work) which means you have to pass only .NET objects to the setter. MXS isn't able to convert MXS data to a System.Object for you and will complain that it can't find an appropriate method if you pass it an MXS data type (even if it is something that is trivial to convert, like a string or integer)

so instead of:

arry = dotnetObject "System.Object[]" 1
arry[1] = 99
print arry[1]

use:

arry.set 0 (dotNetObject "System.Int32" 99)
print (arry.get 0)