Windows 7 - Mobile 5 - Debugging Managed C#/Unmanaged C++ Code

Asked By john.e.otte on 04-Mar-08 08:20 PM
Hi,

We are working on an application that is targeting a PDA that runs
Windows Mobile 5.0.  Our development environment is Visual Studio 2005
with the appropriate plugins.

Currently, the GUI is being built with C# managed code using the VS
2005 GUI builder.  The main processing of the code is planned to be
contained in a static DLL written with unmanaged C++.  We will use
PInvoke calls to access data in the DLL for display/interaction on the
GUI.  We decided upon this as it does not appear that we can use
managed C++ in the Windows Mobile 5 platform, and the only way to use C
++ for the GUI in the Mobile environment is to use the Windows API
calls (which means development would take longer, and perhaps be less
robust).

I wrote some simple functions on the C++ side to verify that the
concept would work with the current version of the GUI, and it did.
However, now that we are trying to do full up development we realize
that we will need to use the debugger on the unmanaged C++ side.

I poked around on the internet and found some references that state
you should set your debugging state to "Both" in the C++ unmanaged
project so that debugging would work with both managed and unmanaged
code.  However, that option does not appear in our DLL project -
instead only "Smart Device Native Debugger" appears as a choice.
Also, the MSDN pages discuss an option in the C# project settings
under the debug tab that allows you to "Enable unmanaged code
debugging."  That checkbox does not appear in our C# project either.

My concern is that such settings (like some others) do not exist in
the Windows Mobile paradigm.  If they do exist, how can I access
them?  If they do not exist, does anyone have any suggestions on how
to proceed?

We do not have any experience programming in C# (hence the desire for
a C++ unmanaged DLL) and although we would like to learn, we do have
to keep our project deadline in mind. If it is the most expedient way
to do it, we can possibly bite the bullet (but I'll have to find some
way to appease the project manager for the additional time it may
take).

My only other thought is (assuming that the settings do not exist in
the Mobile environment) that we attempt to do the managed/unmanaged
development outside of the Mobile environment and then port it to
Windows Mobile 5 after it is completed.  This is not a very attractive
solution either. Has anyone done anything similar to this?

Any comments or suggestions would be greatly appreciated!

Thanks,
John




Paul G. Tobey [eMVP] replied on 03-Mar-08 12:12 PM
No, you can't step from managed code through a P/Invoke call into native
code in the Smart Device debugger.  You might be able to use Attach to
Process to do the native debugging (with the native DLL project loaded into
that instance of VS2005), or simply write debug information from the native
DLL to a serial port or something.  This really doesn't come up very often,
though, where you actually *need* to step from one to the other.

Paul T.
john.e.otte replied on 04-Mar-08 08:20 PM
Paul,
Thanks for your reply.

I did look into Attach to Process to access the DLL code during
debugging. However, the threads that I spawned in the DLL do not
appear in the Thread list on the IDE, so I don't know how I can get a
handle into the code in the DLL.  Setting breakpoints in the DLL code
does not work - the IDE states that because the DLL symbols are not
loaded it can't set a breakpoint (I am using a debug version of the
DLL, but perhaps because of the nature of the managed/unmanaged code
it can't tell that the DLL is actually loaded?).

We are less concerned with stepping from the managed to the unmanaged
code than we are being able to step through the unmanaged code
itself.  Most of the heavy duty processing will be performed in the
unmanaged code, so we just want to be sure we can get into it during
debugging.

Any other thoughts?

John

On Mar 3, 12:12=A0pm, "Paul G. Tobey [eMVP]" <p space tobey no spam AT
o
e
en,
Paul G. Tobey [eMVP] replied on 03-Mar-08 01:28 PM
Do you have the DLL project loaded when you do this?  You could drop a
DebugBreak() call in your DLL and see if that will trigger the debugger.

The easiest thing is to debug native code from a native code user and then
you have tested code against which you don't have to debug much; all bugs,
at that point, should be in the real, managed user of the DLL.

Paul T.

Paul,
Thanks for your reply.

I did look into Attach to Process to access the DLL code during
debugging. However, the threads that I spawned in the DLL do not
appear in the Thread list on the IDE, so I don't know how I can get a
handle into the code in the DLL.  Setting breakpoints in the DLL code
does not work - the IDE states that because the DLL symbols are not
loaded it can't set a breakpoint (I am using a debug version of the
DLL, but perhaps because of the nature of the managed/unmanaged code
it can't tell that the DLL is actually loaded?).

