MaxScript与外部程序通讯
最近项目要求通过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 ®_key key_value_name key_value_type key_value =
(
registry.createKey hkey key_name key:®_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" ®_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) ®_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}" ®_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与外部程序通讯的更多相关文章
- HTTP协议和web工作原理
本章学完之后能干什么? 要把 知识点学好,那就需要把它相关的周边知识点了解全面 HTTP协议是web学习的核心!!! 学东东切忌只学配置,不学原理:只学会框架有什么用,要会自己写框架!! web学习直 ...
- Matlab中TCP通讯-实现外部程序提供优化目标函数解
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Matlab中TCP通讯-实现外部程序提供优化目标函数解 本文地址:http://te ...
- 【工业串口和网络软件通讯平台(SuperIO)教程】二.架构和组成部分
1.1 架构结构图 1.1.1 层次示意图 1.1.2 模型对象示意图 1.2 IO管理器 IO管理器是对串口和网络通讯链路的管理.调度.针对串口和网络通讯链路的特点,在IO管 ...
- 工业串口和网络软件通讯平台(SuperIO 2.1)更新发布
SuperIO 2.1下载 一.SuperIO 的特点: 1) 能够很快的构建自己的通讯平台软件,包括主程序. 2) 设备模块化开发,通过配制文件挂载,即可在平台软件下运行. 3) 设备 ...
- C#与西门子PLC通讯
1.0 通讯组件概述 通讯组件用于PC与可编程控制器(PLC).智能仪表等进行数据通讯,适用于基于PC高级语言的工业自动化控制系统.组件采用动态链接库文件(*.DLL)的形式,在PC系统的项目工程里 ...
- 利用消息机制实现VC与Delphi之间的通讯(发送自定义消息)
摘要: 本文介绍了使用Windows消息机制实现由不同语言编制的程序之间的相互通讯.联系,并以当前较为流行的两种语言Microsoft Visual C++ 6.0和Borland delphi 5. ...
- HTML5笔记:跨域通讯、多线程、本地存储和多图片上传技术
最近做项目在前端我使用了很多新技术,这些技术有bootstrap.angularjs,不过最让我兴奋的还是使用了HTML5的技术,今天我想总结一些HTML5的技术,好记性不如烂笔头,写写文章可以很好的 ...
- (转)利用libcurl和国内著名的两个物联网云端通讯的例程, ubuntu和openwrt下调试成功(四)
1. libcurl 的参考文档如下 CURLOPT_HEADERFUNCTION Pass a pointer to a function that matches the following pr ...
- (转)linux下和云端通讯的例程, ubuntu和openwrt下实验成功(二)
前言: 上节用纯linux的函数实现了和云端通讯, 本节开始利用传说中的神器libcurl 话说一个网络程序员对书法十分感兴趣,退休后决定在这方面有所建树. 于是花重金购买了上等的文房四宝. 一 ...
随机推荐
- 【xsy2913】 enos 动态dp
题目大意:给你一棵 $n$个点 以 $1$为根 的树,每个点有$ 0,1,2 $三种颜色之一,初始时整棵树的颜色均为 $0$. $m$ 次操作, 每次操作形如: 1 x y c : 将 $x$到$y$ ...
- POJ 2498
#include<iostream> using namespace std; #include<string> #include<stdio.h> int mai ...
- Python:线程指南
1. 线程基础 1.1. 线程状态 线程有5种状态,状态转换的过程如下图所示: 1.2. 线程同步(锁) 多线程的优势在于可以同时运行多个任务(至少感觉起来是这样).但是当线程需要共享数据时,可能存在 ...
- Python:Windows8下安装BeautifulSoup
运行环境:Windows 8.1 Python:2.7.6 在安装的时候,我使用的pip来进行安装,命令如下: pip install beautifulsoup4 运行的时候,报错如下: Excep ...
- C# 自定义类型通过实现IFormattable接口,来输出指定的格式和语言文化的字符串(例:DateTime)
常规的调用ToString()方法,存在两个问题. (1).调用者无法控制字符串的格式 (2).调用者不能方便的选择一种特定的语言文化来格式化字符串. 在开发一些国际化的应用时,应用程序需要调用与当前 ...
- vector源码2(参考STL源码--侯捷):空间分配、push_back
vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...
- OpenShift Redhat 搭建NodeJS环境
https://openshift.redhat.com/ OpenShift 是 redhat 公司推出的一个 PaaS 云计算应用平台,开发者可在上面构建.测试.部署和运行应用程序,它支持 Jav ...
- mpvue使用scroll-view实现图片横向滑动
html代码 <div class="swiper-home"> <scroll-view scroll-x="true" style=&qu ...
- 浅尝Vue.js组件(二)
本篇目录: 插槽(Slot) 插槽内容 作用域 具名插槽 作用域插槽 独占默认插槽的缩写语法 解构插槽Prop 使用场景举例 动态插槽名 具名插槽缩写 动态组件&keep-alive 异步组件 ...
- 28-hadoop-hbase入门小程序
hbase的完全分布式建立起来了, 可以试下好使不 1, 导包, {HBASE_HOME}/lib 下所有的jar包, 导入 2, 使用junit测试, 会报错, 因为缺少一个jar 3, 获取链接, ...