MaxSDK GUP plugin linker errors


#1

Hi there!

I am new to maxsdk, but already completed multiple input-output plugins (like our own gltf exporter in C++).

I prefer adding further integration to our plugins via menu items in the main menu so I changed architecture to create a *.gup instead of *.dli and add a single button on GUP plugin start that would run a maxscript command I am reading from a file near the plugin.

The problem is that I cannot instantiate a GUP plugin class because of the following linker errors:

1>------ Build started: Project: SDPlugin, Configuration: Debug x64 ------
1>cl : Command line warning D9025: overriding '/permissive-' with '/permissive'
1>dllmain.cpp
1>   Creating library C:\MagosIT\Autodesk\SpaceDesigner\impex\SDPlugin\x64\Debug\sdplugin.lib and object C:\MagosIT\Autodesk\SpaceDesigner\impex\SDPlugin\x64\Debug\sdplugin.exp
1>dllmain.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl GUP::GUP(void)" (__imp_??0GUP@@QEAA@XZ) referenced in function "public: __cdecl MaxScriptSdGui::MaxScriptSdGui(void)" (??0MaxScriptSdGui@@QEAA@XZ)
1>dllmain.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: virtual __cdecl GUP::~GUP(void)" (__imp_??1GUP@@UEAA@XZ) referenced in function "int `public: __cdecl MaxScriptSdGui::MaxScriptSdGui(void)'::`1'::dtor$0" (?dtor$0@?0???0MaxScriptSdGui@@QEAA@XZ@4HA)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual class BitmapManager * __cdecl GUP::Bmi(void)" (?Bmi@GUP@@UEAAPEAVBitmapManager@@XZ)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual unsigned __int64 __cdecl GUP::Control(unsigned long)" (?Control@GUP@@UEAA_KK@Z)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual int __cdecl GUP::EnumTree(class ITreeEnumProc *)" (?EnumTree@GUP@@UEAAHPEAVITreeEnumProc@@@Z)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl GUP::ExecuteFileScript(wchar_t const *)" (?ExecuteFileScript@GUP@@UEAA_NPEB_W@Z)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl GUP::ExecuteStringScript(wchar_t const *)" (?ExecuteStringScript@GUP@@UEAA_NPEB_W@Z)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual enum IOResult __cdecl GUP::Load(class ILoad *)" (?Load@GUP@@UEAA?AW4IOResult@@PEAVILoad@@@Z)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual class Interface * __cdecl GUP::Max(void)" (?Max@GUP@@UEAAPEAVInterface@@XZ)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual class DllDir * __cdecl GUP::MaxDllDir(void)" (?MaxDllDir@GUP@@UEAAPEAVDllDir@@XZ)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual struct HINSTANCE__ * __cdecl GUP::MaxInst(void)" (?MaxInst@GUP@@UEAAPEAUHINSTANCE__@@XZ)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual struct HWND__ * __cdecl GUP::MaxWnd(void)" (?MaxWnd@GUP@@UEAAPEAUHWND__@@XZ)
1>dllmain.obj : error LNK2001: unresolved external symbol "public: virtual enum IOResult __cdecl GUP::Save(class ISave *)" (?Save@GUP@@UEAA?AW4IOResult@@PEAVISave@@@Z)
1>C:\MagosIT\Autodesk\SpaceDesigner\impex\SDPlugin\x64\Debug\sdplugin.gup : fatal error LNK1120: 13 unresolved externals
1>Done building project "SDPlugin.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========

I am using classes and functions from the SDK already and they work so I have no idea why they the linker does not find these.

This is my additional includes directory:

<IncludePath>..\..\..\maxsdk\include;$(IncludePath)</IncludePath>
<LibraryPath>..\..\..\maxsdk\lib\x64\Release;$(LibraryPath)</LibraryPath>
  • with the given paths of course existing and containing the 2020 MaxSDK. I also see a file there called gup.lib that seems to be maybe what should contain these functions?

If I comment out the instantiation of the gup plugin class, I can build my app and earlier import-export plugins still work and build.

I return a class for gup as usual from the class desc:

void* Create(BOOL /*loading = FALSE*/) override {
	//FIXME:return new MaxScriptSdGui();
	return nullptr;
}

^^only return nullptr now so that the project builds.

The plugin class is this:

class MaxScriptSdGui : public GUP, ActionCallback, DynamicMenuCallback { ..... }

Likely I can drop ActionCallback now as it became a DynamicMenuCallback if needed, but I see no problem with that being there.

The documentation of the “missing” functions are like this:

	/*! \remarks Implemented by the System.\n\n
	This method will execute the specified MAXScript file.
	\par Parameters:
	<b>MCHAR *file</b>\n\n
	The file name for the script file.
	\return  TRUE indicates if the script was successfully sent to
	MAXScript; FALSE if it was not sent. Note that this does not reflect
	the result of the script. */
	GUPExport virtual	bool			ExecuteFileScript	( const MCHAR *file );
  • so I think the implementation should be there for these functions indeed. What do I do wrong?!
    Opening the gup.lib file I see that for exemple this ExecuteFileScript (and others) are listed there.

