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


Norman3D
06 June 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?

denisT
06 June 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 http://forums.cgsociety.org/showthread.php?f=98&t=987387&highlight=MouseHook

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

lo
06 June 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.

denisT
06 June 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

denisT
06 June 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
)
CreateDropFileHooker()

(
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.

Norman3D
06 June 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?

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

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

CGTalk Moderation
06 June 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.


1