Developing Add-Ons for CC3+ – Part 1: Getting Started

Campaign Cartographer 3+ is a a very configurable and extensible program. In addition to the core program, users can purchase official add-ons, providing not just new artwork, but also new tools. Users can easily add new artwork such as symbols and fills, and many users with an artistic talent create such resources themselves and import into CC3+ for use with their maps. It is also easy for users to create their own drawing tools and organize symbols into symbol catalogs. For the more advanced users, it is possible to customize the menus and toolbars, and write macro commands which can be used to add additional functionality or automate tasks.
But, the most powerful option is the possibility of writing your own add-ons, or XP’s. While you can do a lot with macros, you are still limited to the commands actually provided by CC3+. Clever combinations of these commands can yield interesting results, but sooner or later you will run into things you can’t do. And this is where XP development comes in. By writing your own add-ons for CC3+, you get direct access to the building blocks of your drawing, and can write your own commands for CC3+ to do all kinds of stuff.
In this series of articles I will teach you how to write these add-ons yourself. A word of warning here; these articles will teach you about XP development, but I’ll have to assume you actually know something about programming, and in particular, C++. If you don’t know that, I recommend you find yourself a free C++ tutorial on the internet and start there before coming back, as you will have problems following the tutorials otherwise.

In this first tutorial we’ll look at how to set up your programming environment, as well as making our first code.

Note that you can easily find all the articles published in this series so far by using this link.

About XP Development

The technical term for a CC3+ add-on is an XP (eXtended Procedures). This is a set of new CC3+ command compiled into a library file (.dll) that is copied into the CC3+ installation directory. CC3+ automatically includes these library files on startup, and makes all the commands in them available to the program. For example, City Designer 3 comes with the cd2.dll file which contains all the extra commands from this add-on. Remove this file and commands like the random street command stop existing.
Note that an XP is technically different from an Add-On. An add-on comes with not just new commands, but new artwork, templates, drawing tools and so on. An XP only covers the new commands. So, technically an add-on don’t need to contain an XP at all (like SS1 which is basically only artwork). Likewise, you can make an XP that just adds a few more commands to CC3+, it doesn’t have to come with everything else you see in a fully fledged add-on.

CC3+ is built on the codebase of FastCAD by Evolution Computing, and to some degree, CC3+ itself is actually an XP for this program. So, this way of adding functionality by coding XP’s is inherited from FastCAD, which is something you will encounter in the XP documentation. Note that CC3+ has introduced significant changes in the codebase, and any XP written for CC3+ is unlikely to work with FastCAD, but the core and way of doing things remain the same. Note that XP’s can be written in assembler, C or C++, but I’ll stick to C/C++.

The codebase is directly dependent on the Windows SDK, so some familiarity with this is also helpful.

Setting up your Environment

To develop XP’s for CC3+ you need two pieces of software, the Visual Studio IDE and the XP toolkit. You’ll obviously also need a copy of CC3+ to test your XP. For this tutorial I’ll be using Visual Studio IDE 2019 Community Edition. The community edition is the free version of Visual Studio IDE, and contains everything we need, but if you prefer, you can develop XP’s with any version and edition of visual studio, so if you already have a version installed and feel comfortable with using that, you can safely continue using that. From now on, I’ll just refer to the program as Visual Studio, but all my instructions and screenshots are from the selected 2019 Community version.

Installing Visual Studio

You can download Visual Studio here.

When installing Visual Studio, you will be met by a screen with a lot of different options for what to install. The most important option here is the Desktop development with C++ workload. Along with this, I also recommend the optional feature MSVC v141 – VS 2017 C++ x64/x86 build tools which become available in the list to the right once you select the Desktop development with C++ workload. The optional feature is not strictly required, but it let us build XP’s with the same dependencies that CC3+ already has, so everyone with CC3+ can just use the XP without installing any additional libraries, while if you develop using the default libraries for Visual Studio 2019 then every user will have to install the appropriate C++ runtime libraries as well. I am going to assume you install this feature.

Additionally, for later articles in this tutorial series, we are going to need the .NET desktop development workload too.