execute_is_there

Further information

  • This is purely C++ plugin so far
  • I only have maxsdk and max2020 - not other products.
  • PlatformToolset: v141
  • WindowsTargetPlatformVersion: 10.0.17763.0
  • My project was NOT made using the project wizards (I was unable to make them work at all) - but everything linked / worked until now
  • Windows 10, x64, VS2017 as usual. 3dsmax and maxsdk version is both 2020 version.

Original goal:

  • My aim is to put out a simple menu, that runs a maxscript contained in the plugin package itself which contains a more complicated GUI that interfaces with the C++ plugin parts when needed. For this is why I started using GUP as it supposedly runs at startup and sounds like a good place to create a single (“connect to server”) menu button for running the script and building GUI.
  • I am open to alternatives to what I am doing currently, but I want this to happen automatically on startup with no “installers” or other things that would “install” maxscript GUI elements or such. I cannot believe it is so hard to put up a simple menu item :frowning:

Any help is appreciated.
Richard - MagosIT

PS.: If I cannot make this work in a *.gup plugin. Is there an other way to do similar startup-gui-additions in a *.dli kind plugin that contains SceneImport and SceneExport plugin classes? I am not really sure of how life-cycle is for import/export plugins but I know that I can likely force my DLL to not “auto defer” and maybe then there would be some workaround to do operations at startup, but I still prefer to know a proper solution as *.gup sounds to be what I need instead of these hackz… just open to any suggestions…

PS.: Instead of doing it the GOP way, I can maybe try to do it in my DLLs “LibInitialize()” but that sound like a really-really awful idea even if I would force to not use “auto defer” plugin loading…


MaxSDK GUP plugin linker errors
#2

Pfff… I am rarely using VS and MSBuild to develop C++ being mostly linux guy so now I see the lib files were not marked to be used:

Tip for others: You can use /VERBOSE:LIB as a command line linker option to see what files it search for. From that moment it became clear that I somewhere added the files manually that it search but failed to add the gup.lib now


#3

you need to add

gup.lib
bmm.lib

to your linker::Input::Additional Dependencies, there may be others you are missing


#4

obviously its the “gup.lib”
and…
never compile in debug-mode, use hybrid if you need debugging
or do you have max’s debug libs ?


#5

I already fixed the issue when posted the screenshot about missing gup.lib, but I do not understand hybrid VS debug mode difference much. My project setup does not even have a “hybrid” build now. So thanks for answer but this problem is already solved above (that is classic: I go and ask question after lot of debugging but then I find solution right away after I asked haha - still thank you two for fast answer) and the little GUI is there now so an other team can do GUI in maxscript now anytime :wink:

I was not able to make the project wizard work so I just made the project files manually by putting together the project files in gvim from various random samples until they started to work and they are working well so far.

Debugger works even if I am attaching to a running 3dsmax that I start from within VS - except that of course I see no symbols of 3dsmax internals but that is normal in my opinion.

I do not know what debug libs are - is it something I would pay huge amounts for and getting source? Then I do not have it and likely not even need. All I use is the SDK.

How to mark this solved? I solved my issue on my own right after asking it… :frowning:


#6

what were the problems to get appWizzard running ?
since it exists, i never had any problems with it (the setup)
just follow the instructions in the readme.txt exactly at 100%

for hybrid builds
try to generate projects from appwizard, then you get a hybrid-buid entry
the sample code is mostly working but not really helpful
most important, you get a project-file with compiler and library settings

maybe i make a small tutorial: “How to setup SDK and get it working with appwizz” ?

debug vs release builds
when you build your project. the c-runtime libs from windows will be linked to your plugin
for release-mode and degug they are different!!
different libs mean:

  • in your debug-pluggy you request some memory (in DEBUG-library)
  • max releases this memory at some point (in RELEASE-library)
  • result is an unstable max, possibly random crashes, you end up searching for bugs where are none

more: https://stackoverflow.com/questions/11658915/mixing-debug-and-release-library-binary-bad-practice

debug-builds of max, if you have too much money…
https://help.autodesk.com/view/MAXDEV/2021/ENU/?guid=__developer_writing_plug_ins_building_the_sample_plug_ins_hybrid_debug_and_release_build_c_html


#7

guruwareExpert4h
what were the problems to get appWizzard running ?
since it exists, i never had any problems with it (the setup)
just follow the instructions in the readme.txt exactly at 100%

That is what I tried and it never worked. For me it was much easier to dig into the vcproj files via vim and see what is going on and beat it into shape haha :slight_smile:

I am not really a “clicks on the gui” kind of guy coming from linux c++ development hihi :slight_smile:

maybe i make a small tutorial: “How to setup SDK and get it working with appwizz” ?

It is good idea nevertheless. I am fine with my own solution for now as I created a project skeleton that works always and we can copy it whenever needed so for me it does not count, but creating my skeleton was a measurable amount of work months ago.

different libs mean:

