-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
2,464 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.