Note that Visual Studio do require quite some space to install, so plan both for a disk use of ~10GB as well as internet bandwidth use for the same size to download the program. Visual Studio don’t come with a full installer you can download somewhere else, it will download the components after you select the desired options in the installer.

Note that when it comes to Visual Studio, I’ll explain in details the required steps to successfully create and build an XP project, but giving a detailed explanation of how everything works in Visual Studio is far beyond the scope of this tutorial. I’ll assume you know your way around Visual Studio, and know how to create an application in it.

Installing the XP toolkit

You can download the XP toolkit here.

The XP toolkit is just a zip file, and it can technically be extracted anywhere you want (but keep it on the local disk, and not a network drive, this is also recommended for the projects you create in Visual Studio). For this tutorial series I assume you unzipped it to the default C:\FCWXP, if not, adjust any paths as required.

Note that the documentation and examples accompanying this toolkit is very old, but don’t let that discourage you. The actual files needed for creation of XP’s are fully up to date.

Setting up a Project

With all the software ready, we can start by creating a Visual Studio project for our XP. We need to first create a new library project in Visual Studio, and then manually make some changes to the project settings as well as inserting some basic code required for an XP to function.

While I recommend that you follow the instructions below and set up your first project manually to learn about the different options, I have also made a XP Template that you can download and install into Visual Studio. When you start a new project based on this template, all those settings will already be configured for you. The use of this template do require that you did set up the XP toolkit to C:\FCWXP as outlined above, and that you have a copy of CC3+ installed in C:\CC3Plus for development purposes (See the “Easier Testing and Debugging” chapter near the end of this article)

Creating the Project

Start Visual Studio, and in the startup dialog, hit the Create a new project button to the right (If you are already inside the ide, you could click File -> New -> Project instead). This brings up the Create a new project dialog.

We want to start a project using the Windows Desktop Wizard template, using C++ code. You can scroll down in the list, or you can use the search box and filter options on the top to find it. Select it, and hit Next.

On the next screen, give your project a meaningful name, such as My First XP. You can also change the location if you prefer.

Finally, the Windows Desktop Project dialog shows. Make sure to select Dynamic Link Library (.dll) as the application type, and also check Empty Project, then leave the rest of the checkboxes empty.

Creating the First Code File

Before we can access all the configuration options, we need our first source code file. In the Solution Explorer pane to the right, right click the Project name (NOT the Solution name) and select Add -> New Item from the context menu. In the dialog that shows, pick C++ File (.cpp) and give it a decent name, such as Main.cpp before hitting the Add button.

This will create a new blank code file. We’ll add code to it shortly.

Configuring the Project

First of all, make sure the dropdown on the top toolbar is set to x86 and not x64. CC3+ itself is a 32-bit application, and our XP’s need to be too. if this is set to x64, you’re going to get all kinds of errors as we proceed.

Before we can start creating our XP, we need to tell Visual Studio where the files for the XP toolkit is. We’ll also need to change a few other options to make Visual Studio understand which kind of C++ code we are writing. C++ is a very powerful language, but with that comes a cost, it is possible to do things that other programing languages won’t allow you to do for safety reasons. Modern C++ tries to prevent developers from using some of these features, because if you don’t know what you are doing, you can quickly run into serious issues. However, the FastCAD engine do use a lot of these features, because it also allows for faster and more efficient code. As a result, we must tell Visual Studio that we are writing code that depends on these features and we need to be allowed to do so.

Right click the project name in the Solution Explorer and choose Properties. In the Property dialog that shows, make sure to first set the Configuration dropdown in the top left to All Configurations, and also make sure Platform is Active(Win32) (or just Win32). Visual Studio allows us to set different options for Debug builds and Release builds of our application, but the options we set now should apply to both.

These are the options you need to set

 

