OS dependend DllImport

  • Thread starter Ole Christensen
  • Start date
O

Ole Christensen

I'm trying to make a sort of conditional compilation in my C# code because
my app is intended to run on both a Pocket PC and on a normal desktop PC. My
code uses a call to an API function that on the PPC is located in
coredll.dll and on the desktop in kernel32.dll. I could make two versions of
the DllImported funktions but then I would have to ask for the OS version in
every call to the function. This however causes the code to look messy and
it does also make the code a lot slower in case of intensive calls to the
funktion like e.g. reading single bytes from a serial port running at a
speed of 115k. A code like this would be perfect:
#if (System.Environment.OSVersion.Platform == PlatformID.WinCE)
[DllImport("coredll.dll", EntryPoint="ReadFile", SetLastError=true)]
#else
[DllImport("coredll.dll", EntryPoint="ReadFile", SetLastError=true)]
#endif
private static extern bool ReadFile(......

But it is unfortunately not possible because the
"System.Environment.OSVersion.Platform == PlatformID.WinCE" is a not legal
argument to #if in C#. Another similar solution could be:
if (System.Environment.OSVersion.Platform == PlatformID.WinCE)
{
[DllImport("coredll.dll", EntryPoint="ReadFile", SetLastError=true)]
}
else
{
[DllImport("coredll.dll", EntryPoint="ReadFile", SetLastError=true)]
}
private static extern bool ReadFile(......

But this is unfortunately not legal either, because C# doesn't accept that
the dllImport statement is located in a funktion like e.g. form_load.

Does anyone have any idea to do this in a clever way?

Thanks a lot!
Ole
 
O

Ole Christensen

Sorry: The "coredll.dll" must be replaced with "kernel32.dll" in the else
sentences below.
Ole
 
N

Nicholas Paldino [.NET/C# MVP]

Ole,

I would define a flag, POCKET_PC or something like that, and then do the
following:

[DllImport(

// If pocket PC is defined, then compile against coredll.dll.
#if POCKET_PC
"coredll.dll"
#else
"kernel32.dll"
#endif
, EntryPoint="ReadFile", SetLastError=true)]
private static extern bool ReadFile(...

However, this can get pretty messy. I would recommend you do the
definition like this:

[DllImport(Win32DllAlias.Kernel32, EntryPoint="ReadFile",
SetLastError=true)]
public static extern bool ReadFile(...

And then define a dll that has constants in it, exposing the dll name.
Of course, it is there where you place the condition for your constant:

#if POCKET_PC
public const string Kernel32 = "kernel32.dll";
#else
public const string Kernel32 = "coredll.dll";
#endif

This is the cleaner solution, IMO.

Hope this helps.
 
O

Ole Christensen

Hi Nicholas,

Thank you for your promt respons!

Defining a flag would make my code OS dependend. If I didn't have to do the
DllImport I would be able to simply move the exe file from the Pocket PC to
the Desktop PC and run it there instead, but defining a flag would destroy
that possibility.

Thanks,
Ole

Nicholas Paldino said:
Ole,

I would define a flag, POCKET_PC or something like that, and then do the
following:

[DllImport(

// If pocket PC is defined, then compile against coredll.dll.
#if POCKET_PC
"coredll.dll"
#else
"kernel32.dll"
#endif
, EntryPoint="ReadFile", SetLastError=true)]
private static extern bool ReadFile(...

However, this can get pretty messy. I would recommend you do the
definition like this:

[DllImport(Win32DllAlias.Kernel32, EntryPoint="ReadFile",
SetLastError=true)]
public static extern bool ReadFile(...

And then define a dll that has constants in it, exposing the dll name.
Of course, it is there where you place the condition for your constant:

#if POCKET_PC
public const string Kernel32 = "kernel32.dll";
#else
public const string Kernel32 = "coredll.dll";
#endif

This is the cleaner solution, IMO.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Ole Christensen said:
I'm trying to make a sort of conditional compilation in my C# code because
my app is intended to run on both a Pocket PC and on a normal desktop PC.
My
code uses a call to an API function that on the PPC is located in
coredll.dll and on the desktop in kernel32.dll. I could make two versions
of
the DllImported funktions but then I would have to ask for the OS version
in
every call to the function. This however causes the code to look messy and
it does also make the code a lot slower in case of intensive calls to the
funktion like e.g. reading single bytes from a serial port running at a
speed of 115k. A code like this would be perfect:
#if (System.Environment.OSVersion.Platform == PlatformID.WinCE)
[DllImport("coredll.dll", EntryPoint="ReadFile",
SetLastError=true)]
#else
[DllImport("coredll.dll", EntryPoint="ReadFile",
SetLastError=true)]
#endif
private static extern bool ReadFile(......

But it is unfortunately not possible because the
"System.Environment.OSVersion.Platform == PlatformID.WinCE" is a not legal
argument to #if in C#. Another similar solution could be:
if (System.Environment.OSVersion.Platform == PlatformID.WinCE)
{
[DllImport("coredll.dll", EntryPoint="ReadFile", SetLastError=true)]
}
else
{
[DllImport("coredll.dll", EntryPoint="ReadFile",
SetLastError=true)]
}
private static extern bool ReadFile(......

But this is unfortunately not legal either, because C# doesn't accept that
the dllImport statement is located in a funktion like e.g. form_load.

Does anyone have any idea to do this in a clever way?

Thanks a lot!
Ole
 
N

Nicholas Paldino [.NET/C# MVP]

Ole,

Because of what you are doing though, you have no other choice. The
only other option would be to wrap all of your API calls in one separate
assembly, and then have that single assembly be OS dependent.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Ole Christensen said:
Hi Nicholas,

Thank you for your promt respons!

Defining a flag would make my code OS dependend. If I didn't have to do
the
DllImport I would be able to simply move the exe file from the Pocket PC
to
the Desktop PC and run it there instead, but defining a flag would destroy
that possibility.

Thanks,
Ole

in
message news:[email protected]...
Ole,

I would define a flag, POCKET_PC or something like that, and then do the
following:

[DllImport(

// If pocket PC is defined, then compile against coredll.dll.
#if POCKET_PC
"coredll.dll"
#else
"kernel32.dll"
#endif
, EntryPoint="ReadFile", SetLastError=true)]
private static extern bool ReadFile(...

However, this can get pretty messy. I would recommend you do the
definition like this:

[DllImport(Win32DllAlias.Kernel32, EntryPoint="ReadFile",
SetLastError=true)]
public static extern bool ReadFile(...

And then define a dll that has constants in it, exposing the dll
name.
Of course, it is there where you place the condition for your constant:

#if POCKET_PC
public const string Kernel32 = "kernel32.dll";
#else
public const string Kernel32 = "coredll.dll";
#endif

This is the cleaner solution, IMO.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Ole Christensen said:
I'm trying to make a sort of conditional compilation in my C# code because
my app is intended to run on both a Pocket PC and on a normal desktop PC.
My
code uses a call to an API function that on the PPC is located in
coredll.dll and on the desktop in kernel32.dll. I could make two versions
of
the DllImported funktions but then I would have to ask for the OS version
in
every call to the function. This however causes the code to look messy and
it does also make the code a lot slower in case of intensive calls to the
funktion like e.g. reading single bytes from a serial port running at a
speed of 115k. A code like this would be perfect:
#if (System.Environment.OSVersion.Platform == PlatformID.WinCE)
[DllImport("coredll.dll", EntryPoint="ReadFile",
SetLastError=true)]
#else
[DllImport("coredll.dll", EntryPoint="ReadFile",
SetLastError=true)]
#endif
private static extern bool ReadFile(......

But it is unfortunately not possible because the
"System.Environment.OSVersion.Platform == PlatformID.WinCE" is a not legal
argument to #if in C#. Another similar solution could be:
if (System.Environment.OSVersion.Platform == PlatformID.WinCE)
{
[DllImport("coredll.dll", EntryPoint="ReadFile", SetLastError=true)]
}
else
{
[DllImport("coredll.dll", EntryPoint="ReadFile",
SetLastError=true)]
}
private static extern bool ReadFile(......

But this is unfortunately not legal either, because C# doesn't accept that
the dllImport statement is located in a funktion like e.g. form_load.

Does anyone have any idea to do this in a clever way?

Thanks a lot!
Ole
 
M

Mattias Sjögren

Ole,
I could make two versions of
the DllImported funktions but then I would have to ask for the OS version in
every call to the function.

Certainly not, one time is enough. all you have to do is wrap the
functionality in two system dependent classes that share a common
interface and let polymorphism do its magic.

Consider this

interface IMyApis {
bool ReadFile(...);
}

sealed class DesktopApis : IMyApis {
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool ReadFile(...);

bool IMyApis.ReadFile(...) { return ReadFile(...); }
}

sealed class PocketPCApis : IMyApis {
[DllImport("coredll.dll", SetLastError=true)]
private static extern bool ReadFile(...);

bool IMyApis.ReadFile(...) { return ReadFile(...); }
}


IMyApis api = Environment.OSVersion.Platform == PlatformID.WinCE ?
new PocketPCApis() : new DesktopApis();
api.ReadFile(...);



Mattias
 
O

Ole Christensen

Thanks Mattias

It looks like it's something worth trying out so I'll do - Thanks a lot!

Ole

Mattias Sjögren said:
Ole,
I could make two versions of
the DllImported funktions but then I would have to ask for the OS version in
every call to the function.

Certainly not, one time is enough. all you have to do is wrap the
functionality in two system dependent classes that share a common
interface and let polymorphism do its magic.

Consider this

interface IMyApis {
bool ReadFile(...);
}

sealed class DesktopApis : IMyApis {
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool ReadFile(...);

bool IMyApis.ReadFile(...) { return ReadFile(...); }
}

sealed class PocketPCApis : IMyApis {
[DllImport("coredll.dll", SetLastError=true)]
private static extern bool ReadFile(...);

bool IMyApis.ReadFile(...) { return ReadFile(...); }
}


IMyApis api = Environment.OSVersion.Platform == PlatformID.WinCE ?
new PocketPCApis() : new DesktopApis();
api.ReadFile(...);



Mattias
 
O

ORC

Hi there,

NOP - it doesn't work. I get an error in this part:
IMyApis api = Environment.OSVersion.Platform == PlatformID.WinCE ?
new PocketPCApis() : new DesktopApis();

the error text is:
"Type of conditional expression can't be determined because there is no
implicit conversion between 'Ports.SerialPort.PocketPCApis' and
'Ports.SerialPort.DesktopApis'"

Code is made exactly as suggested and I don't get any other errors in the
code - the two dependend classes are exactly equal.

Any suggestion ???

Thanks
Ole

Ole Christensen said:
Thanks Mattias

It looks like it's something worth trying out so I'll do - Thanks a lot!

Ole

Mattias Sjögren said:
version
in
every call to the function.

Certainly not, one time is enough. all you have to do is wrap the
functionality in two system dependent classes that share a common
interface and let polymorphism do its magic.

Consider this

interface IMyApis {
bool ReadFile(...);
}

sealed class DesktopApis : IMyApis {
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool ReadFile(...);

bool IMyApis.ReadFile(...) { return ReadFile(...); }
}

sealed class PocketPCApis : IMyApis {
[DllImport("coredll.dll", SetLastError=true)]
private static extern bool ReadFile(...);

bool IMyApis.ReadFile(...) { return ReadFile(...); }
}


IMyApis api = Environment.OSVersion.Platform == PlatformID.WinCE ?
new PocketPCApis() : new DesktopApis();
api.ReadFile(...);



Mattias
 
R

Robert Jordan

NOP - it doesn't work. I get an error in this part:
IMyApis api = Environment.OSVersion.Platform == PlatformID.WinCE ?
new PocketPCApis() : new DesktopApis();

the error text is:
"Type of conditional expression can't be determined because there is no
implicit conversion between 'Ports.SerialPort.PocketPCApis' and
'Ports.SerialPort.DesktopApis'"

Code is made exactly as suggested and I don't get any other errors in the
code - the two dependend classes are exactly equal.

Any suggestion ???

IMyApis api;
if (Environment.OSVersion.Platform == PlatformID.WinCE) {
api = new PocketPCApis();
}
else {
api = new DesktopApis();
}

or

IMyApis api = Environment.OSVersion.Platform == PlatformID.WinCE ?
(IMyApis) new PocketPCApis() : (IMyApis) new DesktopApis();

bye
Rob
 
O

ORC

Great! thanks!

Regards
Ole

Robert Jordan said:
IMyApis api;
if (Environment.OSVersion.Platform == PlatformID.WinCE) {
api = new PocketPCApis();
}
else {
api = new DesktopApis();
}

or

IMyApis api = Environment.OSVersion.Platform == PlatformID.WinCE ?
(IMyApis) new PocketPCApis() : (IMyApis) new DesktopApis();

bye
Rob
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top