MaxScript与外部程序通讯

最近项目要求通过java给max发送任务指令,max接收指令执行任务,并且返回执行的结果。不管为什么会有这样的需求,有就要去实现。

1、OLE开启

Max本身提供了一个方式,它可以将自己注册成一个Ole自动化对象,默认是没有开启的,开启这个接口只需要操作注册表即可。将该脚本存放的max的安装路径下的ScriptsStartUp,即max启动时会默认加载的脚本。保证max启动以后会执行该脚本。

关于脚本中内容具体请参考Maxscript的自带文档 OLE Automation 章节。

 1 (
 2     /* Dynamically writes the necessary Registry information to allow
 3         Simon Felton's MXSCOM bridge to work.
 4         IF RUNNING THIS SCRIPT ON AN VERSION OF MAX OLDER THAN MAX 10
 5         THE AVG EXTENSION *MUST* BE INSTALLED
 6     */
 7 
 8     local reg_key
 9     local max_version = ((maxVersion())[1] / 1000) as string
10 
11     fn create_reg_key hkey key_name &reg_key key_value_name key_value_type key_value =
12     (
13         registry.createKey hkey key_name key:&reg_key
14         registry.setValue reg_key key_value_name key_value_type key_value
15     )
16 
17     fn write_sub_key_data reg_key sub_key_name sub_key_type sub_key_value =
18     (
19         local sub_key
20         registry.createKey reg_key sub_key_name key:&sub_key
21         registry.setValue sub_key "" sub_key_type sub_key_value
22     )
23 
24 
25     -- Establish a root key for generalized Max data
26     create_reg_key HKEY_CURRENT_USER @"SoftwareClassesMAX.Application" &reg_key "" #REG_SZ "OLE Automation MAX Application"
27 
28     -- Add the Clsid information
29     write_sub_key_data reg_key "Clsid" #REG_SZ "{7FA22CB1-D26F-11d0-B260-00A0240CEEA3}"
30 
31     -- Add the CurVer information
32     write_sub_key_data reg_key "CurVer" #REG_SZ ("MAX.Application." + max_version)
33 
34     -- Establish a new root key for the version of Max being used
35     create_reg_key HKEY_CURRENT_USER (@"SoftwareClassesMAX.Application." + max_version) &reg_key "" #REG_SZ ("OLE Automation MAX " + max_version + ".0 Application")
36 
37     -- Add the Clsid information
38     write_sub_key_data reg_key "Clsid" #REG_SZ "{7FA22CB1-D26F-11d0-B260-00A0240CEEA3}"
39 
40     -- Make a new root key for the CLSID data
41     create_reg_key HKEY_CURRENT_USER @"SoftwareClassesCLSID{7FA22CB1-D26F-11d0-B260-00A0240CEEA3}" &reg_key "" #REG_SZ ("OLE Automation MAX " + max_version + ".0 Application")
42 
43     -- Add sub key data
44     write_sub_key_data reg_key "ProgID" #REG_SZ ("MAX.Application." + max_version)
45     write_sub_key_data reg_key "VersionIndependentProgID" #REG_SZ "MAX.Application"
46 
47     -- Register the running of files and executing script code to OLE.
48     registerOLEInterface #( filein, execute, edit, encryptscript )
49 
50 )
ole开启脚本

