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 话说一个网络程序员对书法十分感兴趣,退休后决定在这方面有所建树. 于是花重金购买了上等的文房四宝. 一 ...
随机推荐
- 详解使用flask_paginate进行分页
分页技术好处: 1.分页技术是把数据全部查询出来,然后再进行分页 2.分页技术可以,降低带宽使用,提高访问速度 使用flask_paginate进行分页 1.要使用flask_paginate,首先安 ...
- odoo开发笔记 -- wkhtmltox打印不显示中文 --ubuntu字体安装
wkhtmltox 是一个开源的将网页内容转换成PDF的软件包,常嵌套在网页页面里边做打印功能. 以微软雅黑字体为例(其他的宋体.黑体等点阵字体都一样的),我们的雅黑字体文件是:Yahei.ttf(放 ...
- Centos配置vsftpd
#安装vsftpdyum install vsftpd #限制用户只能访问配置的目录,不能访问其他路径#修改vi /etc/vsftpd/vsftpd.conf chroot_list_enable= ...
- 【从0到1学Web前端】javascript中的ajax对象(一) 分类: JavaScript 2015-06-24 10:18 754人阅读 评论(1) 收藏
现在最流行的获取后端的(浏览器从服务器)数据的方式就是通过Ajax了吧.今天就来详细的来学习下这个知识吧.如果使用ajax来访问后段的数据,浏览器和浏览器端的js做了那些工作呢?我做了一个图,请大家看 ...
- webkit技术内幕读书笔记 (一)
本文部分摘录自互联网. Chromeium与Chrome Chromium是Google为发展自家的浏览器Google Chrome而打开的项目,所以Chromium相当于Google Chrome的 ...
- Makefile中.PHONY的作用
单词phony (即phoney)的意思是:伪造的,假的.来自collins的解释是: If you describe something as phoney, you disapprove of i ...
- 面试:vector类的简单实现
vector类的简单实现 #include <vector> #include <iostream> #include <cstring> #include < ...
- windows环境下搭建Java开发环境(一):jdk安装和配置
一.资源下载 官网:http://www.oracle.com/technetwork/java/javase/downloads/index.html 本人安装的是jdk1.8,百度云资源:链接:h ...
- FFmpeg简易播放器的实现-音视频同步
本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10284653.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...
- 基于vue实现一个简单的MVVM框架(源码分析)
不知不觉接触前端的时间已经过去半年了,越来越发觉对知识的学习不应该只停留在会用的层面,这在我学jQuery的一段时间后便有这样的体会. 虽然jQuery只是一个JS的代码库,只要会一些JS的基本操作学 ...