Adding Files/Links To Projects

  • Thread starter Thread starter Jeff Gaines
  • Start date Start date
J

Jeff Gaines

I am a hobbyist programmer, using C# and VS2008 and writing desktop apps.

I am trying hard to take a modular approach to avoid re-inventing the
wheel but I'm finding it a bit frustrating. For instance I have a
ListViewEx class (based on a ListView) which has in-place editing and a
sorter based on column content. It uses custom column headers and custom
ListViewItems. In turn the ListViewEx may have a further class base on it
and so on.

It really came home to me when I set up a test app this afternoon to try
and build a new class, I ended up adding links to about 30 files just to
run a test.

I appreciate that I could compile them into a class library but each time
they are used I come across another property/function that I need and it
is much easier to change the source from a project and re-compile than to
have to open and re-compile half a dozen class libraries.

The thought of doing this for a living where there may be links to
hundreds rather that dozens of files is horrifying.

What do other people do about this? I was very disappointed not to find a
#include directive in C#. Is there a way I can structure things so that I
can link to all files in a directory for instance, rather than to each
individual file in the directory?

I would appreciate any thoughts.
 
Jeff Gaines said:
I appreciate that I could compile them into a class library but each time
they are used I come across another property/function that I need and it
is much easier to change the source from a project and re-compile than to
have to open and re-compile half a dozen class libraries.

You need to think about organization of your modules before you write them.
An ad-hoc approach where you just slap the class where it's easier (for
now), and assembly partitions are arbitrary, doesn't scale.

Also, why "open and re-compile"? Create a multi-project solution, set up
dependencies between projects within it (make sure you're adding _project_
dependencies, not _file_ dependencies - the latter is when you just pick the
..dll in Browse), and just kick off builds with Ctrl+Shift+B. Visual Studio
(or, more precisely, MSBuild) will take care of dependency resolution, and
will rebuild only the stuff that needs rebuilding.
What do other people do about this? I was very disappointed not to find a
#include directive in C#.

This is the first time I've actually seen someone nostalgic for #include.
Given that people are pushing to phase it out in C++ now (hopefully by the
next TR after C++0x), it's a strange sentiment.

Anyway, you don't need #include in C#, because it doesn't have the concept
of headers.
Is there a way I can structure things so that I can link to all files in a
directory for instance, rather than to each individual file in the
directory?

No, but why not just make an assembly out of all those files in a directory,
and then link to that?
 
You need to think about organization of your modules before you write
them. An ad-hoc approach where you just slap the class where it's easier
(for now), and assembly partitions are arbitrary, doesn't scale.

Each class/control sits in its own directory and uses my standardised
directory/namespace/class naming for consistency.

Also, why "open and re-compile"? Create a multi-project solution, set up
dependencies between projects within it (make sure you're adding project
dependencies, not file dependencies - the latter is when you just pick the
.dll in Browse), and just kick off builds with Ctrl+Shift+B. Visual Studio
(or, more precisely, MSBuild) will take care of dependency resolution, and
will rebuild only the stuff that needs rebuilding.

That could work, each class has its own project so I would just need to
add those projects to the new project, and ensure the dependencies are
clear. I will look at that.

This is the first time I've actually seen someone nostalgic for #include.
Given that people are pushing to phase it out in C++ now (hopefully by the
next TR after C++0x), it's a strange sentiment.

Anyway, you don't need #include in C#, because it doesn't have the concept
of headers.

I was thinking more of a 21st century #include pragma. If I have, say, a
ListViewEx class with a dozen or so related classes it would be good to
#include those classes in the main class file. Then it would only be
necessary to link to the main class file when using it in another project.

No, but why not just make an assembly out of all those files in a
directory, and then link to that?

I could add a reference to the class file dll but would then probably need
one instance of VS running for each class project to alter/update on the
hoof so to speak. Probably adding the original projects is easier.

Thanks for the input :-)
 
Jeff Gaines said:
Each class/control sits in its own directory and uses my standardised
directory/namespace/class naming for consistency. ....
That could work, each class has its own project so I would just need to
add those projects to the new project, and ensure the dependencies are
clear. I will look at that.