We are less concerned with stepping from the managed to the unmanaged
code than we are being able to step through the unmanaged code
itself.  Most of the heavy duty processing will be performed in the
unmanaged code, so we just want to be sure we can get into it during
debugging.

Any other thoughts?

John

On Mar 3, 12:12 pm, "Paul G. Tobey [eMVP]" <p space tobey no spam AT
Paul G. Tobey [eMVP] replied on 03-Mar-08 02:10 PM
A quick test shows that the easiest way to handle this is to 'run' your DLL.
That is, set the debugging options to start the managed code EXE that will
use your DLL and set your breakpoints in the DLL (all from the DLL project,
of course).  Naturally, when the EXE starts, your DLL won't be loaded, so
you'll see the breakpoints as hollow circles with ! on them, but, when you
call any of the native functions in your DLL, the DLL will be loaded (it's
not loaded on startup), and the breakpoints will be set.  Works fine for me,
anyway.

Paul T.
john.e.otte replied on 04-Mar-08 08:20 PM
Paul,

I tried your suggestion, and it worked.  Thank you very much for your
help!

Regards,
John

L.

,
o


me,



en
s,

e


e
C
You can go one further too.  You can set the startup EXE to be VIsual Studio
itself, then load up your managed project there and it gives you the ability
to (alomost) step from managed to native by setting breakpoints at the entry
of your native DLL.  A step in the managed instance in Studio across the
P/Invoke call then transfers to the native instance of Studio.  That's the
best I've been able to achieve (and it's slow since you have to fire up
studio every time you hit Run).


--

Chris Tacke, eMVP
Join the Embedded Developer Community
http://community.opennetcf.com
john.e.otte replied on 04-Mar-08 08:20 PM
Thanks Chris,

We might give your suggestion a try, although I don't forsee us being
too concerned with the actual transition from the managed to the
native code.

However (and I am not getting greedy, I think the suggestions given so
far will get us where we need to go :-),  I noticed that I am not able
to examine the values of the array I passed into the native code (as
an int *) while I am stepping through the native code.  Any ideas as
to why this is?  I tried casting the array pointer within the watch
list, but the debugger seems to be treating the pointer as an int
variable.  The code works properly, and I am able to see the values of
the array defined in the native code (the function I am using as a
test just copies the values of the native array to the managed array).
I am curious, because memory is memory, and casting the type should
make it possible to see the values as the memory is cast (that's what
I believe, anyway).  Does the managed code "do something" to the
memory to make it type specific or something?  I will admit that I am
new to this P/Invoke issue, and have not studied it at length...

Thanks again, Paul and Chris!

John

udio
ty
ry

he

t

be
OT
a
.
ll
.

ve

.
5
he
e
s


r

y
e

e
Paul G. Tobey [eMVP] replied on 03-Mar-08 03:26 PM
Show the declaration of the native code function and how you're calling it
from managed code.

Paul T.

Thanks Chris,

We might give your suggestion a try, although I don't forsee us being
too concerned with the actual transition from the managed to the
native code.

However (and I am not getting greedy, I think the suggestions given so
far will get us where we need to go :-),  I noticed that I am not able
to examine the values of the array I passed into the native code (as
an int *) while I am stepping through the native code.  Any ideas as
to why this is?  I tried casting the array pointer within the watch
list, but the debugger seems to be treating the pointer as an int
variable.  The code works properly, and I am able to see the values of
the array defined in the native code (the function I am using as a
test just copies the values of the native array to the managed array).
I am curious, because memory is memory, and casting the type should
make it possible to see the values as the memory is cast (that's what
I believe, anyway).  Does the managed code "do something" to the
memory to make it type specific or something?  I will admit that I am
new to this P/Invoke issue, and have not studied it at length...

Thanks again, Paul and Chris!

