Introduction
This tip is not for NMAKE experts.
Background
At
start we have our project cool_addon.dll that is intended for use with a non-debugable
host. In practice such are most add-ons for known big applications
like AutoCAD or IE. Here is an abstract sample of how to debug such an add-on with
minimal recanting from a common developing process. As a base we use an ubiquitous Hello
World from PSDK. This sample
is live but uses a wide protocol that does not want to work on my single local machine. But MSDN has notes about the same project with
a pipe oriented
connection. It is a fish to consolidate them, all working as described. This NMAKE project has
the main structure of our debug solution. Only things missing are compatible wrappers on both ends. Thus
we begin.
Using the code
I use VS9
so all comments are about this environment.
First
create a separate solution, and at once create a BlackBox - host simulator. It used
to study developing this system. BlackBox must load cool_addon.dll and make its testing calls. Place
a reference to the compiled release at a convenient place like Service->External
tools or near shortcut.
Next
create an optional empty project rpc_core_dbg.
To avoid compile errors set it as the tool project or .lib maybe. This project only launches MIDL,
the purpose is not binary, RPC code only. Add a renamed copy of
.idl
and .acf from 'Hello world'. In my
case VS does not understand the .acf format and
I excluded it from compiling. It is reached with MIDL settings. Changing
interface the name, uuid and implicit_handle name are not required, as you wish.
The content of the interface can be fully cleared except the Shutdown
function. It will be used for debugging the control. Now to the body of the interface
declaration add declarations of
functions listed in your .def, suffix/prefix and attribute them as demand RPC.
Rename functions needed to be distinguish RCP from target to bind. Here it
is all pithiness of the content of this project - create RPC transport code with
compatible
interface. To generate the common way, in project settings change the MIDL
output header to rpc_core_dbg.h and
output the path to $(SolutionDir) for
simply reaching current result - rpc_core_dbg.h, rpc_core_dbg_c.c,
rpc_core_dbg_s.c
in the relative projects. Where the .c generated transport code is for
implementation on the appropriate end. rpc_core_dbg.h is
solely for this transport. Extend MIDL command line with
/acf rpc_core_dbg.acf /client stub /server stub /rpcss /target NT51
This
switches subjects for experiment, as do other MIDL settings. Performing
the compilation of this project real only generates code, no binary executable. So
it must be excluded from any configuration, because _.c files still need
correction and surplus regeneration will harm its full ready view. Other
settings has no effect on this task. I clear them.
The host
simulator is on, now the client stub. Add to
solution new DLL project face_addon that
fully repeated main cool_addon with
settings and dll interface. Best way is using the same .def directly from
source project and other shared files from solution top, so set additional
include directoryes to $(SolutionDir).
Add to this project rpc_core_dbg.h
rpc_core_dbg_c.c . Set output binary name as original cool_addon.dll. Generally it is wrapper to rpc
calls with interface of original cool_addon.dll.
Changes about rpc for dllmain are borrowed from Hello project. Preparing and
finalising of rpc calls united to singles at begin and to unloading library
respectively. Clear prc is not wait apperance of target. It return error and
client continues self wait in this situation. Simplest compilation will rise
C1853 - C++c disaccord on rpc_core_dbg_c.c .
It require separate .pch. Setting for precompiled header of this file: Create
new nonStdAfx.h, named other.pch. But compiler again rises C1189 - version
wrong, MIDL defines it for self only.
Well, strictly define required version:
#ifdef TARGET_IS_NT51_OR_LATER
#undef TARGET_IS_NT51_OR_LATER
#endif
#define _TARGET_IS_NT51_OR_LATER 1
Anywhere inside nonStdAfx.h, I place it to shared targetver.h near others. Linker
must have Rpcrt4.lib reference. Write it to project settings or like #pragma comment(lib, "Rpcrt4.lib") i place to StdAfx.h. Regenerated by MIDL rpc_core_dbg_c.c not conatains required reference to its
precompiled header #include
"nonStdAfx.h". I am
add this stroke handly each time. That is "payment") lazy write corrector).
Last step
- server stub and back wrapper. Create executable Debugee project, not
principal console or window. Anywhere call RPC server implementation. RPC
server never leaved listen mode and is invisible/nonobstacle for debugging. So
calm debugee seems like deadlock. RPC activity occurs direct in interface
implementation where we place target call. Any requirements are the same as for
client. Exept rpc_core_dbg_s.c using,
note - _s postfix. Rename in cool_addon project settings binary output as
dbg_addon.dll and use it in Debugee. Renaming output required another .def for
this name. Or point output of Debugee and cool_addon to another folder. Maybe
you prefer superpose original code in one project as .exe when debug and target
.dll on release. This allow skip wrappers on server side but obtain naming
conflicts that of course can solved witn #if. In conjunction with separating
output such config seems more beauty. But i gather worst variant here). Here
very many words, graph inside attached zip can help to sort dependencies.
Points of Interest
Test.
What you launch first doesn't matter. Set breakpoints in the cool_addon project,
input any stroke in the host simulator. Debug.
Preparing
exchanges is separate theme. Interesting point - interface function: double ArrayStringMess_dbg([in,out, size_is( 3 ), string]char**pp);
generates a MIDL2291 warning, but code still truly work in both directions.
Sorry for
bad English. Good luck!