Note that you can have a single assembly (i.e., project) with multiple
classes, where each class is still in a separate folder (under that project
folder). There's nothing wrong with that, especially if the classes are
logically related and have lots of dependencies between them.
I was thinking more of a 21st century #include pragma. If I have, say, a
ListViewEx class with a dozen or so related classes it would be good to
#include those classes in the main class file. Then it would only be
necessary to link to the main class file when using it in another project.

..NET doesn't define dependencies in terms of classes, but rather in terms of
assemblies. For assemblies, you can do pretty much what you described, so
long as your dependencies are not exposed in public members of your class.
In other words, if you have class A in project/assembly PA depend on class B
in assembly PB, which in turn depends on class C in assembly PC, then you
only need a reference to PB in PA, not to PC. You'll need a reference to PC
only if class B extends class C, or if you use a public member of B that
references C in its signature.
I could add a reference to the class file dll but would then probably need
one instance of VS running for each class project to alter/update on the
hoof so to speak. Probably adding the original projects is easier.

Once again, you do not need an instance of VS per project. You can have a
single solution with as many projects as you wish, and you only need one
instance of VS to work with that solution, and it will be entirely displayed
in Solution Explorer with all the child projects.
 
.NET doesn't define dependencies in terms of classes, but rather in terms
of assemblies. For assemblies, you can do pretty much what you described,
so long as your dependencies are not exposed in public members of your
class. In other words, if you have class A in project/assembly PA depend
on class B in assembly PB, which in turn depends on class C in assembly
PC, then you only need a reference to PB in PA, not to PC. You'll need a
reference to PC only if class B extends class C, or if you use a public
member of B that references C in its signature.

Thank you - I have just set up a new project with several projects within
it and that works nicely :-)
Once again, you do not need an instance of VS per project. You can have a
single solution with as many projects as you wish, and you only need one
instance of VS to work with that solution, and it will be entirely
displayed in Solution Explorer with all the child projects.

Yes, I will need to get used to it but it achieves what I want, thank you
again :-)

A supplementary question...

I am running XP Pro x64 but usually compile for x86 as many of the
database drivers are x86 only.

What about a strategy similar to the above that would enable me to switch
between x86 and x64? Each included project can be switched between x86 and
x64 but the 'main' project needs a reference to the class file (dll) that
the included project produces, which are different for x86/x64. Is it
possible to have a means whereby a project can easily be switched back and
forth or is it better to just have an x86 project and an x64 project?

I like compiling and testing for x64 because it is totally unforgiving,
careless use of an 'int' instead of 'uint' and there are pieces of
computer everywhere - so it is a good discipline for me!
 
Jeff Gaines said:
What about a strategy similar to the above that would enable me to switch
between x86 and x64? Each included project can be switched between x86 and
x64 but the 'main' project needs a reference to the class file (dll) that
the included project produces, which are different for x86/x64. Is it
possible to have a means whereby a project can easily be switched back and
forth or is it better to just have an x86 project and an x64 project?

I like compiling and testing for x64 because it is totally unforgiving,
careless use of an 'int' instead of 'uint' and there are pieces of
computer everywhere - so it is a good discipline for me!

If you're using C#, then you should not see any difference whatsoever
between x86 and x64 in managed code. Given that sizeof(int)==sizeof(uint)==4
regardless of the platform, I don't understand what you mean by "careless
use of 'int' instead of 'uint'".

Furthermore, your assemblies shouldn't even be x86- or x64-specific - the
default target platform for a C# project created in VS is "Any", which is
precisely what it says - it will happily run on either OS, and will be
JIT-compiled to native code for the corresponding architecture.

The only case when a .NET assembly is platform specific is when it uses
P/Invoke or COM interop to call into a native DLL/component, and that
component is only available for a specific platform. For example, when you
call user32.dll via P/Invoke, your assembly is still fine, because on 32-bit
OS it will load 32-bit user32.dll, and on 64-bit OS it will load 64-bit
user32.dll. But if you P/Invoke into some custom .dll, which you
redistribute with your application, and which is 32-bit only, then, when
your assembly is loaded and executed on 64-bit OS using 64-bit version of
..NET, it will crash when it'll try to invoke that 32-bit DLL - and that's
when you set the target platform for your assembly to "x86", so that even on
64-bit, it gets JIT-compiled to 32-bit code and run via WoW64.
 