Where Setting Value Comment
General Windows SDK Version 10.0.17763.0 This is the latest major version of Windows 10 (Fall Creators Update). You can target an earlier version if you wish, but do NOT leave it at “10.0 (latest installed version)” as that will cause errors.
Configuration Type Dynamic Library (.dll)
Platform Toolset Visual Studio 2017 (v141) This option makes the project binary compatible with Visual Studio 2017 projects. CC3+ itself is being built using VS 2017, so by using this toolset we don’t have to install any other runtime libraries on the computers we deploy our XP on.
Character Set Use Multi-Byte Character Set Sets up the character set used in the project. MBCS uses UTF-8, which is compatible with ASCII, which is what CC3+ uses.
C/C++ -> General Additional Include Directories C:\FCWXP\xpdev;%(AdditionalIncludeDirectories)
C/C++ -> Language Conformance mode No
Linker -> Input Additional Dependencies c:\fcwxp\xpdev\fcw32.lib;%(AdditionalDependencies)

Template Code

Finally, we can put in the template code. Paste this into the empty code file (Main.cpp) you made earlier. Just paste it in for now, we’ll discuss the code a bit later.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <windows.h>
#include "XP.H"

#define XPID 0xF000

void XPCALL About(void);

char CList[] = "DEMO\0\0";
PCMDPROC PList[] = { About, About };

XP MyXP = { 0, CList, PList, 0, 0, 0, XPID, 0, 620, 0, 0, 620 };

/////////////  DllMain - XP initialization & Unload code //////////////
BOOL WINAPI DllMain(const HINSTANCE hDLL, const DWORD dwReason, LPVOID lpReserved) {
	UNREFERENCED_PARAMETER(lpReserved);

	switch (dwReason)
	{
	case DLL_PROCESS_ATTACH:
		MyXP.ModHdl = hDLL;
		_XPRegCmd(&MyXP);
		break;
	case DLL_PROCESS_DETACH:
		_XPUnregCmd(&MyXP);
		break;
	default:
		break;
	}
	return TRUE;
}

void XPCALL About() {

	FORMST(MyAPkt, "My XP\n\n"
		"This is my XP. You should make your own"
	)

	FormSt(&MyAPkt, RSC(FD_MsgBox));
	CmdEnd();
}

Testing

Our XP project should now be configured properly, and we can build our first XP. It won’t do much yet, but it will work.

It is important that we build our new XP as a 32-bit library, so make sure the dropdown on the toolbar is set to x86 and not x64 before you proceed.

In Visual Studio, select Build Solution from the Build menu. Assuming the build succeeds (If not, check the project setup details we just went through) you now have a working .dll file for your XP.

Copy this .dll file (you’ll find it in the solution directory, easiest way to go there is to right click the solution in the solution explorer window, and select Open Folder in File Explorer. The .dll should have the same name as your project, and should be in the Debug directory at that location) to your CC3+ installation directory (This is C:\Program Files (x86)\ProFantasy\CC3Plus by default, don’t confuse it with the CC3+ data directory).

Now start CC3+ and type DEMO at the command line. You should get a dialog box showing with the text from line 34-35 in the code above. Assuming this worked, you have just built a functional XP. It doesn’t do much yet, but it works!
Remember that you must start CC3+ AFTER copying in the library file. CC3+ won’t pick up on files being copied into the directory while running.

You can also check that CC3+ loaded your XP by typing XPCFG on the command line and look at the list of XP’s. Theoretically you should be able to choose your .dll in the list and hit About to see the result of the about function for that particular XP, but a small bug have resulted in the button calling the wrong XP. You should normally be able to get the about response from your XP by trying to select the XP a few positions above however.

Dissecting the Code

Let us break down the code we pasted in earlier and discuss the important parts of it. Note that this is C++ and I do assume that you have an understanding of this, otherwise you may not fully understand the explanations

line 1: windows.h includes most of what we need from the Windows SDK. This provides api access to Windows.

line 2: This includes everything we need to build an XP. This file will in turn include most of the other elements from the XP Toolkit.

line 4: All XP’s have an ID. This is mainly used to identify which XP is responsible for which tools/commands, and isn’t terribly important for you. You can pick a random number between 0xF000 and 0xFFFF for your XP. The rest of the numbers are reserved for registered XP’s, don’t use those. Note that a conflict with the ID numbers don’t have any important consequences.

line 6: Standard C++ declaration of the About function

line 8: This string defines all the commands this XP provided to CC3+. Each command name is null-terminated, and there is also an extra null character at the end of the string. Convention dictates we write these in upper case, but when typed inside CC3+ they are not case sensitive.

