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

1、OLE开启

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

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

 (
/* Dynamically writes the necessary Registry information to allow
Simon Felton's MXSCOM bridge to work.
IF RUNNING THIS SCRIPT ON AN VERSION OF MAX OLDER THAN MAX 10
THE AVG EXTENSION *MUST* BE INSTALLED
*/ local reg_key
local max_version = ((maxVersion())[1] / 1000) as string fn create_reg_key hkey key_name &reg_key key_value_name key_value_type key_value =
(
registry.createKey hkey key_name key:&reg_key
registry.setValue reg_key key_value_name key_value_type key_value
) fn write_sub_key_data reg_key sub_key_name sub_key_type sub_key_value =
(
local sub_key
registry.createKey reg_key sub_key_name key:&sub_key
registry.setValue sub_key "" sub_key_type sub_key_value
) -- Establish a root key for generalized Max data
create_reg_key HKEY_CURRENT_USER @"Software\Classes\MAX.Application" &reg_key "" #REG_SZ "OLE Automation MAX Application" -- Add the Clsid information
write_sub_key_data reg_key "Clsid" #REG_SZ "{7FA22CB1-D26F-11d0-B260-00A0240CEEA3}" -- Add the CurVer information
write_sub_key_data reg_key "CurVer" #REG_SZ ("MAX.Application." + max_version) -- Establish a new root key for the version of Max being used
create_reg_key HKEY_CURRENT_USER (@"Software\Classes\MAX.Application." + max_version) &reg_key "" #REG_SZ ("OLE Automation MAX " + max_version + ".0 Application") -- Add the Clsid information
write_sub_key_data reg_key "Clsid" #REG_SZ "{7FA22CB1-D26F-11d0-B260-00A0240CEEA3}" -- Make a new root key for the CLSID data
create_reg_key HKEY_CURRENT_USER @"Software\Classes\CLSID\{7FA22CB1-D26F-11d0-B260-00A0240CEEA3}" &reg_key "" #REG_SZ ("OLE Automation MAX " + max_version + ".0 Application") -- Add sub key data
write_sub_key_data reg_key "ProgID" #REG_SZ ("MAX.Application." + max_version)
write_sub_key_data reg_key "VersionIndependentProgID" #REG_SZ "MAX.Application" -- Register the running of files and executing script code to OLE.
registerOLEInterface #( filein, execute, edit, encryptscript ) )

ole开启脚本

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

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

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Web.Script.Serialization; namespace SocketTest
{
public class SocketServer
{
//承载接收数据
private static byte[] result = new byte[];
//端口
private static int myProt = ; private static Socket serverSocket;
public static void InitSocket()
{
//创建通讯对象
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定IP地址:端口
serverSocket.Bind(new IPEndPoint(IPAddress.Any, myProt));
//设定最多10个排队连接请求
serverSocket.Listen();
//通过Clientsoket发送数据
Thread myThread = new Thread(ListenClientConnect);
myThread.Start();
}
/// <summary>
/// 监听客户端连接
/// </summary>
private static void ListenClientConnect()
{
while (true)
{
Socket clientSocket = serverSocket.Accept();
try
{
clientSocket.Send(Encoding.UTF8.GetBytes("第一次握手"));
Thread receiveThread = new Thread(ReceiveMessage);
receiveThread.Start(clientSocket);
}
catch (Exception)
{ clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
} }
} /// <summary>
/// 接收消息
/// </summary>
/// <param name="clientSocket"></param>
private static void ReceiveMessage(object clientSocket)
{
Socket myClientSocket = (Socket)clientSocket;
while (true)
{
try
{
//通过clientSocket接收数据
int receiveNumber = myClientSocket.Receive(result);
//返回给客户端的字典对象
Dictionary<string, object> dicTemp = new Dictionary<string, object>();
if (receiveNumber > )
{
try
{
//将客户端消息转换成字符
string clientResult = Encoding.UTF8.GetString(result, , receiveNumber);
//json字符串转换成字典对象
Dictionary<string, object> dicResult = GetDicByJson(clientResult); if (dicResult.Keys.Contains("code"))
{
//判断是否为java轮询监听
if (dicResult["code"].ToString().Equals(""))
{
//返回正常运行消息
dicTemp.Add("code", ""); }
//执行任务文件处理的任务命令
else if (dicResult["code"].ToString().Equals(""))
{
try
{
//获取输入输出路径
string inFilePath = dicResult["in"].ToString();
string outFilePath = dicResult["out"].ToString();
//判断文件是否存在
//if (File.Exists(inFilePath))
//{
//获取max ole对象
var com_type = Type.GetTypeFromProgID("Max.Application");
dynamic com_obj = Activator.CreateInstance(com_type);
//构建执行参数
object[] parameter = new object[];
//Fncreathouse 自定义ms中的方法 测试的时候可以用box()来替代 sname是参数名称 inFilePath是java传过来的参数值
parameter[] = "Fncreathouse sName:\"" + inFilePath + "\"";
//执行方法
object result = com_type.InvokeMember("execute", BindingFlags.InvokeMethod | BindingFlags.Instance, System.Type.DefaultBinder, com_obj, parameter);
dicTemp.Add("code", result.ToString());
//myClientSocket.Send(Encoding.UTF8.GetBytes("成功了" + result.ToString()));
//string filepath = "D:\\2017\\3DMAX\\MXSPyCOM-master\\hello_world.ms";
//com_obj.FileIn(filepath);
//}
//else
//{
// //文件不存在
// dicTemp.Add("code", "0004");
//}
}
catch (Exception)
{
dicTemp.Add("code", "");
}
}
}
else
{ }
}
catch (Exception)
{ dicTemp.Add("code", "");
}
//将结果转换成json字符串,返回给客户端
string returnStr = GetJsonStrByDic(dicTemp);
myClientSocket.Send(Encoding.UTF8.GetBytes(returnStr));
}
else
{
//关闭客户端的连接
myClientSocket.Shutdown(SocketShutdown.Both);
myClientSocket.Close();
break;
} }
catch (Exception)
{
myClientSocket.Shutdown(SocketShutdown.Both);
myClientSocket.Close();
break;
}
}
} /// <summary>
/// 将字符串转换成字典
/// </summary>
/// <param name="jsonString"></param>
/// <returns></returns>
public static Dictionary<string, object> GetDicByJson(string jsonString)
{
Dictionary<string, object> JsonData = new Dictionary<string, object>();
try
{
JavaScriptSerializer s = new JavaScriptSerializer();
JsonData = (Dictionary<string, object>)s.DeserializeObject(jsonString);
}
catch (Exception)
{
}
return JsonData;
}
/// <summary>
/// 字典转换成简单json
/// </summary>
/// <param name="dic"></param>
/// <returns></returns>
public static string GetJsonStrByDic(Dictionary<string, object> dic)
{
string json = string.Empty;
try
{
if (dic.Keys.Count > )
{
json = "{";
foreach (var item in dic.Keys)
{
//如果是最后一个不加逗号
if (item.Equals(dic.Keys.Last()))
{
json = json + "\"" + item + "\":\"" + dic[item].ToString() + "\"";
}
else
{
json = json + "\"" + item + "\":\"" + dic[item].ToString() + "\",";
}
}
json = json + "}";
}
}
catch (Exception)
{ }
return json;
}
}
}

C# Socket通讯

 /*
后台监听7457端口消息
*/
Global Encoding,IPAddress
(
Fn fntest =(
--print("准创建box")
box()
--print("创建完box") exportfile "f:\\box.fbx" #noPrompt --print("保存文件") )
Fn ExecutionOfTasks =
(
--theIPAddress = IPAddress.Parse "127.0.0.1"
mainTcpListener = DotNetObject "System.Net.Sockets.TcpListener" IPAddress.Any 7455
--承载数据接收
mainByteStream = DotNetObject "System.Byte[]" 1024 mainTcpListener.Start()
while true do
( try
(
--获取客户端
theSocket = mainTcpListener.AcceptSocket()
--与客户端第一次握手
theSocket.Send(Encoding.UTF8.GetBytes("I am 3dmax"))
while true do
(
--获取客户端数
num= theSocket.Receive mainByteStream
if num>0 then
(
--解码客户端数据
theString = Encoding.UTF8.GetString(mainByteStream) print("收到客户端的消息:"+theString) /*
for i=1 to 10000000 do
(
str="fuck"
)*/
--给客户端发送数据*
fntest()
print("创建box完成")
theSocket.Send(Encoding.UTF8.GetBytes("我是主线程"))
)
else
(
theSocket.Close()
exit
) ) )
catch
(
theSocket.Close() )
) ) Fn ListenerTasks =
(
theTcpListener = DotNetObject "System.Net.Sockets.TcpListener" IPAddress.Any 7456
--承载数据接收
secondaryByteStream = DotNetObject "System.Byte[]" 1024 theTcpListener.Start()
while true do
( try
(
--获取客户端
theSocket = theTcpListener.AcceptSocket()
--与客户端第一次握手
theSocket.Send(Encoding.UTF8.GetBytes("I am 3dmax"))
while true do
(
--获取客户端数
num= theSocket.Receive secondaryByteStream
if num>0 then
(
--解码客户端数据
theString = Encoding.UTF8.GetString(secondaryByteStream)
print("收到客户端的消息:"+theString)
--给客户端发送数据
theSocket.Send(Encoding.UTF8.GetBytes("我辅助线程"))
)
else
(
theSocket.Close()
exit
) ) )
catch
(
theSocket.Close() )
) )
--IP地址
IPAddress = DotNetClass "System.Net.IPAddress"
--定义编码解码对象
Encoding = DotnetClass "System.Text.Encoding" MainThread = DotNetObject "System.ComponentModel.BackgroundWorker"
DotNet.AddEventHandler MainThread "DoWork" ExecutionOfTasks
MainThread.WorkerSupportsCancellation = true
--异步运行
MainThread.RunWorkerAsync() SecondaryThread = DotNetObject "System.ComponentModel.BackgroundWorker"
DotNet.AddEventHandler SecondaryThread "DoWork" ListenerTasks
SecondaryThread.WorkerSupportsCancellation = true
--异步运行
SecondaryThread.RunWorkerAsync() --异步运行 /*
windows.processPostedMessages()
BackgroundWorker.CancelAsync()
BackgroundWorker.Dispose()
*/
)

ms Socket通讯

3、使用ms加载dll

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

 Fn GetDotNetAssemblyByFile dllFileName =
(
local result
DotNetAssembly = dotNetClass "System.Reflection.Assembly" tempFolder = SysInfo.TempDir
sourceFileName = GetFilenameFile dllFileName
tempPrefix = (GenClassID returnValue:true)[1] as string
tempFileName = tempFolder + tempPrefix + sourceFileName + GetFilenameType dllFileName
CopyFile dllFileName tempFileName
result = DotNetAssembly.LoadFile tempFileName
result
) DotNetActivator = DotNetClass "System.Activator"
--根据实际路径填写
TestAssembly = GetDotNetAssemblyByFile @"C:\Program Files\Autodesk\3ds Max 2016\scripts\Startup\SocketBy3DMAX.dll"
TestClassType = TestAssembly.GetType("SocketTest.SocketServer")
TestClassObject = DotNetActivator.CreateInstance TestClassType
TestClassObject.InitSocket()

ms加载dll

MaxScript与外部程序通讯的更多相关文章

  1. HTTP协议和web工作原理

    本章学完之后能干什么? 要把 知识点学好,那就需要把它相关的周边知识点了解全面 HTTP协议是web学习的核心!!! 学东东切忌只学配置,不学原理:只学会框架有什么用,要会自己写框架!! web学习直 ...

  2. Matlab中TCP通讯-实现外部程序提供优化目标函数解

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Matlab中TCP通讯-实现外部程序提供优化目标函数解     本文地址:http://te ...

  3. 【工业串口和网络软件通讯平台(SuperIO)教程】二.架构和组成部分

    1.1    架构结构图 1.1.1    层次示意图 1.1.2    模型对象示意图 1.2    IO管理器 IO管理器是对串口和网络通讯链路的管理.调度.针对串口和网络通讯链路的特点,在IO管 ...

  4. 工业串口和网络软件通讯平台(SuperIO 2.1)更新发布

    SuperIO 2.1下载 一.SuperIO 的特点: 1)    能够很快的构建自己的通讯平台软件,包括主程序. 2)   设备模块化开发,通过配制文件挂载,即可在平台软件下运行. 3)   设备 ...

  5. C#与西门子PLC通讯

    1.0  通讯组件概述 通讯组件用于PC与可编程控制器(PLC).智能仪表等进行数据通讯,适用于基于PC高级语言的工业自动化控制系统.组件采用动态链接库文件(*.DLL)的形式,在PC系统的项目工程里 ...

  6. 利用消息机制实现VC与Delphi之间的通讯(发送自定义消息)

    摘要: 本文介绍了使用Windows消息机制实现由不同语言编制的程序之间的相互通讯.联系,并以当前较为流行的两种语言Microsoft Visual C++ 6.0和Borland delphi 5. ...

  7. HTML5笔记:跨域通讯、多线程、本地存储和多图片上传技术

    最近做项目在前端我使用了很多新技术,这些技术有bootstrap.angularjs,不过最让我兴奋的还是使用了HTML5的技术,今天我想总结一些HTML5的技术,好记性不如烂笔头,写写文章可以很好的 ...

  8. (转)利用libcurl和国内著名的两个物联网云端通讯的例程, ubuntu和openwrt下调试成功(四)

    1. libcurl 的参考文档如下 CURLOPT_HEADERFUNCTION Pass a pointer to a function that matches the following pr ...

  9. (转)linux下和云端通讯的例程, ubuntu和openwrt下实验成功(二)

    前言: 上节用纯linux的函数实现了和云端通讯, 本节开始利用传说中的神器libcurl 话说一个网络程序员对书法十分感兴趣,退休后决定在这方面有所建树. 于是花重金购买了上等的文房四宝.    一 ...