John
If it comes in as an int*, I *think* (I'd have to fire up a native session
to be sue and I don't really feel like doing that right now) that what
you'll get in the immediate window would be the variable name and the
address it points to.  Since it's a pointer type it should have a plus by it
that you can expand and see the value of the first int in the array.  That
is probably all it's going to give you.

That said, you can still get to the other value with a Memory or Watch
window.  Open a Memory window and give it the address listed for your
pointer.  that gives you the hex values of everything at that point, from
which it's pretty easy to just look at int numbers.

The other option is to use a watch on the index you're after.  So if your
native declaration is int *vals, then you can do a watch on vals[2] and see
the value of the third item in the array.  None of this will tell you how
long that array is, though.  For that you should be passing a second
argument (unless it's fixed length).


--

Chris Tacke, eMVP
Join the Embedded Developer Community
http://community.opennetcf.com


Thanks Chris,

We might give your suggestion a try, although I don't forsee us being
too concerned with the actual transition from the managed to the
native code.

However (and I am not getting greedy, I think the suggestions given so
far will get us where we need to go :-),  I noticed that I am not able
to examine the values of the array I passed into the native code (as
an int *) while I am stepping through the native code.  Any ideas as
to why this is?  I tried casting the array pointer within the watch
list, but the debugger seems to be treating the pointer as an int
variable.  The code works properly, and I am able to see the values of
the array defined in the native code (the function I am using as a
test just copies the values of the native array to the managed array).
I am curious, because memory is memory, and casting the type should
make it possible to see the values as the memory is cast (that's what
I believe, anyway).  Does the managed code "do something" to the
memory to make it type specific or something?  I will admit that I am
new to this P/Invoke issue, and have not studied it at length...

Thanks again, Paul and Chris!

John
john.e.otte replied on 04-Mar-08 08:20 PM
Ok, The call to GetData (with the external declaration) is:

[dllImport("TestDLL.dll")]
public static unsafe extern void GetData(int[] dataArray, int size);

// Declared as a private member variable
int[] yPoints =3D new int[21];

// This is called within a member function that was
// invoked by a delegate function
GetData(yPoints, 21);

The native code function is:

extern "C" __declspec(dllexport) void GetData(int *dataArray, int
size)
{
for (int i =3D 0; i < size; i++)
{
dataArray[i] =3D localData[i];  // localData is initialized in
the DLL
}
}

I can characterize what is happening a bit more...

If I set a breakpoint on the dataArray[i] =3D ... line, when the
execution breaks, size is equal to 21, dataArray is equal to some hex
address, *dataArray is equal to 0, and i is undefined (presumably
because I declared it within the loop definition).  Now, each time as
I continue through the loop, size will decrement by one, dataArray
will change to an address 4 bytes greater, and due to this, *dataArray
will remain at 0.  This continues until size =3D 0 at which time the
loop exits the next time I hit continue.  This is not the behavior I
expected, but at least I can follow what is going on.  By the way,
although I don't explicitly initialize the yPoints array to 0 before
each call, it appears that it is initialized somewhere - the magic of
C# I suppose.

So, Chris is correct in that the pointer type only give the value of
the first int in the array (which hasn't yet been initialized and thus
is 0).  However, I cannot put a watch on dataArray[2] because the
pointer to dataArray changes on each iteration.  At least I can use a
memory window to see the values (as I would hope!)

Anyway, at this point I am happy to be able to do what I can at the
moment.  Later, I'll be annoyed that I can't look at the passed in
array in a straightforward manner :-)  But, if you guys have any
comments on why I see the described behavior, I would be very
interested in them. I suppose the reason might become important as my
project gets further along.

Thanks again for your help!
John


On Mar 3, 3:26=A0pm, "Paul G. Tobey [eMVP]" <p space tobey no spam AT no
Paul G. Tobey [eMVP] replied on 03-Mar-08 06:18 PM
You're not changing the value of dataArray.  dataArray[i] is changing, of
course.  I didn't realize that we'd lost the ability to tell the Watch
window how big an array was, but obviously we have.

You can use the Memory window to look at the data, of course, too.

Paul T.

Ok, The call to GetData (with the external declaration) is:

[dllImport("TestDLL.dll")]
public static unsafe extern void GetData(int[] dataArray, int size);

// Declared as a private member variable
int[] yPoints = new int[21];

// This is called within a member function that was
// invoked by a delegate function
GetData(yPoints, 21);

The native code function is:

extern "C" __declspec(dllexport) void GetData(int *dataArray, int
size)
{
for (int i = 0; i < size; i++)
{
dataArray[i] = localData[i];  // localData is initialized in
the DLL
}
}

I can characterize what is happening a bit more...

If I set a breakpoint on the dataArray[i] = ... line, when the
execution breaks, size is equal to 21, dataArray is equal to some hex
address, *dataArray is equal to 0, and i is undefined (presumably
because I declared it within the loop definition).  Now, each time as
I continue through the loop, size will decrement by one, dataArray
will change to an address 4 bytes greater, and due to this, *dataArray
will remain at 0.  This continues until size = 0 at which time the
loop exits the next time I hit continue.  This is not the behavior I
expected, but at least I can follow what is going on.  By the way,
although I don't explicitly initialize the yPoints array to 0 before
each call, it appears that it is initialized somewhere - the magic of
C# I suppose.

So, Chris is correct in that the pointer type only give the value of
the first int in the array (which hasn't yet been initialized and thus
is 0).  However, I cannot put a watch on dataArray[2] because the
pointer to dataArray changes on each iteration.  At least I can use a
memory window to see the values (as I would hope!)

Anyway, at this point I am happy to be able to do what I can at the
moment.  Later, I'll be annoyed that I can't look at the passed in
array in a straightforward manner :-)  But, if you guys have any
comments on why I see the described behavior, I would be very
interested in them. I suppose the reason might become important as my
project gets further along.