line 9: This array contains function pointers to the functions to use for each command. The functions here are mapped to the commands from line 8. Note that the first command here is always the About command for the XP, and this does not have an entry in the command list. So technically, the second entry here maps to the first entry in the command list, the third to the second in the command list, and so on. In this particular example, About appears twice in this example because the first entry is the default required about entry, and the second entry is to connect the About function to the DEMO command just so we would have a command to test.

line 11: Instantiates a struct with important values for the XP. You’ll notice it references the various variables from the lines above. This is a boilerplate line, and will always look like this.

line 14-30: These lines are boilerplate code that handles the registration and unregistration of the dll. These lines will always look exactly like this, and are required.

line 32-40: This is the About function for this XP. It is required for every XP to have an About function, and generally, it will always look like this, just with a bit different text. FormSt is simply short for Format String and is the system CC3+ uses to provide messages to the user. We’ll discuss this in a later article, for now, let us just accept it. Note that if you change the text here, do NOT put in an exclamation mark (“!”), as this has special meaning to the FormSt command. CmdEnd() tells CC3+ that the command ends here. This is required, otherwise you will get errors when you start the next command.

Let’s Create

Now that we have discussed how XP’s work, set up the default environment, added the template code and built a working XP, let us actually do something ourselves before we end this tutorial.

When adding the code below, I strongly recommend you take the time to type in the code yourself rather than just copy and paste it. Typing it yourself is the best way to notice all the small nuances of how the code is built up.

I won’t explain all the code below in detail, it contain concepts we will be discussing in a later article, but I will provide a few words to help you understand what is going on.

First, at the bottom of your main.cpp file, add this code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
char name[50];

void XPCALL SayHello(const int Result, int Result2, int Result3)
{
	if (Result != X_OK) { CmdEnd(); return; }
	UNREFERENCED_PARAMETER(Result2);
	UNREFERENCED_PARAMETER(Result3);

	FORMSTPKT(MyFPkt, "Hi !01\nHave a Nice Day\0", 1)
		ITEMFMT(name, FT_Stg, FJ_Var, 0, 0)
	FORMSTEND

	FormSt(&MyFPkt, RSC(FD_MsgBox));
	CmdEnd();
}

void XPCALL Demo() {
	FORMST(lpszPrompt, "Your Name:\0")

	RDATA NameReq =
	{ sizeof(RDATA), RD_TxWord, NULL, RDF_C, (DWORD*)& name,
	(DWORD*)& lpszPrompt,RDC_ARROW, SayHello, NULL, NULL, 0, NULL, 0 };

	ReqData(&NameReq);

}

Then, near the top, find

void XPCALL About(void);

and add this below it

void XPCALL Demo(void);

Finally, in the PList array, replace the second About with Demo, so it looks like this

PCMDPROC PList[] = { About, Demo };

This final change made it so the DEMO command when used in CC3+ now calls our Demo function instead of About. We don’t really need a command to call the about function, but if we wanted to keep it, we could have added the Demo entry after the last About instead of replacing it, as well as adding another command to the CList array above to match it.
You can now build the .dll, copy it to your CC3+ directory and test it by typing DEMO at the command line.

The command line will now ask for your name, so type it in (single word only) and hit enter.

Explaining the Code

So, what do the code lines we just wrote mean? I’ll get into some more details in a later article, but lets us give a short overview

line 1: Declare a variable to hold some text. This will be used to carry data between our functions below. We set it up to hold 50 characters. Note that because the way this variable is accessed later, it is easy to put more than 50 characters in it which could cause buffer overrun problems, so always make sure you provide a big enough buffer for the expected input.

line 17-26: This is the function that gets called by our DEMO command

line 18: This prepares a string which contains the prompt we wish CC3+ to give

line 20-22: RDATA is a struct that tells CC3+ how to ask for data, what to ask for and what to do with it. You can see it contains the value RD_TxWord which tells CC3+ the input should be a single word; a reference to our variable name from line 1, this is where it will put the data; a reference to lpszPrompt, the prompt variable we defined on line 18, and SayHello, the function starting on line 3. In short, what will happen here is that it will ask the user to input a text string on the command line, using the prompt text we defined, and when the user provides input, it will be stored in the name variable, and then the function SayHello will be called.