in your debug-pluggy you request some memory (in DEBUG-library)
max releases this memory at some point (in RELEASE-library)
result is an unstable max, possibly random crashes, you end up searching for bugs where are none

Oh I see. So the point of a hybrid build is that it tries to support memory allocation schemes better when pointers and ownership are passed between max and the plugin. It seems this have not gotten us yet at all yet but I see your point.

I guess this likely happens if the allocation is in some function that is not linked to my code, but for example gets inlined from some header when I call the function (or if I am dumb-enough to instantiate classes of max on my own instead of asking for it). I see how this can be harmful, but is “hybrid” build a “thing” in visual studio normally or is it just some configuration that max projects use. I guess it is the former. Hopefully it will be not hard to transform a debug config into a hybrid one then, because I see value in changing to that in the future.

Going for a hybrid config will be low-priority for now, because our plugin is already quite stable as-is, but I certainly create a task for this because I see the danger in this!


#8

Okay I grew unsure… maybe it is just a MAXSDK thing:

https://help.autodesk.com/view/3DSMAX/2017/ENU/?guid=__files_GUID_AF966D24_7646_4EE2_AC0D_DEA05DA277B9_htm

This kind of hints it is just in maxsdk wizard and examples. Btw if that is the case it can be that I already configured my debug build similarily by hand because I “stole stuff from multiple places” so it might be already ok then… But I will check it later.


#9

its not just a max-thing, you should never mix libraries runtime-libs
as said, you might end up searching for errors which are just because of different libraries used
what if a header has some #ifdefs for debug/release-mode? anyways…

Hybrid is just a name for a config in visual studio
Hybrid is same as Debug, only difference is that its using the release runtime-libs

how to build one in VC:

  • on top of VC you have a droplist to choose debug or release
  • there is also an entry “Configuration Manager…” in this list - click that
  • in the Configuration Manager Dialog under “Actve Solution Configuration” choose “<New…>”
  • here you enter the name “Hybrid” or whatever name you want
  • below in “Copy setting from” choose Debug
  • click “OK” and then “Close”
    now you have a Hybrid config
    open properties for this Hybrid config
    under “Code Generation” set as Runtime Library: Multi-threaded DLL (/MD)
    click OK, now use your Hybrid configuration instead of Debug

welcome to the world of clicking :slight_smile:


#10

In other worlds you need to add this line - without clicking:

<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MultiThreadedDLL</RuntimeLibrary>

Indeed it was missing, but I just added to our debug config - maybe I will rename that but I am sure we will likely not use a debug build of max for a lot of money so it can be as-is in our skeletons and plugins.

Was good you mention this.

“its not just a max-thing” VS. “Hybrid is just a name for a config in visual studio”

For me this indeed qualifies “hybrid” as a convention that is a “max thing” because I could have named it anything from “kiskacsa” (=duck) from anything else and would still work. My point was that I was not sure if calling these as “Hybrid” is some kind of windows-world convention or just something you made up for max as the naming convention. It does not count much as a difference, just was interested because I can imagine this is common issue over windows and closed source systems so maybe it is well known terminology to call these kind of builds hybrids - but I find no trace of that or not much and that is why I asked.

“what if a header has some #ifdefs for debug/release-mode?”

Mine always has for example. Logging is a good example. Also unit testing and mocking is an other for my code.

Anyways. Thanks for all. These things already work for now :wink:

PS.: Is there anything here that I need to do to close this discussion here?


#11

actually now the build fails for unit tests:

2>linker_includes.obj : error LNK2019: unresolved external symbol __imp__invalid_parameter referenced in function "void * __cdecl std::_Allocate_manually_vector_aligned<struct std::_Default_allocate_traits>(unsigned __int64)" (??$_Allocate_manually_vector_aligned@U_Default_allocate_traits@std@@@std@@YAPEAX_K@Z)
2>SDPluginTest.obj : error LNK2001: unresolved external symbol __imp__invalid_parameter
2>linker_includes.obj : error LNK2019: unresolved external symbol __imp__CrtDbgReport referenced in function "void * __cdecl std::_Allocate_manually_vector_aligned<struct std::_Default_allocate_traits>(unsigned __int64)" (??$_Allocate_manually_vector_aligned@U_Default_allocate_traits@std@@@std@@YAPEAX_K@Z)
2>SDPluginTest.obj : error LNK2001: unresolved external symbol __imp__CrtDbgReport
2>C:\MagosIT\Autodesk\SpaceDesigner\impex\SDPlugin\x64\Debug\SDPluginTest.exe : fatal error LNK1120: 2 unresolved externals

#12

As a workaround I just removed the “MultiThreadedDLL” settings for the unit tests, because maxsdk is not included in the tests anyways (just mocking parts of maxsdk by my own code for sensing operations anyways).

Have no idea why this is however. Only changed that single line. Maybe the multithreaded libs have different linkage needs here and there which is a bit weird but fine… would be good to know in case someone will set the multi-threaded to be on to the unit test project and maybe include maxsdk code in it but I see no reason why that should be hybrid build so I keep only the main project to build as hybrid.