Thanks again for your help!
John


On Mar 3, 3:26 pm, "Paul G. Tobey [eMVP]" <p space tobey no spam AT no
C# initializes all arrays (probably by calling Array.Initialize, but you'd
have to use Reflector to verify that if you care) after creation, so nicely
it zeros everything out for you.

The behavior you're seeing baffles me - you're saying that dataArray itself
is changing, yough your code isn't and i is undefined?  That sure smells
like optimized code to me - you're sure you're running in Debug not Release
mode and that optimizations are off for Debug?

You might also try something like:

extern "C" __declspec(dllexport) void GetData(int *dataArray, int
size)
{
int *watchvar = dataArray;

for (int i = 0; i < size; i++)
{
dataArray[i] = localData[i];  // localData is initialized in
the DLL
}
}

You can then set a watch on watchvar[2] and you should be good.  If all goes
as planned the compiler will strip it out in a Release build too, so there's
no penalty for it being there, but I'm still betting on the behavior you see
being a result of optimization.


--

Chris Tacke, eMVP
Join the Embedded Developer Community
http://community.opennetcf.com



Ok, The call to GetData (with the external declaration) is:

[dllImport("TestDLL.dll")]
public static unsafe extern void GetData(int[] dataArray, int size);

// Declared as a private member variable
int[] yPoints = new int[21];

// This is called within a member function that was
// invoked by a delegate function
GetData(yPoints, 21);

The native code function is:

extern "C" __declspec(dllexport) void GetData(int *dataArray, int
size)
{
for (int i = 0; i < size; i++)
{
dataArray[i] = localData[i];  // localData is initialized in
the DLL
}
}

I can characterize what is happening a bit more...

If I set a breakpoint on the dataArray[i] = ... line, when the
execution breaks, size is equal to 21, dataArray is equal to some hex
address, *dataArray is equal to 0, and i is undefined (presumably
because I declared it within the loop definition).  Now, each time as
I continue through the loop, size will decrement by one, dataArray
will change to an address 4 bytes greater, and due to this, *dataArray
will remain at 0.  This continues until size = 0 at which time the
loop exits the next time I hit continue.  This is not the behavior I
expected, but at least I can follow what is going on.  By the way,
although I don't explicitly initialize the yPoints array to 0 before
each call, it appears that it is initialized somewhere - the magic of
C# I suppose.

So, Chris is correct in that the pointer type only give the value of
the first int in the array (which hasn't yet been initialized and thus
is 0).  However, I cannot put a watch on dataArray[2] because the
pointer to dataArray changes on each iteration.  At least I can use a
memory window to see the values (as I would hope!)

Anyway, at this point I am happy to be able to do what I can at the
moment.  Later, I'll be annoyed that I can't look at the passed in
array in a straightforward manner :-)  But, if you guys have any
comments on why I see the described behavior, I would be very
interested in them. I suppose the reason might become important as my
project gets further along.

Thanks again for your help!
John


On Mar 3, 3:26 pm, "Paul G. Tobey [eMVP]" <p space tobey no spam AT no
john.e.otte replied on 04-Mar-08 08:20 PM
Chris,
You are correct.  Although the code was compiled in debug mode, the
optimization was set to \O2.  I was pretty sure I had turned off the
optimization, but when I looked at the project again, it was set.  I
recompiled it again with the optimization off and the behavior was
more what one might expect (I could see the value for i, I could
reference values like dataArray[2], the dataArray address did not
change each iteration, etc.).

Chris and Paul - Thanks again for your help!

Regards,
John



y
f

e
zed in
goes
's
ee