line 24: This is the request data call, and this is what actually tells CC3+ to ask the user for input, using the setup we defined in lines 20-22.

line 3-15: This method will be called to handle the input the user just provided

line 5: Here we check that the appropriate input was received (depending on what we expected), if we didn’t (for example, the user hit esc to terminate the command, or typed text when a number was requested) we terminate the command here. It is important to remember to call CmdEnd() before exiting

line 9-11: Here we set up a text that will be shown in a text box. The interesting part here is the !01 in the text, which says that the first parameter should be inserted here. The parameter itself (the name variable) is defined on line 10, where we also tells CC3+ that this is a string (FT_Stg) (The !01 syntax is why we can’t simply have an exclamation mark in the text)

line 13: Here we use the text output service in CC3+ to display a message box with the text we just set up.

line 14: And finally we tell CC3+ that our command is at an end.

You can download my solution. Note that this assumes default paths.

Easier Testing and Debugging

So far I have just told you to build the .dll and copy it to the CC3+ directory yourself. This isn’t that bad if we know what we have written works exactly as we planned, but anyone who deals with coding knows that frequent testing is often required. And you also need to use the debugging tools in the IDE when testing.

So, we can instead get Visual Studio to put the .dll right into the CC3+ directory after compiling it, and start CC3+ automatically.

Note that for this process to work, Visual Studio must be able to write to the CC3+ installation directory. This is normally blocked, because Windows UAC blocks writes to the Program Files (x86) directory. The best way to handle this is to have a separate CC3+ install somewhere else on your drive dedicated to development. Now, CC3+ don’t allow you to select your installation location, but what you can do is to just copy the full CC3Plus directory from Program Files (x86)\ProFantasy and put it somewhere else, for example to C:\CC3Plus. This has the added advantage that you don’t put development files into your regular CC3+ install. And the two installs would share the same data directory, so you don’t need to worry about duplicating that one and all the extra space that would take (after all, the data directory is the large one, the install directory is tiny). Also make sure to set the security settings on the directory you copied to allow the Users group write access.

Now, in the project properties under Build Events -> Post-Build Event, set Command line to
copy "$(OutDir)$(TargetName)$(TargetExt)" c:\cc3plus\

This will cause Visual Studio to copy the .dll it built to the CC3plus directory, assuming the build was successful.

Then, on the debugging category, set the Command option to your CC3+ executable (C:\cc3plus\fcw32.exe if you followed my example). Once you have done this, hitting the start debug button will build the .dll, then copy it automatically into the CC3+ installation directory, and CC3+ will start, ready to test your commands. Now you can easily use breakpoints, memory profiling and all the other tools of Visual Studio with your XP.

Note that when you double click a drawing (.fcw file) to open it, it will open in the last CC3+ instance you used. To ensure that a drawing opens in your regular install, and not the copy you made for develoment, start the regular version at least once before double clicking map files in explorer.

Help and Discussions

The ProFantasy Community Forum has a dedicated category for Macros and XPs. I recommend you post any questions you may have over here. Comments on this blog entry is not a good place to get help, in part because I don’t get alerted when new comments are posted, and I don’t go around checking old posts for comments.

2 Responses to “Developing Add-Ons for CC3+ – Part 1: Getting Started”

  1. Great first part; looking forward to the rest of it šŸ™‚

    Questions:
    Is Windows SDK Version 10.0.17763.0 related to the compatibility of the final XP? That is, will the XP work in CC3+ under Windows 7?

    Also, does this XP Toolkit build XPs only compatible with CC3+? Or will the resulting XP also work with CC3?

  2. Windows is mostly backwards compatible, meaning that even if you target the latest Windows release like we are doing here, it will work on earlier versions of Windows too, as long as we don’t implement newer features only available in Windows 10. This won’t normally be a concern for creating XP’s.
    As for CC3/CC3+, it is mostly the same answer. The XP will work unless it targets functionality that was added/changed with CC3+.