You may have noticed that there are many typing commands in MicroStation. The Key-in icon can be found in the Primary group of the Home card. The Key-in Command dialog box can be opened, where you can browse and execute all currently available key-in commands, as shown in the figure below. Although only four columns are listed in this dialog box, each typing command can consist of more than 4 words.
These typing commands have many uses: for example,
Typing commands is an important link between the MicroStation graphical user interface and background code execution. The four uses of the typed commands listed above are shown below:
[1] | [2] |
[3]
[4]
Below we step by step to add command functions to the existing HelloWorld project.
1. Create a new text file HelloWorldCmd.r in Visual Studio, copy the following content into this file, and save it.
#include <Mstn\MdlApi\rscdefs.r.h> #include <Mstn\MdlApi\cmdclass.r.h> /*----------------------------------------------------------------------+ | Local Defines +----------------------------------------------------------------------*/ enum CmdTableIds { CT_NONE = 0, CT_MAIN, CT_SUB, CT_CREATE }; /*----------------------------------------------------------------------+ | HelloWorld commands +----------------------------------------------------------------------*/ CommandTable CT_MAIN = { { 1, CT_SUB,PLACEMENT, REQ,"HELLOWORLD" }, }; CommandTable CT_SUB = { { 1, CT_CREATE, INHERIT, NONE, "CREATE" }, }; CommandTable CT_CREATE = { { 1, CT_NONE, INHERIT, DEF, "Line" }, { 2, CT_NONE, INHERIT, NONE, "ComplexShape" }, { 3, CT_NONE, INHERIT, NONE, "ProjectedSolid" }, { 4, CT_NONE, INHERIT, NONE, "BsplineSurface",}, };
The above command table file defines the following 6 key-in commands, each of which has a corresponding command number. Now create a HelloWorldCmd.h file and add the following:
#define CMD_HELLOWORLD 0x0100000000000000UI64 #define CMD_HELLOWORLD_CREATE 0x0101000000000000UI64 #define CMD_HELLOWORLD_CREATE_LINE 0x0101010000000000UI64 #define CMD_HELLOWORLD_CREATE_COMPLEXSHAPE 0x0101020000000000UI64 #define CMD_HELLOWORLD_CREATE_PROJECTEDSOLID 0x0101030000000000UI64 #define CMD_HELLOWORLD_CREATE_BSPLINESURFACE 0x0101040000000000UI64
In the above HelloWorldCmd.r command table file:
2. Open the HelloWorld.mke file in Visual Studio and make the following two changes:
a. Change appRscs = $(o)$(appName).rsc
to appRscs=$(o)$(appName).rsc $(o)$(appName)Cmd.rsc
b. Add the lines :
$ (baseDir)$(appName) Cmd.h : $(baseDir)$(appName)Cmd.r
$(o)$(appName)Cmd.rsc: $(baseDir)$(appName)Cmd.r
Note: The above code contains two very important blank lines. You cannot delete them at will. A blank line indicates that the target file is generated according to the default rules. During the compilation process, bmake will find the .r .h and .r .rsc rules in the mdl.mki file to compile and generate.
#-------------------------------------------------------- # MicroStation CONNECT HelloWorld.mke # Fixed by LA Solutions #-------------------------------------------------------- PolicyFile = MicroStationPolicy.mki DEFAULT_TARGET_PROCESSOR_ARCHITECTURE=x64 appName=HelloWorld appObjs = $(o)$(appName)$(oext) appRscs = $(o)$(appName).rsc $(o)$(appName)Cmd.rsc baseDir = $(_MakeFilePath) mdlLibs = $(MSMDE)library/ %include mdl.mki #-------------------------------------------------------- # Create needed output directories if they don't exist #-------------------------------------------------------- always: ~mkdir $(o) ~mkdir $(rscObjects) ~mkdir $(reqdObjs) #-------------------------------------------- # Create command table and header file #-------------------------------------------- $(baseDir)$(appName)Cmd.h:$(baseDir)$(appName)Cmd.r $(o)$(appName)Cmd.rsc: $(baseDir)$(appName)Cmd.r #-------------------------------------------------------- # Define macros for files included in our link and resource merge #-------------------------------------------------------- DLM_NO_SIGN = 1 DLM_OBJECT_DEST = $(o) DLM_NAME =$(appName) DLM_NO_DLS = 1 DLM_NO_DEF = 1 DLM_NOENTRY = 1 DLM_OBJECT_FILES = $(appObjs) DLM_NO_MANIFEST = 1 DLM_DEST = $(mdlapps) LINKER_LIBRARIES = $(mdlLibs)bentley.lib \ $(mdlLibs)BentleyAllocator.lib \ $(mdlLibs)mdlbltin.lib \ $(mdlLibs)RmgrTools.lib \ $(mdlLibs)BentleyGeom.lib \ $(mdlLibs)DgnPlatform.lib \ $(mdlLibs)dgnview.lib #----------------------------------------------------------------------- # Generate resource files #----------------------------------------------------------------------- $(o)$(appName).rsc: $(baseDir)$(appName).r #--------------------------------------------- # Merge the app resources using rlib #--------------------------------------------- $(o)$(appName).mi : $(appRscs) $(msg) > $(o)make.opt -o$@ $(appRscs) < $(RLibCmd) @$(o)make.opt ~time appRscs = \ $(o)$(appName).mi \ $(o)$(appName).rsc $(DLM_DEST)$(appName).ma : $(appRscs) $(msg) > $(rscObjects)make.opt -o$@ $(appRscs) < $(RLibCmd) @$(rscObjects)make.opt ~time #----------------------------------------------------------------------- # Builds any necessary C++ CODE modules and link them to DLL #----------------------------------------------------------------------- $(o)$(appName)$(oext):$(baseDir)$(appName).cpp %include dlmlink.mki # Blank line above required for MKE/MKI files, this line for editors that rip.
3. Here are a few changes to HelloWorld.cpp:
a. Include HelloWorldCmd.h.
#include <Mstn\MdlApi\MdlApi.h> #include <DgnPlatform\DgnPlatformApi.h> #include "HelloWorldCmd.h"
b. Delete some original function calls in the MdlMain function, add command numbers and dynamic array definitions of command processing functions, open resource files, load command tables, and register command numbers.
MdlCommandNumber cmdNums[] = { { (CmdHandler)createALine, CMD_HELLOWORLD_CREATE_LINE }, { (CmdHandler)createAComplexShape, CMD_HELLOWORLD_CREATE_COMPLEXSHAPE }, { (CmdHandler)createAProjectedSolid,CMD_HELLOWORLD_CREATE_PROJECTEDSOLID }, { (CmdHandler)createABsplineSurface, CMD_HELLOWORLD_CREATE_BSPLINESURFACE }, 0 }; extern "C" DLLEXPORT void MdlMain(int argc, WCharCP argv[]) { ModelInfoCP pInfo = ACTIVEMODEL->GetModelInfoCP(); g_1mu = pInfo->GetUorPerStorage(); RscFileHandle rscFileH; mdlResource_openFile(&rscFileH, NULL, RSC_READONLY); mdlParse_loadCommandTable(NULL); mdlSystem_registerCommandNumbers(cmdNums); }
The mdlResource_openFile in the above code opens the resource file HelloWorld.ma, and then mdlParse_loadCommandTable loads the command table resource from it. The correspondence between the command processing function and each command number is defined in the dynamic array cmdNums, and then registered by mdlSystem_registerCommandNumbers. We did not define a set of command names at the same time as in most MDL examples (requires registration with mdlSystem_registerCommandNames), because the use of command names is far less convenient than typing commands. The use of command names is only necessary if you have not defined a command table.
c. Make some modifications to createALine, createAComplexShape, createAProjectedSolid, and createABsplineSurface to meet the requirements as command processing functions. At the same time, the assignment of basePt is built into each function. The modified code is as follows:
/*-------------------------------------------------------------+ | HelloWorld.cpp | +-------------------------------------------------------------*/ #include <Mstn\MdlApi\MdlApi.h> #include <DgnPlatform\DgnPlatformApi.h> #include "HelloWorldCmd.h" USING_NAMESPACE_BENTLEY_DGNPLATFORM USING_NAMESPACE_BENTLEY_MSTNPLATFORM USING_NAMESPACE_BENTLEY_MSTNPLATFORM_ELEMENT double g_1mu; void createALine(WCharCP unparsed) { DPoint3d basePt = DPoint3d::FromZero(); EditElementHandle eeh; DSegment3d seg; seg.Init(basePt, DPoint3d::From(basePt.x + g_1mu * 2, basePt.y + g_1mu)); ICurvePrimitivePtr pCurve = ICurvePrimitive::CreateLine(seg); DraftingElementSchema::ToElement(eeh, *pCurve, nullptr, ACTIVEMODEL->Is3d(), *ACTIVEMODEL); eeh.AddToModel(); } void createAComplexShape(WCharCP unparsed) { EditElementHandle eeh; MSElement el; MSElementDescrP edP = NULL; DPoint3d basePt, pts[3]; basePt.x = 1.7*g_1mu; basePt.y = -0.3*g_1mu; basePt.z = -0.6*g_1mu; mdlComplexChain_createHeader (&el, 1, 0); mdlElmdscr_new (&edP, NULL, &el); pts[0] = pts[1] = pts[2] = basePt; pts[1].x += g_1mu*0.3; pts[1].y += g_1mu*0.7; pts[0].x += g_1mu; pts[0].y += g_1mu; DEllipse3d arcPts = DEllipse3d::FromPointsOnArc(pts[2], pts[1], pts[0]); CurveVectorPtr pCurveVec = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Outer); pCurveVec->Add(ICurvePrimitive::CreateArc(arcPts)); pts[1].x = pts[0].x; pts[1].y = pts[2].y; pCurveVec->Add(ICurvePrimitive::CreateLineString(pts, 3)); DraftingElementSchema::ToElement(eeh, *pCurveVec, nullptr, ACTIVEMODEL->Is3d(), *ACTIVEMODEL); eeh.AddToModel(); } void createAProjectedSolid(WCharCP unparsed) { DPoint3d basePt, pts[6]; basePt.x = 3.2*g_1mu; basePt.y = -0.6*g_1mu; basePt.z = -1.2*g_1mu; pts[0] = basePt; pts[0] = basePt; pts[1].x = pts[0].x; pts[1].y = pts[0].y - g_1mu / 2; pts[1].z = pts[0].z; pts[2].x = pts[1].x + g_1mu / 2; pts[2].y = pts[1].y; pts[2].z = pts[0].z; pts[3].x = pts[2].x; pts[3].y = pts[2].y - g_1mu / 2; pts[3].z = pts[0].z; pts[4].x = pts[3].x + g_1mu / 2; pts[4].y = pts[3].y; pts[4].z = pts[0].z; pts[5].x = pts[4].x; pts[5].y = pts[0].y; pts[5].z = pts[0].z; CurveVectorPtr pCurveVec = CurveVector::CreateLinear(pts, 6, CurveVector::BOUNDARY_TYPE_Outer); DVec3d extrusionVec = DVec3d::From(0, 0, g_1mu); DgnExtrusionDetail data(pCurveVec, extrusionVec, true); ISolidPrimitivePtr pSolid = ISolidPrimitive::CreateDgnExtrusion(data); EditElementHandle eeh; DraftingElementSchema::ToElement(eeh, *pSolid, nullptr, *ACTIVEMODEL); eeh.AddToModel(); } void createABsplineSurface(WCharCP unparsed) { MSBsplineSurface bsSurface; MSBsplineCurve bsCurves[4]; DPoint3d basePt, arcPts[4][3]; basePt.x = 5.4*g_1mu; basePt.y = -2.3*g_1mu; basePt.z = -1.8*g_1mu; arcPts[0][0] = arcPts[0][1] = arcPts[0][2] = basePt; DPoint3d center[4]; RotMatrix rMatrix[4]; double radius = g_1mu / 2; center[0] = center[1] = center[2] = center[3] = basePt; center[0].x += radius; center[1].x += g_1mu; center[1].y += radius; center[2].x += radius; center[2].y += g_1mu; center[3].y += radius; DVec3d xVec = DVec3d::From(1, 0, 0), negativeXVec = DVec3d::From(-1, 0, 0); DVec3d yVec = DVec3d::From(0, 1, 0), negativeYVec = DVec3d::From(0, -1, 0); DVec3d zVec = DVec3d::From(0, 0, 1); rMatrix[0].InitFrom2Vectors(xVec, zVec); //Front View rMatrix[1].InitFrom2Vectors(yVec, zVec); //Right View rMatrix[2].InitFrom2Vectors(negativeXVec, zVec); //Back View rMatrix[3].InitFrom2Vectors(negativeYVec, zVec); //Left View EditElementHandle eeh; for (int i = 0; i<4; i++) { bsCurves[i].InitEllipticArc(center[i], radius, radius, 0, PI, &rMatrix[i]); } if (SUCCESS == mdlBspline_coonsPatch(&bsSurface, bsCurves)) { DraftingElementSchema::ToElement(eeh, bsSurface, nullptr, *ACTIVEMODEL); eeh.AddToModel(); mdlBspline_freeSurface(&bsSurface); } for (int i = 0; i<4; i++) mdlBspline_freeCurve(&bsCurves[i]); } MdlCommandNumber cmdNums[] = { { (CmdHandler)createALine, CMD_HELLOWORLD_CREATE_LINE }, { (CmdHandler)createAComplexShape, CMD_HELLOWORLD_CREATE_COMPLEXSHAPE }, { (CmdHandler)createAProjectedSolid,CMD_HELLOWORLD_CREATE_PROJECTEDSOLID }, { (CmdHandler)createABsplineSurface, CMD_HELLOWORLD_CREATE_BSPLINESURFACE }, 0 }; extern "C" DLLEXPORT void MdlMain(int argc, WCharCP argv[]) { ModelInfoCP pInfo = ACTIVEMODEL->GetModelInfoCP(); g_1mu = pInfo->GetUorPerStorage(); RscFileHandle rscFileH; mdlResource_openFile(&rscFileH, NULL, RSC_READONLY); mdlParse_loadCommandTable(NULL); mdlSystem_registerCommandNumbers(cmdNums); }
4. Return to the command prompt of MicroStation CONNECT Edition SDK and type bmake to generate the project. In the process of generating the project, if any yellow or red prompt message appears, it indicates that there are warnings or errors, which need to be eliminated before the executable ma and dll can be finally generated.
Note: Before executing bmake, you must type mdl unload helloworld into the MicroStation software to unload the loaded application, otherwise an error message will appear during bmake that cannot overwrite the original DLL.
5. Go back to MicroStation and open the Key-in dialog. Type MDL LOAD HelloWorld to load the application. After entering HelloWorld again, you will see the command typing tree shown in the following figure, which corresponds exactly to what we defined in HelloWorldCmd.r. Enter one of these commands and press Enter to draw the corresponding part of the graph.
Prev:[[Creating elements in MDL applications]] | Next:[[Creating a VS project and debugging the application]] |