The only case when a .NET assembly is platform specific is when it uses
P/Invoke or COM interop to call into a native DLL/component, and that
component is only available for a specific platform. For example, when you
call user32.dll via P/Invoke, your assembly is still fine, because on
32-bit OS it will load 32-bit user32.dll, and on 64-bit OS it will load
64-bit user32.dll. But if you P/Invoke into some custom .dll, which you
redistribute with your application, and which is 32-bit only, then, when
your assembly is loaded and executed on 64-bit OS using 64-bit version of
.NET, it will crash when it'll try to invoke that 32-bit DLL - and that's
when you set the target platform for your assembly to "x86", so that even
on 64-bit, it gets JIT-compiled to 32-bit code and run via WoW64.

OK, pretty well all of my apps use P/Invoke and COM as there is limited
support in NET for what I want to do (e.g. masked system icons in
TreeViews, showing the Explorer context menu etc.). I have found that many
calls which work in x86 fail (sometimes spectacularly) when compiled for
x64. After correcting them (and often it is uint for int) they work fine
in both. So x64 acts as a check that I am getting my prototypes right. It
just seems that somehow x64 is less forgiving than x86.

I will continue to experiment and try to find something that doesn't use
databases so I can allow it to run as x64.
 
OK, pretty well all of my apps use P/Invoke and COM as there is limited
support in NET for what I want to do (e.g. masked system icons in
TreeViews, showing the Explorer context menu etc.). I have found that many
calls which work in x86 fail (sometimes spectacularly) when compiled for
x64

The calls are the same no matter how you compile. What fails is that
your 64-bit process is trying to load a 32-bit DLL. It's actually not
even a .NET limitation, but a general Win32 one.
After correcting them (and often it is uint for int) they work fine
in both.

Yet again, I cannot imagine any interop scenario where replacing uint
for int would fix an x86/x64 incompatibility problem. In fact, if you
end up directly calling 32-bit code from 64-bit code, there's
absolutely nothing you can do in prototypes or elsewhere to make it
work. The OS will make sure that it won't.

Do you perhaps mean that you accidentally use int/uint where you
should have used IntPtr/UIntPtr? This sort of thing would indeed
result in your code working against 32-bit DLLs, but failing against
64-bit.
So x64 acts as a check that I am getting my prototypes right. It
just seems that somehow x64 is less forgiving than x86.

To reiterate: there are absolutely no differences in your C#
prototypes on x86 and on x64. Mainly because the relations between
types are always strictly defined (i.e., int is always 4 bytes, long
is always 8, IntPtr varies at runtime depending on platform, but you
will never get, say, an implicit conversion between int and IntPtr,
even if you compile on x86 - unlike C++ std::size_t).
 
Do you perhaps mean that you accidentally use int/uint where you
should have used IntPtr/UIntPtr? This sort of thing would indeed
result in your code working against 32-bit DLLs, but failing against
64-bit.

That as well! The other one is using ANSI strings rather than wide
strings, works fine under x86 but falls apart under x64.
I can't really analyse it in detail because if it fails I go right back to
basics and update the prototype completely. It's the greatest of pities
that MSFT didn't include namespaces for all their dll's (or at least put
prototypes in the help file) but then VS is not really s desktop
development environment if you want to do any serious work. I like C# and
I like the VS IDE otherwise I suspect Delphi is much more suited to what I
do. If somebody produced an IDE as good as VS that worked in pure 'C' I'd
be off like a shot!
 
Jeff Gaines said:
That as well! The other one is using ANSI strings rather than wide
strings, works fine under x86 but falls apart under x64.

If you mean CharSet.Ansi vs CharSet.Unicode (or MarshalAs(UnmanagedType)),
then it shouldn't, either. If you mean something else, then I'm curious what
it is.
I can't really analyse it in detail because if it fails I go right back to
basics and update the prototype completely. It's the greatest of pities
that MSFT didn't include namespaces for all their dll's (or at least put
prototypes in the help file)

You should have a look at the P/Invoke Interop Assistant:
http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=clrinterop&ReleaseId=14120
but then VS is not really s desktop development environment if you want to
do any serious work.

This is a rather strange statement. Lots of desktop applications are
developed using VS and C#; what, in your opinion, is mising to make it a
"desktop development environment"?
I like C# and I like the VS IDE otherwise I suspect Delphi is much more
suited to what I do

