Skip to content

Commit

Permalink
add c++ c# python and mxs
Browse files Browse the repository at this point in the history
  • Loading branch information
hako committed Nov 29, 2019
1 parent a06ec9b commit 9c3f095
Show file tree
Hide file tree
Showing 26 changed files with 2,464 additions and 0 deletions.
1,010 changes: 1,010 additions & 0 deletions .gitignore

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
### Autodesk 3ds Max Custom Callback Notification Examples

This repository demonstrates how to hook onto and call custom callback notifications in Autodesk 3ds Max 2019. This repository comes with [this accompanying blogpost](https://wesleyhill.co.uk/p/custom-callback-notifcations-in-3ds-max/).

### Requirements

+ [**Autodesk 3ds Max 2019**](https://www.autodesk.co.uk/products/3ds-max/free-trial) and higher.
+ Autodesk 3ds Max 2019 (and higher) **SDK** (Comes with the installer)
+ [**Microsoft Visual Studio 2017/2019 IDE**](<https://visualstudio.microsoft.com/vs/community/>)
+ [**Windows 10**](https://www.microsoft.com/en-gb/software-download/windows10)


### Usage

Each folder contains a language implementation of the example with a README on how to run the examples.

![](demo.png)

[`c++`](https://github.com/hako/3dsMax-CustomNotifications/tree/master/c%2B%2B) (top left)

[`csharp`](https://github.com/hako/3dsMax-CustomNotifications/tree/master/csharp) (top right)

[`maxscript`](https://github.com/hako/3dsMax-CustomNotifications/tree/master/maxscript) (bottom left)

[`python`](https://github.com/hako/3dsMax-CustomNotifications/tree/master/python) (bottom right)

This has been tested to be working on **Windows 10**.

### LICENSE

Apache License 2.0

See [LICENSE](https://github.com/hako/3dsMax-CustomNotifications/tree/master/LICENSE) for the full license text.
32 changes: 32 additions & 0 deletions c++/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
### C++

### Building the C++ example

1. Launch `Example.sln` in Visual Studio
2. Go to "Project > Example Properties > Reference Paths"
3. Add the following paths:
+ `<your 3ds Max install path>\3ds Max 2019\`
+ `<your 3ds Max install path>\3ds Max 2019\bin\assemblies\`
4. Click on to "Build > Build Solution"

### Running the C++ example

There are two ways in installing & running the C++ example:

1. Go to "x64\bin\Debug\" or "x64\bin\Release\"
2. Copy `CustomNotificationsDemo.dlu` to `<your 3ds Max install path>\3ds Max 2019\stdplugs\`
3. Launch 3ds Max 2019

**or**

1. Launch 3ds Max 2019
2. Go to "Customize > Plug-in Manager (Right Click) > Load New Plug-in..."
3. Go to "x64\bin\Debug\" or "x64\bin\Release\" and select `CustomNotificationsDemo.dlu`

Finally, go to "Utilities > More... > Custom Notifications Demo" to run the demo.

### LICENSE

Apache License 2.0

See [LICENSE](https://github.com/hako/3dsMax-CustomNotifications/tree/master/LICENSE) for the full license text.
53 changes: 53 additions & 0 deletions c++/example/DllEntry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// Demonstration on how to call custom 3ds Max notifications in C++.
// Works with 3ds Max 2019 and above.
// (c) 2019 Wesley Hill
//

#include "Example.h"

extern ClassDesc2* GetUtilitySampleDesc();

HINSTANCE hInstance;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, ULONG fdwReason, LPVOID)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
hInstance = hinstDLL;
DisableThreadLibraryCalls(hInstance);
}
return(TRUE);
}

__declspec(dllexport) int LibNumberClasses()
{
return 1;
}

__declspec(dllexport) ULONG LibVersion()
{
return VERSION_3DSMAX;
}

__declspec(dllexport) const TCHAR* LibDescription()
{
return L"Demonstration on how to call custom 3ds Max notifications in C++ (Autodesk 3DS Max 2019 and up).";
}

__declspec(dllexport) ClassDesc* LibClassDesc(int i)
{
switch (i) {
case 0: return GetUtilitySampleDesc();
default: return 0;
}
}

TCHAR *GetString(int id)
{
static TCHAR buf[256];

if (hInstance)
return LoadString(hInstance, id, buf, _countof(buf)) ? buf : nullptr;
return nullptr;
}
145 changes: 145 additions & 0 deletions c++/example/Example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//
// Demonstration on how to call custom 3ds Max notifications in C++.
// Works with 3ds Max 2019 and above.
// (c) 2019 Wesley Hill
//

#include "Example.h"
#include <notify.h>
#include <string>

ClassDesc2* GetUtilitySampleDesc() {
static ExampleClassDesc exampleDesc;
return &exampleDesc;
}

void ShowMessage(const wchar_t* msg) {
HWND sbHandle = GetDlgItem(GetActiveWindow(), IDC_STATUS_BAR);
SetWindowTextW(sbHandle, msg);
}

int GetNotificationCode() {
HWND cHandle = GetDlgItem(GetActiveWindow(), IDC_COMBOBOX);

wchar_t textCode[256];
LRESULT idx = SendMessageW(cHandle, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
SendMessageW(cHandle, (UINT)CB_GETLBTEXT, (WPARAM)idx, (LPARAM)textCode);

std::wstring str = std::wstring(textCode);
if (str.compare(L"Custom1") == 0) { return Example::Custom1; }
if (str.compare(L"Custom2") == 0) { return Example::Custom2; }
if (str.compare(L"Custom3") == 0) { return Example::Custom3; }
if (str.compare(L"Custom4") == 0) { return Example::Custom4; }
if (str.compare(L"Custom5") == 0) { return Example::Custom5; }
if (str.compare(L"Custom6") == 0) { return Example::Custom6; }
if (str.compare(L"Custom7") == 0) { return Example::Custom7; }

return -1;
}

void Callback(void *param, NotifyInfo *info) {
MessageBoxW(nullptr, L"Hello World!", L"Result", MB_ICONINFORMATION);
}

void Example::Register() {
int code = GetNotificationCode();

if (registeredCodes.count(code) == 1 && code != -1) {
ShowMessage(L"Notification already registered.");
return;
}
RegisterNotification(Callback, nullptr, code);
ShowMessage(L"Notification registered.");
registeredCodes.insert(code);
}

void Example::Broadcast() {
int code = GetNotificationCode();
if (code != -1) {
BroadcastNotification(code);
}
}

void Example::Unregister() {
int code = GetNotificationCode();
if (registeredCodes.count(code) == 1 && code != -1) {
UnRegisterNotification(Callback, nullptr, code);
ShowMessage(L"Notification unegistered.");
registeredCodes.erase(code);
return;
}
ShowMessage(L"Notification not registered.");
}

void Example::ForceUnregister() {
if (!registeredCodes.empty()) {
for (int code = Custom1; code <= Custom7; code++) {
UnRegisterNotification(Callback, nullptr, code);
}
ShowMessage(L"Notifications forcibly unregistered.");
registeredCodes.clear();
return;
}
ShowMessage(L"Notifications not registered.");
}

void Example::BeginEditParams(Interface* ip, IUtil* iu) {
this->ip = ip;
ex.InitDialog();
}

void Example::EndEditParams(Interface* ip, IUtil* iu) {
this->ip = nullptr;
}

void Example::InitDialog() {
CreateDialogParamW(hInstance, MAKEINTRESOURCE(IDD_PANEL), ip->GetMAXHWnd(), DlgProc, (LPARAM)this);

HWND cHandle = GetDlgItem(GetActiveWindow(), IDC_COMBOBOX);
for (int i = 1; i <= 7; i++) {
std::wstring checkBoxText = L"Custom" + std::to_wstring(i);
SendMessageW(cHandle, (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)checkBoxText.c_str());
}
SendMessageW(cHandle, (UINT)CB_SELECTSTRING, (WPARAM)0, (LPARAM)L"Custom1");
}

INT_PTR CALLBACK Example::DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
break;

case WM_CLOSE:
EndDialog(hWnd, 0);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;

case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_BN:
Example::Broadcast();
break;

case IDC_RN:
Example::Register();
break;

case IDC_UN:
Example::Unregister();
break;

case IDC_FUN:
Example::ForceUnregister();
break;
}
break;

default:
return FALSE;
}
return TRUE;
}
8 changes: 8 additions & 0 deletions c++/example/Example.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
LIBRARY CustomNotificationsDemo.dlu
EXPORTS
LibDescription @1 PRIVATE
LibNumberClasses @2 PRIVATE
LibClassDesc @3 PRIVATE
LibVersion @4 PRIVATE
SECTIONS
.data READ WRITE
67 changes: 67 additions & 0 deletions c++/example/Example.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// Demonstration on how to call custom 3ds Max notifications in C++.
// Works with 3ds Max 2019 and above.
// (c) 2019 Wesley Hill
//

#pragma once

#include "Max.h"

#include "istdplug.h"
#include "iparamb2.h"
#include "iparamm2.h"
#include "resource.h"
#include <maxtypes.h>
#include <utilapi.h>
#include <set>

extern HINSTANCE hInstance;
extern TCHAR *GetString(int id);

class Example : public UtilityObj
{
public:
Example() { }
virtual ~Example() { }
virtual void DeleteThis() { }
static void ForceUnregister();
static void Unregister();
static void Broadcast();
static void Register();
virtual void BeginEditParams(Interface *ip, IUtil *iu);
virtual void EndEditParams(Interface *ip, IUtil *iu);

enum CustomNotificationCode {
Custom1 = 4098, // 0x00001002
Custom2 = 4099, // 0x00001003
Custom3 = 4100, // 0x00001004
Custom4 = 4101, // 0x00001005
Custom5 = 4102, // 0x00001006
Custom6 = 4103, // 0x00001007
Custom7 = 4104, // 0x00001008
};

void InitDialog();
static INT_PTR DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

private:
Interface *ip;
HWND hPanel;
};

static Example ex;
static std::set<int> registeredCodes;

class ExampleClassDesc : public ClassDesc2
{
public:
virtual int IsPublic() { return TRUE; }
virtual void* Create(BOOL) { return &ex; }
virtual const TCHAR * ClassName() { return L"Custom Notifications Demo"; }
virtual SClass_ID SuperClassID() { return UTILITY_CLASS_ID; }
virtual Class_ID ClassID() { return Class_ID(0x6a287c04, 0x76533d12); }
virtual const TCHAR* Category() { return L"CustomNotificationsDemo"; }
virtual const TCHAR* InternalName() { return L"CustomNotificationsDemo"; }
virtual HINSTANCE HInstance() { return hInstance; }
};
Binary file added c++/example/Example.rc
Binary file not shown.
25 changes: 25 additions & 0 deletions c++/example/Example.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.757
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example", "Example.vcxproj", "{4E8DC1E8-083B-4518-9346-FA40FE903BC7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4E8DC1E8-083B-4518-9346-FA40FE903BC7}.Debug|x64.ActiveCfg = Debug|x64
{4E8DC1E8-083B-4518-9346-FA40FE903BC7}.Debug|x64.Build.0 = Debug|x64
{4E8DC1E8-083B-4518-9346-FA40FE903BC7}.Release|x64.ActiveCfg = Release|x64
{4E8DC1E8-083B-4518-9346-FA40FE903BC7}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B641622E-CF90-442A-B67E-8EFC9653E77C}
EndGlobalSection
EndGlobal
Loading

0 comments on commit 9c3f095

Please sign in to comment.