Get filename of file being drag & dropped on the viewport


#1

Hey guys!
I’m trying to improve MaxScriptManager, and one way of doing this, would be to be able to “know” what MZP is being drag & dropped on the 3dsMax viewport. The reason why, is because I need to do several checks on the file before I run it.
I’m able to do this through the “Run Script…” dialog, because I replaced it with a custom dotnet one, hehe. So I do checks such as MD5 hash check, to see if it’s in the repository already, or if it’s a MaxScriptManager compatible script, in order to show a install wizard or not. And after all that, I run it.

The problem is when the user drags & drops a MZP file instead of using the “Run Script…” dialog. Currently I’m monitoring the TEMP folder for changes, since that’s where the MZP is unpacked temporarily. So once a new “mzptmp” folder is found I know a MZP file has been drag & dropped. By looking at the files inside that folder I can determine whether it’s MaxScriptManager compatible or not. Unfortunately the MZP is being run regardless.
So anyway… long story short, ideally I would like to be able to “intercept” the file being dropped inside the 3dsMax window, get it’s location and in case of it being a MZP stop it from being dropped entirely, then do my checks and run it.
I think the stopping of the MZP will be impossible, but perhaps getting the file location isn’t.

I’ve used Spy++ and I’ve been able to find the dropfile message, here is an example:

00C105D4 P WM_DROPFILES hDrop:03BC2768

But I don’t know how to go on from here… Would there be a way to get more information out of it?


#2

mouse hook WH_MOUSE has to catch WM_DROPFILES. There is a sample for another hook http://forums.cgsociety.org/showthread.php?f=98&t=987387&highlight=MouseHook


#3

it seams like i was wrong. i can’t catch WM_DROPFILES message with mouse hook.


#4

I have successfully caught a WM_DROPFILES message using a wrapper around a NativeWindow class.

I have not yet attempted to catch the message details such as filename.

Will post what I have tomorrow.


#5

Good! The NativeWindow was my plan B


#6

i did it with plan B :slight_smile:


 global WindowHooker
 fn CreateDropFileHooker forceRecompile:on = if forceRecompile do
 (
 
 source = ""
 source += "using System;
"
 source += "using System.Runtime.InteropServices;
"
 source += "using System.Text;
"
 source += "using System.Windows.Forms;
"
 source += "public class DropFileHooker : NativeWindow
"
 source += "{
"
 source += "	private const int WM_DROPFILES = 0x0233;
"
 source += "	private const int MAX_PATH = 260;
"
 source += "	public DropFileHooker() { }
"
 source += "	public class MessageEventArgs : EventArgs
"
 source += "	{
"
 source += "		public MessageEventArgs(Message message, string [] files)
"
 source += "		{
"
 source += "			Message = message;
"
 source += "			Files = files;
"
 source += "			Handled = false;
"
 source += "		}
"
 source += "		public readonly Message Message;
"
 source += "		public readonly string[] Files;
"
 source += "		public bool Handled = false;
"
 source += "	}
"
 source += "	public event EventHandler MessageReceived;
"
 source += "	protected override void WndProc(ref Message message)
"
 source += "	{
"
 source += "		switch (message.Msg)
"
 source += "		{
"
 source += "			case WM_DROPFILES:
"
 source += "				IntPtr hDrop = message.WParam;
"
 source += "				//string FileName = null;
"
 source += "				uint FilesDropped = DragQueryFile(hDrop, -1, null, 0);
"
 source += "				string[] Files = new string[FilesDropped];
"
 source += "				if (FilesDropped != 0)
"
 source += "				{
"
 source += "					StringBuilder sFileName = new StringBuilder(MAX_PATH);
"
 source += "					for (int i = 0; i < FilesDropped; i++)
"
 source += "					{
"
 source += "						DragQueryFile(hDrop, i, sFileName, MAX_PATH);
"
 source += "						Files[i] = sFileName.ToString().ToLower();
"
 source += "					}
"
 source += "				}
"
 source += "				MessageEventArgs arg = new MessageEventArgs(message, Files);
"
 source += "				MessageReceived(this, arg);
"
 source += "				if (arg.Handled)
"
 source += "				{
"
 source += "					DragFinish(hDrop);
"
 source += "				}
"
 source += "				break;
"
 source += "			default:
"
 source += "				break;
"
 source += "		}
"
 source += "		base.WndProc(ref message);
"
 source += "	}
"
 source += "	[DllImport(\"shell32.dll\")]
"
 source += "	static extern uint DragQueryFile(IntPtr hDrop, int iFile, [Out] StringBuilder lpszFile, uint cch);
"
 source += "	[DllImport(\"shell32.dll\")]
"
 source += "	static extern uint DragFinish(IntPtr hDrop);
"
 source += "}
"
 
 	csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
 	compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
 
 	compilerParams.ReferencedAssemblies.AddRange #("System.dll", "System.Windows.Forms.dll")
 
 	compilerParams.GenerateInMemory = true
 	compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
 		
 	WindowHooker = compilerResults.CompiledAssembly
 )
 CreateDropFileHooker()
 
 (
 	global hooker = WindowHooker.createInstance "DropFileHooker"
 	fn onMessageReceived s e =
 	(
 		format "here: %
" e.files 
 		if e.files.count > 1 do e.Handled = on
 	)
 	dotnet.removeAllEventHandlers hooker
 	dotnet.addEventHandler hooker "MessageReceived" onMessageReceived
 	
 --	hooker.ReleaseHandle() -- DON'T FORGET TO RELEASE
 	hooker.AssignHandle (dotnetobject "IntPtr" (windows.getMAXHWND()))
 )
 

of course it might be (and should be) optimized.


Does MXS support "catching a file" dropped into max?
#7

ok wow! Like always this seems too complicated for me. :stuck_out_tongue:

So what are hooks? and what is the NativeWindow class?
Do you “inject” something to the 3dsMax process in order to intercept the dropped files, is that it?


#8

I’m starting to believe that DenisT is the Chuck Norris of Maxscript :bowdown:


#9

well… that saved me a few hours :slight_smile:


#10

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.