I admit I didn't have a lot of experience with Delphi back in the day, but
from what I've seen, C#+WinForms is really very similar to Delphi+VCL, if
you disregard the curly-braces C'ish syntax. No surprises there, either -
remember that both Delphi the language and C# the language were designed by
the same person.
If somebody produced an IDE as good as VS that worked in pure 'C' I'd be
off like a shot!

VS is actually a very good C/C++ IDE, when you need that sort of thing.
Possibly even the best out there - at least I don't know any other product
that can match its visual debugging facilities for C++.
 
If you mean CharSet.Ansi vs CharSet.Unicode (or MarshalAs(UnmanagedType)),
then it shouldn't, either. If you mean something else, then I'm curious
what it is.

I have just picked one up. In my HDITEM structure I had pszText as a
string and it worked fine under x86 but failed under x64. I have added
[MarshalAs(UnmanagedType.LPWStr)] and it now works fine under both.
Another was using HDM_SETITEMA which works under x86 but not x64, changing
it to HDM_SETITEMW works under both. A lot of these definitions will have
been carried forward from VB6 days and I only change them if/when they fail.

I do use that but as long as it's people like me putting the definitions
up there some will be wrong! We really could do with MSFT releasing
standard prototypes, I am sure I had a file of them once from MSFT, I'll
have to try and find it.
This is a rather strange statement. Lots of desktop applications are
developed using VS and C#; what, in your opinion, is mising to make it a
"desktop development environment"?

Access to the dll's, Interfaces, structures etc. It's like VB6 leaving you
to prototype them yourself. At least a couple have crept in recently in
System.Runtime.InteropServices.ComTypes but where is IContextMenu (and 2 &
3) and the most common one for me IShellFolder? And, of course, #include :-)
 
Jeff Gaines said:
I have just picked one up. In my HDITEM structure I had pszText as a
string and it worked fine under x86 but failed under x64. I have added
[MarshalAs(UnmanagedType.LPWStr)] and it now works fine under both.
Another was using HDM_SETITEMA which works under x86 but not x64, changing
it to HDM_SETITEMW works under both. A lot of these definitions will have
been carried forward from VB6 days and I only change them if/when they
fail.

I wonder... could it be that x86 Win32 API DLLs only offer Unicode entry
points, and not ANSI ones? I can't really think of any reason why it might
work differently...
I do use that but as long as it's people like me putting the definitions
up there some will be wrong! We really could do with MSFT releasing
standard prototypes, I am sure I had a file of them once from MSFT, I'll
have to try and find it.

Unfortunately there's no such thing... I've raised this issue with MSFT
before, and apparently they are not interested with providing "official"
P/Invoke definitions for Win32 API, with .NET or separately.
Access to the dll's, Interfaces, structures etc.

You mean unmanaged DLLs? A lot of desktop apps don't need that sort of thing
at all - ideally, when you write an app in C#, you just use the managed
assemblies, and don't have all that headache. Of course, we aren't quite
there yet, but even so, there aren't that many scenarios where P/Invoke or
COM interop is really needed in a .NET app today.

Keep in mind that as far as Microsoft is concerned, COM is a legacy binary
interface.
 
You mean unmanaged DLLs? A lot of desktop apps don't need that sort of
thing at all - ideally, when you write an app in C#, you just use the
managed assemblies, and don't have all that headache. Of course, we aren't
quite there yet, but even so, there aren't that many scenarios where
P/Invoke or COM interop is really needed in a .NET app today.

I guess it depends what you write. Much of my stuff revolves around File
Management and I want masked system icons, the Explorer context menu etc.
Keep in mind that as far as Microsoft is concerned, COM is a legacy binary
interface.

Indeed, but where's the replacement...
 
Jeff Gaines said:
I guess it depends what you write. Much of my stuff revolves around File
Management and I want masked system icons, the Explorer context menu etc.

Ah yes, the Shell APIs - one of the COM strongholds in the Win32 land :)
Indeed, but where's the replacement...

Well, .NET supposedly is, it's just that functionality from a lot of system
APIs isn't covered (yet?). Though remember the promises, a few years ago,
that Longhorn/Vista was going to be .NET-based throughout, with .NET APIs as
native ones, and all the unmanaged APIs as wrappers around the former. I
wonder if that sort of thing is still in plans for some future Windows
version...
 
Back
Top