View Full Version : Get filename of file being drag & dropped on the viewport

06-29-2011, 03:21 PM
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?

06-29-2011, 04:02 PM
00C105D4 P WM_DROPFILES hDrop:03BC2768

mouse hook WH_MOUSE has to catch WM_DROPFILES. There is a sample for another hook

06-29-2011, 07:36 PM
it seams like i was wrong. i can't catch WM_DROPFILES message with mouse hook.

06-29-2011, 08:07 PM
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.

06-29-2011, 09:29 PM
I have successfully caught a WM_DROPFILES message using a wrapper around a NativeWindow class.

Good! The NativeWindow was my plan B

06-29-2011, 11:35 PM
i did it with plan B :)

global WindowHooker
fn CreateDropFileHooker forceRecompile:on = if forceRecompile do

source = ""
source += "using System;\n"
source += "using System.Runtime.InteropServices;\n"
source += "using System.Text;\n"
source += "using System.Windows.Forms;\n"
source += "public class DropFileHooker : NativeWindow\n"
source += "{\n"
source += " private const int WM_DROPFILES = 0x0233;\n"
source += " private const int MAX_PATH = 260;\n"
source += " public DropFileHooker() { }\n"
source += " public class MessageEventArgs : EventArgs\n"
source += " {\n"
source += " public MessageEventArgs(Message message, string [] files)\n"
source += " {\n"
source += " Message = message;\n"
source += " Files = files;\n"
source += " Handled = false;\n"
source += " }\n"
source += " public readonly Message Message;\n"
source += " public readonly string[] Files;\n"
source += " public bool Handled = false;\n"
source += " }\n"
source += " public event EventHandler MessageReceived;\n"
source += " protected override void WndProc(ref Message message)\n"
source += " {\n"
source += " switch (message.Msg)\n"
source += " {\n"
source += " case WM_DROPFILES:\n"
source += " IntPtr hDrop = message.WParam;\n"
source += " //string FileName = null;\n"
source += " uint FilesDropped = DragQueryFile(hDrop, -1, null, 0);\n"
source += " string[] Files = new string[FilesDropped];\n"
source += " if (FilesDropped != 0)\n"
source += " {\n"
source += " StringBuilder sFileName = new StringBuilder(MAX_PATH);\n"
source += " for (int i = 0; i < FilesDropped; i++)\n"
source += " {\n"
source += " DragQueryFile(hDrop, i, sFileName, MAX_PATH);\n"
source += " Files[i] = sFileName.ToString().ToLower();\n"
source += " }\n"
source += " }\n"
source += " MessageEventArgs arg = new MessageEventArgs(message, Files);\n"
source += " MessageReceived(this, arg);\n"
source += " if (arg.Handled)\n"
source += " {\n"
source += " DragFinish(hDrop);\n"
source += " }\n"
source += " break;\n"
source += " default:\n"
source += " break;\n"
source += " }\n"
source += " base.WndProc(ref message);\n"
source += " }\n"
source += " [DllImport(\"shell32.dll\")]\n"
source += " static extern uint DragQueryFile(IntPtr hDrop, int iFile, [Out] StringBuilder lpszFile, uint cch);\n"
source += " [DllImport(\"shell32.dll\")]\n"
source += " static extern uint DragFinish(IntPtr hDrop);\n"
source += "}\n"

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

global hooker = WindowHooker.createInstance "DropFileHooker"
fn onMessageReceived s e =
format "here: %\n" 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.

06-29-2011, 11:55 PM
ok wow! Like always this seems too complicated for me. :p

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?

06-30-2011, 10:41 AM
I'm starting to believe that DenisT is the Chuck Norris of Maxscript :bowdown:

06-30-2011, 11:03 AM
well... that saved me a few hours :)

CGTalk Moderation
06-30-2011, 11:03 AM
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.