2、编写socket通讯dll(C#)

为什么要开启ole,是因为该dll用到了ole。为什么用C#写dll通信,是因为我对C#比较熟悉,还有就是maxscript中虽然可以调用donet的方法,但是语法上写起来很别扭,之前也写过ms一版,有些问题在ms中不好解决,比如在在调用ms中的执行了“importFile (strIn) #noPrompt” 时会发生未知错误。下面会贴上C#和ms两个版本的socket通讯代码(都是demo版本,仅供参考)。这里max都是做服务端,需要循环监听客户端的消息。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Net;
  5 using System.Net.Sockets;
  6 using System.Reflection;
  7 using System.Text;
  8 using System.Threading;
  9 using System.Web.Script.Serialization;
 10 
 11 namespace SocketTest
 12 {
 13     public class SocketServer
 14     {
 15         //承载接收数据
 16         private static byte[] result = new byte[1024];
 17         //端口
 18         private static int myProt = 8889;
 19 
 20         private static Socket serverSocket;
 21         public static void InitSocket()
 22         {
 23             //创建通讯对象
 24             serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 25             //绑定IP地址:端口
 26             serverSocket.Bind(new IPEndPoint(IPAddress.Any, myProt));
 27             //设定最多10个排队连接请求
 28             serverSocket.Listen(5);
 29             //通过Clientsoket发送数据
 30             Thread myThread = new Thread(ListenClientConnect);
 31             myThread.Start();
 32         }
 33         /// <summary>
 34         /// 监听客户端连接
 35         /// </summary>
 36         private static void ListenClientConnect()
 37         {
 38             while (true)
 39             {
 40                 Socket clientSocket = serverSocket.Accept();
 41                 try
 42                 {
 43                     clientSocket.Send(Encoding.UTF8.GetBytes("第一次握手"));
 44                     Thread receiveThread = new Thread(ReceiveMessage);
 45                     receiveThread.Start(clientSocket);
 46                 }
 47                 catch (Exception)
 48                 {
 49 
 50                     clientSocket.Shutdown(SocketShutdown.Both);
 51                     clientSocket.Close();
 52                 }
 53 
 54             }
 55         }
 56 
 57         /// <summary>
 58         /// 接收消息
 59         /// </summary>
 60         /// <param name="clientSocket"></param>
 61         private static void ReceiveMessage(object clientSocket)
 62         {
 63             Socket myClientSocket = (Socket)clientSocket;
 64             while (true)
 65             {
 66                 try
 67                 {
 68                     //通过clientSocket接收数据
 69                     int receiveNumber = myClientSocket.Receive(result);
 70                     //返回给客户端的字典对象
 71                     Dictionary<string, object> dicTemp = new Dictionary<string, object>();
 72                     if (receiveNumber > 0)
 73                     {
 74                         try
 75                         {
 76                             //将客户端消息转换成字符
 77                             string clientResult = Encoding.UTF8.GetString(result, 0, receiveNumber);
 78                             //json字符串转换成字典对象
 79                             Dictionary<string, object> dicResult = GetDicByJson(clientResult);
 80                            
 81                             if (dicResult.Keys.Contains("code"))
 82                             {
 83                                 //判断是否为java轮询监听
 84                                 if (dicResult["code"].ToString().Equals("0100"))
 85                                 {
 86                                     //返回正常运行消息
 87                                     dicTemp.Add("code", "0002");
 88 
 89                                 }
 90                                 //执行任务文件处理的任务命令
 91                                 else if (dicResult["code"].ToString().Equals("0101"))
 92                                 {
 93                                     try
 94                                     {
 95                                         //获取输入输出路径
 96                                         string inFilePath = dicResult["in"].ToString();
 97                                         string outFilePath = dicResult["out"].ToString();
 98                                         //判断文件是否存在
 99                                         //if (File.Exists(inFilePath))
100                                         //{
101                                         //获取max ole对象
102                                         var com_type = Type.GetTypeFromProgID("Max.Application");
103                                         dynamic com_obj = Activator.CreateInstance(com_type);
104                                         //构建执行参数
105                                         object[] parameter = new object[1];
106                                         //Fncreathouse 自定义ms中的方法 测试的时候可以用box()来替代  sname是参数名称 inFilePath是java传过来的参数值
107                                         parameter[0] = "Fncreathouse sName:"" + inFilePath + """;
108                                         //执行方法
109                                         object result = com_type.InvokeMember("execute", BindingFlags.InvokeMethod | BindingFlags.Instance, System.Type.DefaultBinder, com_obj, parameter);
110                                         dicTemp.Add("code", result.ToString());
111                                         //myClientSocket.Send(Encoding.UTF8.GetBytes("成功了" + result.ToString()));
112                                         //string filepath = "D:\2017\3DMAX\MXSPyCOM-master\hello_world.ms";
113                                         //com_obj.FileIn(filepath);
114                                         //}
115                                         //else
116                                         //{
117                                         //    //文件不存在
118                                         //    dicTemp.Add("code", "0004");
119                                         //}
120                                     }
121                                     catch (Exception)
122                                     {
123                                         dicTemp.Add("code", "0005");
124                                     }
125                                 }
126                             }
127                             else
128                             {
129 
130                             }
131                         }
132                         catch (Exception)
133                         {
134 
135                             dicTemp.Add("code", "0005"); 
136                         }
137                         //将结果转换成json字符串,返回给客户端
138                         string returnStr = GetJsonStrByDic(dicTemp);
139                         myClientSocket.Send(Encoding.UTF8.GetBytes(returnStr));
140                     }
141                     else
142                     {
143                         //关闭客户端的连接
144                         myClientSocket.Shutdown(SocketShutdown.Both);
145                         myClientSocket.Close();
146                         break;
147                     }
148 
149 
150                 }
151                 catch (Exception)
152                 {
153                     myClientSocket.Shutdown(SocketShutdown.Both);
154                     myClientSocket.Close();
155                     break;
156                 }
157             }
158         }
159 
160         /// <summary>
161         /// 将字符串转换成字典
162         /// </summary>
163         /// <param name="jsonString"></param>
164         /// <returns></returns>
165         public static Dictionary<string, object> GetDicByJson(string jsonString)
166         {
167             Dictionary<string, object> JsonData = new Dictionary<string, object>();
168             try
169             {
170                 JavaScriptSerializer s = new JavaScriptSerializer();
171                 JsonData = (Dictionary<string, object>)s.DeserializeObject(jsonString);
172             }
173             catch (Exception)
174             {
175             }
176             return JsonData;
177         }
178         /// <summary>
179         /// 字典转换成简单json
180         /// </summary>
181         /// <param name="dic"></param>
182         /// <returns></returns>
183         public static string GetJsonStrByDic(Dictionary<string, object> dic)
184         {
185             string json = string.Empty;
186             try
187             {
188                 if (dic.Keys.Count > 0)
189                 {
190                     json = "{";
191                     foreach (var item in dic.Keys)
192                     {
193                         //如果是最后一个不加逗号
194                         if (item.Equals(dic.Keys.Last()))
195                         {
196                             json = json + """ + item + "":"" + dic[item].ToString() + """;
197                         }
198                         else
199                         {
200                             json = json + """ + item + "":"" + dic[item].ToString() + "",";
201                         }
202                     }
203                     json = json + "}";
204                 }
205             }
206             catch (Exception)
207             {
208 
209             }
210             return json;
211         }
212     }
213 }
C# Socket通讯
  1 /*
  2     后台监听7457端口消息
  3 */
  4 Global Encoding,IPAddress
  5 (
  6     Fn fntest    =(
  7         --print("准创建box")
  8             box()
  9                 --print("创建完box")
 10                 
 11             exportfile  "f:\box.fbx" #noPrompt
 12 
 13             --print("保存文件")
 14             
 15                 )
 16     Fn ExecutionOfTasks = 
 17     (
 18         --theIPAddress = IPAddress.Parse "127.0.0.1"
 19         mainTcpListener = DotNetObject "System.Net.Sockets.TcpListener" IPAddress.Any 7455
 20         --承载数据接收
 21         mainByteStream = DotNetObject "System.Byte[]" 1024
 22         
 23         mainTcpListener.Start()
 24         while true do
 25         (
 26             
 27             try
 28             (
 29                 --获取客户端
 30                 theSocket = mainTcpListener.AcceptSocket()
 31                 --与客户端第一次握手
 32                 theSocket.Send(Encoding.UTF8.GetBytes("I am 3dmax"))
 33                 while true do
 34                 (
 35                     --获取客户端数
 36                     num= theSocket.Receive mainByteStream
 37                     if num>0 then
 38                     (
 39                         --解码客户端数据
 40                         theString = Encoding.UTF8.GetString(mainByteStream)
 41                         
 42                         print("收到客户端的消息:"+theString)
 43                     
 44                         /*
 45                         for i=1 to 10000000 do
 46                         (
 47                             str="fuck"
 48                         )*/
 49                         --给客户端发送数据*
 50                         fntest()
 51                         print("创建box完成")
 52                         theSocket.Send(Encoding.UTF8.GetBytes("我是主线程"))
 53                     )
 54                     else
 55                     (
 56                         theSocket.Close()
 57                         exit
 58                     )
 59                         
 60                 )
 61             
 62             )
 63             catch
 64             (
 65                 theSocket.Close()
 66                         
 67             )
 68         )
 69     
 70             
 71     )
 72 
 73     Fn  ListenerTasks  = 
 74     (
 75         theTcpListener = DotNetObject "System.Net.Sockets.TcpListener" IPAddress.Any 7456
 76         --承载数据接收
 77         secondaryByteStream = DotNetObject "System.Byte[]" 1024
 78         
 79         theTcpListener.Start()
 80         while true do
 81         (
 82             
 83             try
 84             (
 85                 --获取客户端
 86                 theSocket = theTcpListener.AcceptSocket()
 87                 --与客户端第一次握手
 88                 theSocket.Send(Encoding.UTF8.GetBytes("I am 3dmax"))
 89                 while true do
 90                 (
 91                     --获取客户端数
 92                     num= theSocket.Receive secondaryByteStream
 93                     if num>0 then
 94                     (
 95                         --解码客户端数据
 96                         theString = Encoding.UTF8.GetString(secondaryByteStream)
 97                         print("收到客户端的消息:"+theString)
 98                         --给客户端发送数据
 99                         theSocket.Send(Encoding.UTF8.GetBytes("我辅助线程"))
100                     )
101                     else
102                     (
103                         theSocket.Close()
104                         exit
105                     )
106                         
107                 )
108             
109             )
110             catch
111             (
112                 theSocket.Close()
113                         
114             )
115         )
116     
117             
118     )
119     --IP地址
120     IPAddress = DotNetClass "System.Net.IPAddress"
121     --定义编码解码对象
122     Encoding = DotnetClass  "System.Text.Encoding"
123     
124     MainThread  = DotNetObject "System.ComponentModel.BackgroundWorker"
125     DotNet.AddEventHandler MainThread  "DoWork" ExecutionOfTasks
126     MainThread.WorkerSupportsCancellation = true
127     --异步运行
128     MainThread.RunWorkerAsync()
129     
130     SecondaryThread  = DotNetObject "System.ComponentModel.BackgroundWorker"
131     DotNet.AddEventHandler SecondaryThread  "DoWork" ListenerTasks
132     SecondaryThread.WorkerSupportsCancellation = true
133     --异步运行
134     SecondaryThread.RunWorkerAsync()
135     
136     
137     --异步运行
138 
139     /*
140     windows.processPostedMessages()
141     BackgroundWorker.CancelAsync()
142     BackgroundWorker.Dispose()
143     */
144 )
ms Socket通讯

3、使用ms加载dll

下面的脚本要在max启动的时候执行,建议放在max的安装目录下的ScriptsStartUp

 1 Fn GetDotNetAssemblyByFile dllFileName = 
 2 (
 3     local result
 4     DotNetAssembly = dotNetClass "System.Reflection.Assembly"
 5     
 6     tempFolder = SysInfo.TempDir
 7     sourceFileName = GetFilenameFile dllFileName
 8     tempPrefix = (GenClassID returnValue:true)[1] as string
 9     tempFileName = tempFolder + tempPrefix + sourceFileName + GetFilenameType dllFileName
10     CopyFile dllFileName tempFileName
11     result = DotNetAssembly.LoadFile tempFileName
12     result
13 )
14 
15 DotNetActivator = DotNetClass "System.Activator"
16 --根据实际路径填写
17 TestAssembly = GetDotNetAssemblyByFile @"C:Program FilesAutodesk3ds Max 2016scriptsStartupSocketBy3DMAX.dll"
18 TestClassType = TestAssembly.GetType("SocketTest.SocketServer")
19 TestClassObject = DotNetActivator.CreateInstance TestClassType
20 TestClassObject.InitSocket()
ms加载dll
原文地址:https://www.cnblogs.com/he-xiang/p/7993782.html