1. #1
    Member User Gallery
    Join Date
    Apr 2004
    Posts
    57

    Default ZPlugin with C#

    Hi there.

    Did anyone here ever manage to call a function from a C# .net assembly from ZScript using [FileExecute, "AssemblyName.dll", "FunctionName"]?

    If so, which attributes did you use to make the C# method visible?

    Do I have to (or can I) include the name of the class before the function name? Will "ClassName.FunctionName" work?

    Does the assembly have to be marked (registered) for COM interop?

    Tried most of these options, but I'm probably missing something. So far Ive been unable to get even a Hello World message to pop up from my assembly.
    Last edited by Sygnus; 04-18-12 at 07:36 AM.

  2. #2
    Moderator User Gallery
    Join Date
    Jun 2004
    Location
    UK
    Posts
    8,598

    Default

    I'm sorry, I can't help you on this - I use C++ for all my dll stuff (and it makes porting to Mac OSX simpler).

  3. #3
    Member User Gallery
    Join Date
    Apr 2004
    Posts
    57

    Default

    Marcus,

    For all the help I already had from you, you'd have my thanks even if you only used Java or Cobol!

    File execute would make things easier, but I believe I can live without it!

    Still, if anyone else would jump in and supply an answer, I'd be far from sad! And if I find anything out, I'll share here.
    Last edited by Sygnus; 04-18-12 at 10:13 AM.

  4. #4
    Member User Gallery
    Join Date
    Apr 2004
    Posts
    57

    Default

    Ok... maybe I can go on without C# callbacks, but... I'm a little stuborn, and won't give up that easy...

    Kinda found a way (cludge): Build a C++ wrapper to a C# assembly, exposing the methods the way they should be exposed.

    Managed to create the basic project, build it and all, but still the same error: "the specified execute-routine could not be found"

    In my DLL, I have the following code:
    [CODE]__declspec( dllexport ) float GetWheelPosition(void)
    {
    return 1.0f;
    }
    [/CODE]

    and on the zscript:
    [CODE][IButton,
    "ZPlugin:ZAirbrush:CallBack",
    "Increases the draw size of the current brush",
    [ISet, Drawraw Size, [FileExecute, Wrapper.dll, GetWheelPosition]]
    ]
    [/CODE]
    Last edited by Sygnus; 04-18-12 at 06:30 PM.

  5. #5
    Member User Gallery
    Join Date
    Apr 2004
    Posts
    57

    Default

    No way to delete the post... but forget about it all the same: You switch out the debug directives and, just like that, it works again.....

    Magic!

    Now on to find out how to call Static C# methods from C++ functions

  6. #6
    Moderator User Gallery
    Join Date
    Jun 2004
    Location
    UK
    Posts
    8,598

    Default

    Great! Glad you solved that. I was hunting around and found this, which might be useful:

    http://harinadha.wordpress.com/tag/using-c-dll-in-c/

  7. #7
    Member User Gallery
    Join Date
    Apr 2004
    Posts
    57

    Default

    Huge step forward!

    I managed to make the wrapper using the link you gave me, but ZB kept on crashing whenever I called anything from the .net side of the force.

    Had to dig a little (assembly bind error logs and the like) to find out what was going on, but as soon as I made it work, I thought I should post it here, in case there are other .net freaks around.

    The steps are quite easy:

    1) you create your C# dll with whatever logic you need on it (in my case, it would just return a float number)
    2) you create a C++ wrapper dll that references your C# dll and make a function call that will instantiate your c# class and execute your method. (static classes are next up on my experiments)
    3) IMPORTANT: you should prefix your c++ funcion with extern "C" __declspec( dllexport ) for it to be findable by ZB. Maybe this is not so for every compiler out there, but it was the only way for me to get it going from VS2010.
    4) after everything is built and ready comes the tricky part: dll placement! The C++ dll must be on the same folder of the script that calls it, but the .net dll must be on the ZBrush root folder along with ZBrush.exe (yeah, i don't like it either).

    Anyway, it is working now! On to the next stage!

    UPDATE: using static methods work just as well, with way less code!
    Last edited by Sygnus; 04-20-12 at 07:32 PM.

  8. #8
    Moderator User Gallery
    Join Date
    Jun 2004
    Location
    UK
    Posts
    8,598

    Default

    You can specify a full path for the C++ dll in the FileExecute command. The recommended way of doing this is to have a data folder for your plugin and put the dll in there. That way it is easier for the user to uninstall if necessary.

    I always have a 'CheckSystem' routine that is called at the start of the plugin operation. This checks various things and includes setting a dllPath variable. There's a special form you can use for ZBrush paths. Here's the code for Transpose Master:

    [VarSet,dllPath,"ZSTARTUP_ZPLUGS\TPoseMasterData4\T ransposeMasterDLL.dll"]


    Then when using [FileExceute] I just use tha variable:

    [VarSet, dllVersion, [FileExecute, [Var,dllPath], Version]]

  9. #9
    Member User Gallery
    Join Date
    Apr 2004
    Posts
    57

    Default

    I actually get to run the plugin itself from wherever I wish... but it looks for the .net DLL's that are referenced inside it on the root folder of ZB.

    And, since I'm here, let me ask you something:

    I'm trying to get a number value through, passing it as a parameter, but it just does not get there. It either gets zeroed or changed into a huge float number, that is not even close to what I want... Below are the code snippets of my ZScript, C++ function and C# function

    [CODE][MessageOk, [FileExecute, ZAirbrushWrapper.dll, GetBrushID, 25], " "][/CODE]

    [CODE] extern "C" __declspec( dllexport ) float GetBrushID(double brushId) {
    float result = ZAirbrushCallbackStaticCallerGetBrushID(brushId);
    return result;
    }[/CODE]

    [CODE] public static int GetBrushID(double brushId) {
    MessageBox.Show(brushId.ToString());
    return 47;
    }[/CODE]

    And the value I get from this is something like 6,2568..E-316 ... any thoughts on what may be happening?
    BTW, I can get the 47 out... is the 25 that's bugging me!
    Last edited by Sygnus; 04-23-12 at 08:37 PM.

  10. #10
    Moderator User Gallery
    Join Date
    Jun 2004
    Location
    UK
    Posts
    8,598

    Default

    You're not following the correct form for the [FileExecute] command. You can pass in a float but you need another comma between it and the function name (to allow for optional text input):

    [CODE][FileExecute,File name including the extension (such as plugin.dll )
    ,Routine to call,Optional text input,Optional number input
    ,Optional memory block input,Optional memory block output][/CODE]

    Your C++ dll function parameters need to reflect this order. In fact, to simplify things I just use the same template for all my C++ functions although I only ever use the first three parameters:

    [CODE]
    #define DLL_EXPORT __declspec(dllexport)


    extern "C"
    {


    float DLL_EXPORT Version(char* pDontCare, double optValue, char* pOptBuffer1, int optBuffer1Size,
    char* pOptBuffer2, int optBuffer2Size, char** zData);


    float DLL_EXPORT MyFunction(char* pDontCare, double optValue, char* pOptBuffer1, int optBuffer1Size,
    char* pOptBuffer2, int optBuffer2Size, char** zData);


    }
    [/CODE]

    HTH,

  11. #11
    Member User Gallery
    Join Date
    Apr 2004
    Posts
    57

    Default

    Marcus,

    I probably already told you this before, but you are my personal hero!

    Will give this a try later on, when I get back home, but it makes a whole lot of sense!

    When I read
    Optional text input,Optional number input
    , I assumed I could opt between them... working late (when you should be sleeping) makes you assume stupid things...

    Thanks once again.

    Oh, and on a personal note: do you use an Intuos 4 (or 5) tablet? If so, would you be willing to give this little Frankenstein a try?

  12. #12
    Senior Member User Gallery
    Join Date
    May 2007
    Location
    Raleigh NC
    Posts
    476

    Default

    I use an Intuos 3 and would be willing to test out anything you need.

  13. #13
    Member User Gallery
    Join Date
    Apr 2004
    Posts
    57

    Default

    Hi, Nyx.

    I hope I'll have the first version up and runing by the end of the week.

    The first feature I'm working on is stylus recognition: the ability to remember the last brush you used with each stylus tip and change back to that brush once you pick up another pen (or use the eraser, for that matter).

    Once this first feature is ok, I intend to start working on Airbrush Wheel controls for a number of items on ZB, like DrawSize, Z & RGB intensity, FocusShift, etc.

    I'm working with the Intuos4 driver, so I'm not sure how compatible it is going to be (and it's going to be great to find out), but if you're interested, send me a pm and I'll send you a copy as soon as it is off the ground.

  14. #14
    Moderator User Gallery
    Join Date
    Jun 2004
    Location
    UK
    Posts
    8,598

    Default

    Quote Originally Posted by Sygnus View Post
    Oh, and on a personal note: do you use an Intuos 4 (or 5) tablet? If so, would you be willing to give this little Frankenstein a try?
    Sygnus, many thanks for the kind words - I'm glad to help when I can. And sadly I only have an old Intuos that you have to start with a handle (an Intuos 2), otherwise I would have liked to test your plugin.

  15. #15
    Member User Gallery
    Join Date
    Apr 2004
    Posts
    57

    Default It's Alive!!

    It worked!!

    Still got a small bug on the method that switches brushes as you switch your pens, but it is certainly due to working way past my sleeping hour (again).

    Anyway, the wheel remote control is working perfectly. And as a bonus, you can use the button on the airbrush to switch between Draw Size, ZIntensity and RGB Intensity (tried to include Focal Shift, but it was not very useful).

    But there's always another question, yes? I was creating the buttons and assigning hotkeys directly from the script, as a parameter... and I found that sometimes the hotkey stops working after the first use. Also tried assigning the hotkey with ISetHotkey, but with the same result. The only way I found to bind the hotkeys for good was to alter the startup hotkeys txt. Am I doing something wrong?

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •