x86 and x64 => AnyCPU

Nov 8, 2012 at 12:39 PM
Edited Nov 8, 2012 at 12:41 PM

I would suggest to simplify the build output from x86/x64 specific builds to one AnyCPU build and avoid platform dependent compilation.

Currently you are using

#if IS_X64
   ...
#else
   ...
#endif

but you can simply use

if (IntPtr.Size == 4)
  ...
else
  ...

  

There is currently only one point I have no suggestion for:

 

#else

 

 

 

  

  

 

A related problem is the same name of the assembly for the different platforms. This is also a pain in the ass if you develop a library which has no differences within the architecture (can run on any cpu). You'll need to distribute platform specific releases, too (caused by the dependency and you can only put one assembly of the same name into the library) or you are forced to use the GAC and required to do some install/script magic.

Some info about mixed mode dlls is provided here:

http://scottbilas.com/blog/automatically-choose-32-or-64-bit-mixed-mode-dlls/

Thx,
Thomas

 

#endif

 

[FieldOffset(0x16)]

[FieldOffset(0x22)]

#if IS_X64

Nov 8, 2012 at 3:03 PM
Edited Nov 8, 2012 at 3:34 PM

A solution to remove the #ifdef for the FieldOffset property might be to split up the AppMouseStruct class into two separate structs (one for x86 and one for x64) because they are only used by one Method and get converted into a MouseStruct.

1. Split up the struct AppMouseStruct in x86 and x64

    [StructLayout(LayoutKind.Explicit)]
    internal struct AppMouseStructForX86
    {

        /// <summary>
        /// Specifies a Point structure that contains the X- and Y-coordinates of the cursor, in screen coordinates.
        /// </summary>
        [FieldOffset(0x00)]
        public Point Point;

        /// <summary>
        /// Specifies information associated with the message.
        /// </summary>
        /// <remarks>
        /// The possible values are:
        /// <list type="bullet">
        /// <item>
        /// <description>0 - No Information</description>
        /// </item>
        /// <item>
        /// <description>1 - X-Button1 Click</description>
        /// </item>
        /// <item>
        /// <description>2 - X-Button2 Click</description>
        /// </item>
        /// <item>
        /// <description>120 - Mouse Scroll Away from User</description>
        /// </item>
        /// <item>
        /// <description>-120 - Mouse Scroll Toward User</description>
        /// </item>
        /// </list>
        /// </remarks>
        [FieldOffset(0x16)]
        public Int16 MouseData;

        /// <summary>
        /// Converts the current <see cref="AppMouseStructForX86"/> into a <see cref="MouseStruct"/>.
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// The AppMouseStruct does not have a timestamp, thus one is generated at the time of this call.
        /// </remarks>
        public MouseStruct ToMouseStruct()
        {
            var tmp = new MouseStruct();
            tmp.Point = this.Point;
            tmp.MouseData = this.MouseData;
            tmp.Timestamp = Environment.TickCount;
            return tmp;
        }
    }

 

    /// <summary>
    /// The AppMouseStructForX64 structure contains information about a application-level mouse input event for x64.
    /// </summary>
    /// <remarks>
    /// See full documentation at http://globalmousekeyhook.codeplex.com/wikipage?title=MouseStruct
    /// </remarks>
    [StructLayout(LayoutKind.Explicit)]
    internal struct AppMouseStructForX64
    {

        /// <summary>
        /// Specifies a Point structure that contains the X- and Y-coordinates of the cursor, in screen coordinates.
        /// </summary>
        [FieldOffset(0x00)]
        public Point Point;

        /// <summary>
        /// Specifies information associated with the message.
        /// </summary>
        /// <remarks>
        /// The possible values are:
        /// <list type="bullet">
        /// <item>
        /// <description>0 - No Information</description>
        /// </item>
        /// <item>
        /// <description>1 - X-Button1 Click</description>
        /// </item>
        /// <item>
        /// <description>2 - X-Button2 Click</description>
        /// </item>
        /// <item>
        /// <description>120 - Mouse Scroll Away from User</description>
        /// </item>
        /// <item>
        /// <description>-120 - Mouse Scroll Toward User</description>
        /// </item>
        /// </list>
        /// </remarks>
        [FieldOffset(0x22)]
        public Int16 MouseData;

        /// <summary>
        /// Converts the current <see cref="MouseStruct"/> into a <see cref="AppMouseStructForX64"/>.
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// The AppMouseStruct does not have a timestamp, thus one is generated at the time of this call.
        /// </remarks>
        public MouseStruct ToMouseStruct()
        {
            MouseStruct tmp = new MouseStruct();
            tmp.Point = this.Point;
            tmp.MouseData = this.MouseData;
            tmp.Timestamp = Environment.TickCount;
            return tmp;
        }
    }

2. .... and for the MouseEventExtArgs class modify the FramRawDataApp method as follows:

        /// <summary>
        /// Creates <see cref="MouseEventExtArgs"/> from Windows Message parameters,
        /// based upon a local application hook.
        /// </summary>
        /// <param name="wParam">The first Windows Message parameter.</param>
        /// <param name="lParam">The second Windows Message parameter.</param>
        /// <returns>A new MouseEventExtArgs object.</returns>
        private static MouseEventExtArgs FromRawDataApp(int wParam, IntPtr lParam)
        {
            if (IntPtr.Size != 4)
            {
                var marshalledMouseStruct = (AppMouseStructForX64)Marshal.PtrToStructure(lParam, typeof(AppMouseStructForX64));
                return FromRawDataUniversal(wParam, marshalledMouseStruct.ToMouseStruct());
            }
            else
            {
                var marshalledMouseStruct = (AppMouseStructForX86)Marshal.PtrToStructure(lParam, typeof(AppMouseStructForX86));
                return FromRawDataUniversal(wParam, marshalledMouseStruct.ToMouseStruct());
            }
        }

... this way together with the (IntPtr.Size == 4) ? "x86" : "x64") hint from the post above there is no need for separate builds for x86 and x64... so you're lib users don't get a "BadImageException" because they're loading the wrong assembly. ;-)

 

Jan 2, 2013 at 8:38 PM

Thanks for posting this!  Worked perfectly on a app I am building with VS2012.