随机推荐

  1. oracle undo redo 解析

    Undo是干嘛用的?          简单理解,就相当于Windows下的回收站.        你对数据执行修改时,数据库会生成undo信息,这样万一你执行的事务或语句由于某种原因失败了,或者如果 ...

  2. xamarin 遇到的奇葩问题

    未能找到路径“E:\platforms”的一部分. xamarin 安卓存档出现这样的错误 建议检查下ndk是否配置完整

  3. python中@staticmethod与@classmethod

    @ 首先这里介绍一下‘@’的作用,‘@’用作函数的修饰符,是python2.4新增的功能,修饰符必须出现在函数定义前一行,不允许和函数定义在同一行.只可以对模块或者类定义的函数进行修饰,不允许修饰一个 ...

  4. 关于Spring Security中无Session和无状态stateless

    Spring Security是J2EE领域使用最广泛的权限框架,支持HTTP BASIC, DIGEST, X509, LDAP, FORM-AUTHENTICATION, OPENID, CAS, ...

  5. php -- 文件读写

    ----- 024-file.php ----- <!DOCTYPE html> <html> <head> <meta http-equiv="c ...

  6. chromium浏览器开发系列第三篇:chromium源码目录结构

    上两篇介绍了下载源码和编译源码,这次主要介绍chromium的源码目录结构,我也是通过源码和官网结合来跟大家说,如果有说的不准确的,欢迎交流. 另外,官网的不一定准确,他们其实也很懒,所以最主要还是靠 ...

  7. 如果非得了解下git系统... - 实践篇

    git的定义是一个内容寻址文件系统.内容.寻址.文件.系统,该来的总会来的… 本文旨在通过实践来介绍.git文件夹中的目录及文件功能,属git基础知识.但在此基础上可解决各git使用过程中可能遇到的问 ...

  8. @Async的使用

    从Spring3.x 开始,加入@Async这个注解,用户异步线程处理,使用起来很方便. 使用配置如下:spring-task.xml <task:executor id="execu ...

  9. “网红架构师”解决你的Ceph 运维难题

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由Tstack发表于云+社区专栏 本文为长篇连续剧,将分多个篇幅发表,主要介绍了从动手部署环境到后期运营故障处理过程中常见的问题,内容由 ...

  10. <Think Python>中统计文献单词的处理代码

    def process_line(line, hist):    """Adds the words in the line to the histogram. Modi ...