PInvoke Marshalling....

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Daniel Bass

    #1

    PInvoke Marshalling....

    Greetings!

    I'm trying to call this method in a c# app...

    SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
    DeviceHandle, unsigned char *pData, long max_length);

    So far I've got this:
    [DllImport("Depe ndencies\\SNAPI .DLL")]
    public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
    StringBuilder pData, long max_length);

    Keep getting a PInvokeStackImb alance error and I think it's the 2nd paramter
    pData because I've referenced the device handler and the long typedef is
    pretty obvious.

    For the 2nd paramter I've tried the following without success:
    byte[]
    char[]
    string
    StringBuilder
    [MarshalAs(Unman agedType.AnsiBS tr)] string

    HELP!
    Thanks.
    Dan.


  • Nicholas Paldino [.NET/C# MVP]

    #2
    Re: PInvoke Marshalling....

    Daniel,

    Actually, it's not pretty obvious. In C++, long corresponds to a 32-bit
    integer, which in C#, is an int. Also, you should declare how your strings
    are marshaled in the DllImport attribute. All-in-all, your declaration
    should look like this:

    [DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
    public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
    StringBuilder pData, int max_length);

    Also, if the pData parameter is not going to be written to by the API
    function, you can pass it as a string.


    --
    - Nicholas Paldino [.NET/C# MVP]
    - mvp@spam.guard. caspershouse.co m


    "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
    news:u83rn0XFIH A.1056@TK2MSFTN GP03.phx.gbl...
    Greetings!
    >
    I'm trying to call this method in a c# app...
    >
    SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
    DeviceHandle, unsigned char *pData, long max_length);
    >
    So far I've got this:
    [DllImport("Depe ndencies\\SNAPI .DLL")]
    public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
    StringBuilder pData, long max_length);
    >
    Keep getting a PInvokeStackImb alance error and I think it's the 2nd
    paramter pData because I've referenced the device handler and the long
    typedef is pretty obvious.
    >
    For the 2nd paramter I've tried the following without success:
    byte[]
    char[]
    string
    StringBuilder
    [MarshalAs(Unman agedType.AnsiBS tr)] string
    >
    HELP!
    Thanks.
    Dan.
    >

    Comment

    • Daniel Bass

      #3
      Re: PInvoke Marshalling....

      Nicholas,

      Excellent, thanks for the prompt reply!

      pData is a buffer that I create, then pass into the function to populate.
      Does the parameter as a StringBuilder marshall this data correctly?

      Thanks.
      Dan.

      "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote in
      message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
      Daniel,
      >
      Actually, it's not pretty obvious. In C++, long corresponds to a
      32-bit integer, which in C#, is an int. Also, you should declare how your
      strings are marshaled in the DllImport attribute. All-in-all, your
      declaration should look like this:
      >
      [DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
      public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
      StringBuilder pData, int max_length);
      >
      Also, if the pData parameter is not going to be written to by the API
      function, you can pass it as a string.
      >
      >
      --
      - Nicholas Paldino [.NET/C# MVP]
      - mvp@spam.guard. caspershouse.co m
      >
      >
      "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
      news:u83rn0XFIH A.1056@TK2MSFTN GP03.phx.gbl...
      >Greetings!
      >>
      >I'm trying to call this method in a c# app...
      >>
      > SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
      >DeviceHandle , unsigned char *pData, long max_length);
      >>
      >So far I've got this:
      > [DllImport("Depe ndencies\\SNAPI .DLL")]
      > public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
      >StringBuilde r pData, long max_length);
      >>
      >Keep getting a PInvokeStackImb alance error and I think it's the 2nd
      >paramter pData because I've referenced the device handler and the long
      >typedef is pretty obvious.
      >>
      >For the 2nd paramter I've tried the following without success:
      > byte[]
      > char[]
      > string
      > StringBuilder
      > [MarshalAs(Unman agedType.AnsiBS tr)] string
      >>
      >HELP!
      >Thanks.
      >Dan.
      >>
      >
      >

      Comment

      • Nicholas Paldino [.NET/C# MVP]

        #4
        Re: PInvoke Marshalling....

        Daniel,

        Yes, if the API function is going to write to the buffer, then passing a
        StringBuilder will cause the data to be marshaled back to you correctly.


        --
        - Nicholas Paldino [.NET/C# MVP]
        - mvp@spam.guard. caspershouse.co m

        "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
        news:%23EkQlBYF IHA.1212@TK2MSF TNGP05.phx.gbl. ..
        Nicholas,
        >
        Excellent, thanks for the prompt reply!
        >
        pData is a buffer that I create, then pass into the function to populate.
        Does the parameter as a StringBuilder marshall this data correctly?
        >
        Thanks.
        Dan.
        >
        "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
        in message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
        >Daniel,
        >>
        > Actually, it's not pretty obvious. In C++, long corresponds to a
        >32-bit integer, which in C#, is an int. Also, you should declare how
        >your strings are marshaled in the DllImport attribute. All-in-all, your
        >declaration should look like this:
        >>
        >[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
        >public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
        >StringBuilde r pData, int max_length);
        >>
        > Also, if the pData parameter is not going to be written to by the API
        >function, you can pass it as a string.
        >>
        >>
        >--
        > - Nicholas Paldino [.NET/C# MVP]
        > - mvp@spam.guard. caspershouse.co m
        >>
        >>
        >"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
        >news:u83rn0XFI HA.1056@TK2MSFT NGP03.phx.gbl.. .
        >>Greetings!
        >>>
        >>I'm trying to call this method in a c# app...
        >>>
        >> SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
        >>DeviceHandl e, unsigned char *pData, long max_length);
        >>>
        >>So far I've got this:
        >> [DllImport("Depe ndencies\\SNAPI .DLL")]
        >> public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
        >>StringBuild er pData, long max_length);
        >>>
        >>Keep getting a PInvokeStackImb alance error and I think it's the 2nd
        >>paramter pData because I've referenced the device handler and the long
        >>typedef is pretty obvious.
        >>>
        >>For the 2nd paramter I've tried the following without success:
        >> byte[]
        >> char[]
        >> string
        >> StringBuilder
        >> [MarshalAs(Unman agedType.AnsiBS tr)] string
        >>>
        >>HELP!
        >>Thanks.
        >>Dan.
        >>>
        >>
        >>
        >
        >

        Comment

        • Daniel Bass

          #5
          Re: PInvoke Marshalling....

          Nicholas,

          I've just been reading through the API guide, and realised that it won't
          pass me back the data in a synchronous manner.

          To quote:
          "A command function returns immediately to the host application...
          After the command is processed, by the scanner, the host application
          received a Windows message indicating the command was processed. The host
          applicaition provides a message handler for the ack from the connected
          device."

          Eeek! In .Net, is there a way to listen for messages? I've worked a little
          with message maps, but that was way back and have not see this sort of basic
          message handling in .net before...

          Cheers.
          Dan.

          "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote in
          message news:%23Wy5GFYF IHA.5328@TK2MSF TNGP05.phx.gbl. ..
          Daniel,
          >
          Yes, if the API function is going to write to the buffer, then passing
          a StringBuilder will cause the data to be marshaled back to you correctly.
          >
          >
          --
          - Nicholas Paldino [.NET/C# MVP]
          - mvp@spam.guard. caspershouse.co m
          >
          "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
          news:%23EkQlBYF IHA.1212@TK2MSF TNGP05.phx.gbl. ..
          >Nicholas,
          >>
          >Excellent, thanks for the prompt reply!
          >>
          >pData is a buffer that I create, then pass into the function to populate.
          >Does the parameter as a StringBuilder marshall this data correctly?
          >>
          >Thanks.
          >Dan.
          >>
          >"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
          >in message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
          >>Daniel,
          >>>
          >> Actually, it's not pretty obvious. In C++, long corresponds to a
          >>32-bit integer, which in C#, is an int. Also, you should declare how
          >>your strings are marshaled in the DllImport attribute. All-in-all, your
          >>declaration should look like this:
          >>>
          >>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
          >>public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
          >>StringBuild er pData, int max_length);
          >>>
          >> Also, if the pData parameter is not going to be written to by the API
          >>function, you can pass it as a string.
          >>>
          >>>
          >>--
          >> - Nicholas Paldino [.NET/C# MVP]
          >> - mvp@spam.guard. caspershouse.co m
          >>>
          >>>
          >>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
          >>news:u83rn0XF IHA.1056@TK2MSF TNGP03.phx.gbl. ..
          >>>Greetings!
          >>>>
          >>>I'm trying to call this method in a c# app...
          >>>>
          >>> SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
          >>>DeviceHandle , unsigned char *pData, long max_length);
          >>>>
          >>>So far I've got this:
          >>> [DllImport("Depe ndencies\\SNAPI .DLL")]
          >>> public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
          >>>StringBuilde r pData, long max_length);
          >>>>
          >>>Keep getting a PInvokeStackImb alance error and I think it's the 2nd
          >>>paramter pData because I've referenced the device handler and the long
          >>>typedef is pretty obvious.
          >>>>
          >>>For the 2nd paramter I've tried the following without success:
          >>> byte[]
          >>> char[]
          >>> string
          >>> StringBuilder
          >>> [MarshalAs(Unman agedType.AnsiBS tr)] string
          >>>>
          >>>HELP!
          >>>Thanks.
          >>>Dan.
          >>>>
          >>>
          >>>
          >>
          >>
          >
          >

          Comment

          • Nicholas Paldino [.NET/C# MVP]

            #6
            Re: PInvoke Marshalling....

            Daniel,

            Yes, there is. You can create a class which implements the
            IMessageFilter interface and then call the AddMessageFilte r method on the
            Application class, passing your implementation. Then, in the
            PreFilterMessag e method, you would check for your message.

            There might be a more subtle issue here. When the function returns, is
            the string already written to? Or is the string written to when the message
            is sent to the application? If it is the former, then the code you have is
            ok. If it is the latter, you will have to change your declaration of the
            unsigned char * parameter to an IntPtr, and allocate the memory that you
            need yourself.

            Then, in the handler for the message, you will have to manually marshal
            the string to managed code using the static methods on the Marshal class
            (freeing the memory of course as well).

            --
            - Nicholas Paldino [.NET/C# MVP]
            - mvp@spam.guard. caspershouse.co m

            "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
            news:u%23iPBKYF IHA.4140@TK2MSF TNGP03.phx.gbl. ..
            Nicholas,
            >
            I've just been reading through the API guide, and realised that it won't
            pass me back the data in a synchronous manner.
            >
            To quote:
            "A command function returns immediately to the host application...
            After the command is processed, by the scanner, the host application
            received a Windows message indicating the command was processed. The host
            applicaition provides a message handler for the ack from the connected
            device."
            >
            Eeek! In .Net, is there a way to listen for messages? I've worked a little
            with message maps, but that was way back and have not see this sort of
            basic message handling in .net before...
            >
            Cheers.
            Dan.
            >
            "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
            in message news:%23Wy5GFYF IHA.5328@TK2MSF TNGP05.phx.gbl. ..
            >Daniel,
            >>
            > Yes, if the API function is going to write to the buffer, then passing
            >a StringBuilder will cause the data to be marshaled back to you
            >correctly.
            >>
            >>
            >--
            > - Nicholas Paldino [.NET/C# MVP]
            > - mvp@spam.guard. caspershouse.co m
            >>
            >"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
            >news:%23EkQlBY FIHA.1212@TK2MS FTNGP05.phx.gbl ...
            >>Nicholas,
            >>>
            >>Excellent, thanks for the prompt reply!
            >>>
            >>pData is a buffer that I create, then pass into the function to
            >>populate. Does the parameter as a StringBuilder marshall this data
            >>correctly?
            >>>
            >>Thanks.
            >>Dan.
            >>>
            >>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
            >>in message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
            >>>Daniel,
            >>>>
            >>> Actually, it's not pretty obvious. In C++, long corresponds to a
            >>>32-bit integer, which in C#, is an int. Also, you should declare how
            >>>your strings are marshaled in the DllImport attribute. All-in-all,
            >>>your declaration should look like this:
            >>>>
            >>>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
            >>>public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
            >>>StringBuilde r pData, int max_length);
            >>>>
            >>> Also, if the pData parameter is not going to be written to by the
            >>>API function, you can pass it as a string.
            >>>>
            >>>>
            >>>--
            >>> - Nicholas Paldino [.NET/C# MVP]
            >>> - mvp@spam.guard. caspershouse.co m
            >>>>
            >>>>
            >>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
            >>>news:u83rn0X FIHA.1056@TK2MS FTNGP03.phx.gbl ...
            >>>>Greetings !
            >>>>>
            >>>>I'm trying to call this method in a c# app...
            >>>>>
            >>>> SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
            >>>>DeviceHandl e, unsigned char *pData, long max_length);
            >>>>>
            >>>>So far I've got this:
            >>>> [DllImport("Depe ndencies\\SNAPI .DLL")]
            >>>> public static extern int SNAPI_SetVersio nBuffer(IntPtr
            >>>>DeviceHandl e, StringBuilder pData, long max_length);
            >>>>>
            >>>>Keep getting a PInvokeStackImb alance error and I think it's the 2nd
            >>>>paramter pData because I've referenced the device handler and the long
            >>>>typedef is pretty obvious.
            >>>>>
            >>>>For the 2nd paramter I've tried the following without success:
            >>>> byte[]
            >>>> char[]
            >>>> string
            >>>> StringBuilder
            >>>> [MarshalAs(Unman agedType.AnsiBS tr)] string
            >>>>>
            >>>>HELP!
            >>>>Thanks.
            >>>>Dan.
            >>>>>
            >>>>
            >>>>
            >>>
            >>>
            >>
            >>
            >
            >

            Comment

            • Daniel Bass

              #7
              Re: PInvoke Marshalling....


              I pass in a handle of the windows into the API as part of an initialisation
              call. Could I then just override "WndProc"?

              It's doing the latter, and only sending a message when the parameter has
              been sent to the buffer. When you say "allocate the memory" yourself, I'm
              not sure what you mean. I'll provide the IntPtr parameter, and according the
              API manual, I'll have a global buffer space that I register with the API
              which should be populated with the event call... Does that sound feasible?

              Thanks for your help and guidance!

              "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote in
              message news:OovEiMYFIH A.5208@TK2MSFTN GP04.phx.gbl...
              Daniel,
              >
              Yes, there is. You can create a class which implements the
              IMessageFilter interface and then call the AddMessageFilte r method on the
              Application class, passing your implementation. Then, in the
              PreFilterMessag e method, you would check for your message.
              >
              There might be a more subtle issue here. When the function returns, is
              the string already written to? Or is the string written to when the
              message is sent to the application? If it is the former, then the code
              you have is ok. If it is the latter, you will have to change your
              declaration of the unsigned char * parameter to an IntPtr, and allocate
              the memory that you need yourself.
              >
              Then, in the handler for the message, you will have to manually marshal
              the string to managed code using the static methods on the Marshal class
              (freeing the memory of course as well).
              >
              --
              - Nicholas Paldino [.NET/C# MVP]
              - mvp@spam.guard. caspershouse.co m
              >
              "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
              news:u%23iPBKYF IHA.4140@TK2MSF TNGP03.phx.gbl. ..
              >Nicholas,
              >>
              >I've just been reading through the API guide, and realised that it won't
              >pass me back the data in a synchronous manner.
              >>
              >To quote:
              >"A command function returns immediately to the host application...
              >After the command is processed, by the scanner, the host application
              >received a Windows message indicating the command was processed. The host
              >applicaition provides a message handler for the ack from the connected
              >device."
              >>
              >Eeek! In .Net, is there a way to listen for messages? I've worked a
              >little with message maps, but that was way back and have not see this
              >sort of basic message handling in .net before...
              >>
              >Cheers.
              >Dan.
              >>
              >"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
              >in message news:%23Wy5GFYF IHA.5328@TK2MSF TNGP05.phx.gbl. ..
              >>Daniel,
              >>>
              >> Yes, if the API function is going to write to the buffer, then
              >>passing a StringBuilder will cause the data to be marshaled back to you
              >>correctly.
              >>>
              >>>
              >>--
              >> - Nicholas Paldino [.NET/C# MVP]
              >> - mvp@spam.guard. caspershouse.co m
              >>>
              >>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
              >>news:%23EkQlB YFIHA.1212@TK2M SFTNGP05.phx.gb l...
              >>>Nicholas,
              >>>>
              >>>Excellent, thanks for the prompt reply!
              >>>>
              >>>pData is a buffer that I create, then pass into the function to
              >>>populate. Does the parameter as a StringBuilder marshall this data
              >>>correctly?
              >>>>
              >>>Thanks.
              >>>Dan.
              >>>>
              >>>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
              >>>wrote in message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
              >>>>Daniel,
              >>>>>
              >>>> Actually, it's not pretty obvious. In C++, long corresponds to a
              >>>>32-bit integer, which in C#, is an int. Also, you should declare how
              >>>>your strings are marshaled in the DllImport attribute. All-in-all,
              >>>>your declaration should look like this:
              >>>>>
              >>>>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
              >>>>public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
              >>>>StringBuild er pData, int max_length);
              >>>>>
              >>>> Also, if the pData parameter is not going to be written to by the
              >>>>API function, you can pass it as a string.
              >>>>>
              >>>>>
              >>>>--
              >>>> - Nicholas Paldino [.NET/C# MVP]
              >>>> - mvp@spam.guard. caspershouse.co m
              >>>>>
              >>>>>
              >>>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
              >>>>news:u83rn0 XFIHA.1056@TK2M SFTNGP03.phx.gb l...
              >>>>>Greeting s!
              >>>>>>
              >>>>>I'm trying to call this method in a c# app...
              >>>>>>
              >>>>> SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
              >>>>>DeviceHand le, unsigned char *pData, long max_length);
              >>>>>>
              >>>>>So far I've got this:
              >>>>> [DllImport("Depe ndencies\\SNAPI .DLL")]
              >>>>> public static extern int SNAPI_SetVersio nBuffer(IntPtr
              >>>>>DeviceHand le, StringBuilder pData, long max_length);
              >>>>>>
              >>>>>Keep getting a PInvokeStackImb alance error and I think it's the 2nd
              >>>>>paramter pData because I've referenced the device handler and the
              >>>>>long typedef is pretty obvious.
              >>>>>>
              >>>>>For the 2nd paramter I've tried the following without success:
              >>>>> byte[]
              >>>>> char[]
              >>>>> string
              >>>>> StringBuilder
              >>>>> [MarshalAs(Unman agedType.AnsiBS tr)] string
              >>>>>>
              >>>>>HELP!
              >>>>>Thanks.
              >>>>>Dan.
              >>>>>>
              >>>>>
              >>>>>
              >>>>
              >>>>
              >>>
              >>>
              >>
              >>
              >
              >

              Comment

              • Nicholas Paldino [.NET/C# MVP]

                #8
                Re: PInvoke Marshalling....

                Daniel,

                I was thinking this is a little odd, since the parameter is named
                "DeviceHand le" and not indicative that it is a windows handle. If it is
                indeed a windows handle you are passing to the method, then you can override
                the WndProc method of the control that contains that windows handle to look
                for the message sent to you.

                You will have to change your API declaration to this:

                [DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle, IntPtr
                pData, int max_length);

                And then call it like this:

                // dataBuffer need to be accessible by the override of WndProc as well.
                dataBuffer = Marshal.AllocHG lobal(dataBuffe rLength);

                // Make the API call:
                SNAPI_SetVersio nBuffer(windowH andle, dataBuffer, dataBufferLengt h);

                Then, in your override of WndProc, in the section that handles the
                message to the window:

                // Get the string.
                string data = Marshal.PtrToSt ringAnsi(dataBu ffer);

                // Free the memory.
                Marshal.FreeHGl obal(dataBuffer );

                // Work with the string.


                --
                - Nicholas Paldino [.NET/C# MVP]
                - mvp@spam.guard. caspershouse.co m


                "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                news:O3sK%23VYF IHA.3548@TK2MSF TNGP06.phx.gbl. ..
                >
                I pass in a handle of the windows into the API as part of an
                initialisation call. Could I then just override "WndProc"?
                >
                It's doing the latter, and only sending a message when the parameter has
                been sent to the buffer. When you say "allocate the memory" yourself, I'm
                not sure what you mean. I'll provide the IntPtr parameter, and according
                the API manual, I'll have a global buffer space that I register with the
                API which should be populated with the event call... Does that sound
                feasible?
                >
                Thanks for your help and guidance!
                >
                "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                in message news:OovEiMYFIH A.5208@TK2MSFTN GP04.phx.gbl...
                >Daniel,
                >>
                > Yes, there is. You can create a class which implements the
                >IMessageFilt er interface and then call the AddMessageFilte r method on the
                >Application class, passing your implementation. Then, in the
                >PreFilterMessa ge method, you would check for your message.
                >>
                > There might be a more subtle issue here. When the function returns,
                >is the string already written to? Or is the string written to when the
                >message is sent to the application? If it is the former, then the code
                >you have is ok. If it is the latter, you will have to change your
                >declaration of the unsigned char * parameter to an IntPtr, and allocate
                >the memory that you need yourself.
                >>
                > Then, in the handler for the message, you will have to manually
                >marshal the string to managed code using the static methods on the
                >Marshal class (freeing the memory of course as well).
                >>
                >--
                > - Nicholas Paldino [.NET/C# MVP]
                > - mvp@spam.guard. caspershouse.co m
                >>
                >"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                >news:u%23iPBKY FIHA.4140@TK2MS FTNGP03.phx.gbl ...
                >>Nicholas,
                >>>
                >>I've just been reading through the API guide, and realised that it won't
                >>pass me back the data in a synchronous manner.
                >>>
                >>To quote:
                >>"A command function returns immediately to the host application...
                >>After the command is processed, by the scanner, the host application
                >>received a Windows message indicating the command was processed. The
                >>host applicaition provides a message handler for the ack from the
                >>connected device."
                >>>
                >>Eeek! In .Net, is there a way to listen for messages? I've worked a
                >>little with message maps, but that was way back and have not see this
                >>sort of basic message handling in .net before...
                >>>
                >>Cheers.
                >>Dan.
                >>>
                >>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                >>in message news:%23Wy5GFYF IHA.5328@TK2MSF TNGP05.phx.gbl. ..
                >>>Daniel,
                >>>>
                >>> Yes, if the API function is going to write to the buffer, then
                >>>passing a StringBuilder will cause the data to be marshaled back to you
                >>>correctly.
                >>>>
                >>>>
                >>>--
                >>> - Nicholas Paldino [.NET/C# MVP]
                >>> - mvp@spam.guard. caspershouse.co m
                >>>>
                >>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                >>>news:%23EkQl BYFIHA.1212@TK2 MSFTNGP05.phx.g bl...
                >>>>Nicholas,
                >>>>>
                >>>>Excellent , thanks for the prompt reply!
                >>>>>
                >>>>pData is a buffer that I create, then pass into the function to
                >>>>populate. Does the parameter as a StringBuilder marshall this data
                >>>>correctly ?
                >>>>>
                >>>>Thanks.
                >>>>Dan.
                >>>>>
                >>>>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                >>>>wrote in message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
                >>>>>Daniel,
                >>>>>>
                >>>>> Actually, it's not pretty obvious. In C++, long corresponds to a
                >>>>>32-bit integer, which in C#, is an int. Also, you should declare how
                >>>>>your strings are marshaled in the DllImport attribute. All-in-all,
                >>>>>your declaration should look like this:
                >>>>>>
                >>>>>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                >>>>>public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
                >>>>>StringBuil der pData, int max_length);
                >>>>>>
                >>>>> Also, if the pData parameter is not going to be written to by the
                >>>>>API function, you can pass it as a string.
                >>>>>>
                >>>>>>
                >>>>>--
                >>>>> - Nicholas Paldino [.NET/C# MVP]
                >>>>> - mvp@spam.guard. caspershouse.co m
                >>>>>>
                >>>>>>
                >>>>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in
                >>>>>message news:u83rn0XFIH A.1056@TK2MSFTN GP03.phx.gbl...
                >>>>>>Greetings !
                >>>>>>>
                >>>>>>I'm trying to call this method in a c# app...
                >>>>>>>
                >>>>>> SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
                >>>>>>DeviceHan dle, unsigned char *pData, long max_length);
                >>>>>>>
                >>>>>>So far I've got this:
                >>>>>> [DllImport("Depe ndencies\\SNAPI .DLL")]
                >>>>>> public static extern int SNAPI_SetVersio nBuffer(IntPtr
                >>>>>>DeviceHan dle, StringBuilder pData, long max_length);
                >>>>>>>
                >>>>>>Keep getting a PInvokeStackImb alance error and I think it's the 2nd
                >>>>>>paramte r pData because I've referenced the device handler and the
                >>>>>>long typedef is pretty obvious.
                >>>>>>>
                >>>>>>For the 2nd paramter I've tried the following without success:
                >>>>>> byte[]
                >>>>>> char[]
                >>>>>> string
                >>>>>> StringBuilder
                >>>>>> [MarshalAs(Unman agedType.AnsiBS tr)] string
                >>>>>>>
                >>>>>>HELP!
                >>>>>>Thanks.
                >>>>>>Dan.
                >>>>>>>
                >>>>>>
                >>>>>>
                >>>>>
                >>>>>
                >>>>
                >>>>
                >>>
                >>>
                >>
                >>
                >
                >

                Comment

                • Daniel Bass

                  #9
                  Re: PInvoke Marshalling....

                  Well, kind of...

                  A little context may help. I'm writing a front end into a driver for a USB
                  connected imaging scanner.

                  DeviceHandle is the handle that I keep hold of for the currently connected
                  device.

                  The first call I make into the API though, is
                  [DllImport("Depe ndencies\\SNAPI .DLL")]
                  public static extern int SNAPI_Init(IntP tr hwend, IntPtr[]
                  DeviceHandles, ref int NumDevices);
                  This basically expects a windows handler, along with a buffer array which it
                  uses to populate with scanners that are currently attached to the system.

                  I've overriden WndProc, and it's correctly getting the message I'd expect,
                  in this case it's the WM_VERSION message. All I'm trying to do is initially
                  query the scanner for the firmware version as a simple way of exchanging
                  data before I get onto imaging and video!

                  OnConnect type event does this:
                  int status = 0;
                  status = DriverProxy.SNA PI_SetVersionBu ffer(handle,
                  _versionBuffer, _versionBuffer. Length);
                  status = DriverProxy.SNA PI_TransmitVers ion(handle);
                  _versionBuffer is global StringBuilder, and transmit version tells the scan
                  to please send me the firmware version to the allocated buffer.

                  In WndProc override:
                  protected override void WndProc(ref Message m)
                  {
                  switch ((uint)m.Msg)
                  {
                  case DriverProxy.WM_ SWVERSION:
                  // should now have a _versionbuffer full of grand stuff
                  FirmwareVersion Label.Text = _versionBuffer. ToString();
                  break;

                  }
                  Debug.WriteLine If(m.Msg 0x8000 && m.Msg < 0xBFFF, "HIT! " +
                  m.Msg.ToString( ));
                  base.WndProc(re f m);
                  }

                  Now I've a label that gets the Firmware version text assigned to it, but
                  this is currently blank, and can confirm that the WM_SWVERSION message comes
                  through...

                  Hope that helps to explain what I'm trying to achieve.
                  Thanks again.
                  Dan.


                  "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote in
                  message news:OadAbZYFIH A.3716@TK2MSFTN GP03.phx.gbl...
                  Daniel,
                  >
                  I was thinking this is a little odd, since the parameter is named
                  "DeviceHand le" and not indicative that it is a windows handle. If it is
                  indeed a windows handle you are passing to the method, then you can
                  override the WndProc method of the control that contains that windows
                  handle to look for the message sent to you.
                  >
                  You will have to change your API declaration to this:
                  >
                  [DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                  public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
                  IntPtr pData, int max_length);
                  >
                  And then call it like this:
                  >
                  // dataBuffer need to be accessible by the override of WndProc as well.
                  dataBuffer = Marshal.AllocHG lobal(dataBuffe rLength);
                  >
                  // Make the API call:
                  SNAPI_SetVersio nBuffer(windowH andle, dataBuffer, dataBufferLengt h);
                  >
                  Then, in your override of WndProc, in the section that handles the
                  message to the window:
                  >
                  // Get the string.
                  string data = Marshal.PtrToSt ringAnsi(dataBu ffer);
                  >
                  // Free the memory.
                  Marshal.FreeHGl obal(dataBuffer );
                  >
                  // Work with the string.
                  >
                  >
                  --
                  - Nicholas Paldino [.NET/C# MVP]
                  - mvp@spam.guard. caspershouse.co m
                  >
                  >
                  "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                  news:O3sK%23VYF IHA.3548@TK2MSF TNGP06.phx.gbl. ..
                  >>
                  >I pass in a handle of the windows into the API as part of an
                  >initialisati on call. Could I then just override "WndProc"?
                  >>
                  >It's doing the latter, and only sending a message when the parameter has
                  >been sent to the buffer. When you say "allocate the memory" yourself, I'm
                  >not sure what you mean. I'll provide the IntPtr parameter, and according
                  >the API manual, I'll have a global buffer space that I register with the
                  >API which should be populated with the event call... Does that sound
                  >feasible?
                  >>
                  >Thanks for your help and guidance!
                  >>
                  >"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                  >in message news:OovEiMYFIH A.5208@TK2MSFTN GP04.phx.gbl...
                  >>Daniel,
                  >>>
                  >> Yes, there is. You can create a class which implements the
                  >>IMessageFilte r interface and then call the AddMessageFilte r method on
                  >>the Application class, passing your implementation. Then, in the
                  >>PreFilterMess age method, you would check for your message.
                  >>>
                  >> There might be a more subtle issue here. When the function returns,
                  >>is the string already written to? Or is the string written to when the
                  >>message is sent to the application? If it is the former, then the code
                  >>you have is ok. If it is the latter, you will have to change your
                  >>declaration of the unsigned char * parameter to an IntPtr, and allocate
                  >>the memory that you need yourself.
                  >>>
                  >> Then, in the handler for the message, you will have to manually
                  >>marshal the string to managed code using the static methods on the
                  >>Marshal class (freeing the memory of course as well).
                  >>>
                  >>--
                  >> - Nicholas Paldino [.NET/C# MVP]
                  >> - mvp@spam.guard. caspershouse.co m
                  >>>
                  >>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                  >>news:u%23iPBK YFIHA.4140@TK2M SFTNGP03.phx.gb l...
                  >>>Nicholas,
                  >>>>
                  >>>I've just been reading through the API guide, and realised that it
                  >>>won't pass me back the data in a synchronous manner.
                  >>>>
                  >>>To quote:
                  >>>"A command function returns immediately to the host application...
                  >>>After the command is processed, by the scanner, the host application
                  >>>received a Windows message indicating the command was processed. The
                  >>>host applicaition provides a message handler for the ack from the
                  >>>connected device."
                  >>>>
                  >>>Eeek! In .Net, is there a way to listen for messages? I've worked a
                  >>>little with message maps, but that was way back and have not see this
                  >>>sort of basic message handling in .net before...
                  >>>>
                  >>>Cheers.
                  >>>Dan.
                  >>>>
                  >>>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                  >>>wrote in message news:%23Wy5GFYF IHA.5328@TK2MSF TNGP05.phx.gbl. ..
                  >>>>Daniel,
                  >>>>>
                  >>>> Yes, if the API function is going to write to the buffer, then
                  >>>>passing a StringBuilder will cause the data to be marshaled back to
                  >>>>you correctly.
                  >>>>>
                  >>>>>
                  >>>>--
                  >>>> - Nicholas Paldino [.NET/C# MVP]
                  >>>> - mvp@spam.guard. caspershouse.co m
                  >>>>>
                  >>>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                  >>>>news:%23EkQ lBYFIHA.1212@TK 2MSFTNGP05.phx. gbl...
                  >>>>>Nicholas ,
                  >>>>>>
                  >>>>>Excellen t, thanks for the prompt reply!
                  >>>>>>
                  >>>>>pData is a buffer that I create, then pass into the function to
                  >>>>>populate . Does the parameter as a StringBuilder marshall this data
                  >>>>>correctl y?
                  >>>>>>
                  >>>>>Thanks.
                  >>>>>Dan.
                  >>>>>>
                  >>>>>"Nichola s Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                  >>>>>wrote in message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
                  >>>>>>Daniel,
                  >>>>>>>
                  >>>>>> Actually, it's not pretty obvious. In C++, long corresponds to a
                  >>>>>>32-bit integer, which in C#, is an int. Also, you should declare
                  >>>>>>how your strings are marshaled in the DllImport attribute.
                  >>>>>>All-in-all, your declaration should look like this:
                  >>>>>>>
                  >>>>>>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                  >>>>>>public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
                  >>>>>>StringBui lder pData, int max_length);
                  >>>>>>>
                  >>>>>> Also, if the pData parameter is not going to be written to by the
                  >>>>>>API function, you can pass it as a string.
                  >>>>>>>
                  >>>>>>>
                  >>>>>>--
                  >>>>>> - Nicholas Paldino [.NET/C# MVP]
                  >>>>>> - mvp@spam.guard. caspershouse.co m
                  >>>>>>>
                  >>>>>>>
                  >>>>>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in
                  >>>>>>message news:u83rn0XFIH A.1056@TK2MSFTN GP03.phx.gbl...
                  >>>>>>>Greeting s!
                  >>>>>>>>
                  >>>>>>>I'm trying to call this method in a c# app...
                  >>>>>>>>
                  >>>>>>> SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
                  >>>>>>>DeviceHa ndle, unsigned char *pData, long max_length);
                  >>>>>>>>
                  >>>>>>>So far I've got this:
                  >>>>>>> [DllImport("Depe ndencies\\SNAPI .DLL")]
                  >>>>>>> public static extern int SNAPI_SetVersio nBuffer(IntPtr
                  >>>>>>>DeviceHa ndle, StringBuilder pData, long max_length);
                  >>>>>>>>
                  >>>>>>>Keep getting a PInvokeStackImb alance error and I think it's the 2nd
                  >>>>>>>paramt er pData because I've referenced the device handler and the
                  >>>>>>>long typedef is pretty obvious.
                  >>>>>>>>
                  >>>>>>>For the 2nd paramter I've tried the following without success:
                  >>>>>>> byte[]
                  >>>>>>> char[]
                  >>>>>>> string
                  >>>>>>> StringBuilder
                  >>>>>>> [MarshalAs(Unman agedType.AnsiBS tr)] string
                  >>>>>>>>
                  >>>>>>>HELP!
                  >>>>>>>Thanks .
                  >>>>>>>Dan.
                  >>>>>>>>
                  >>>>>>>
                  >>>>>>>
                  >>>>>>
                  >>>>>>
                  >>>>>
                  >>>>>
                  >>>>
                  >>>>
                  >>>
                  >>>
                  >>
                  >>
                  >
                  >

                  Comment

                  • Nicholas Paldino [.NET/C# MVP]

                    #10
                    Re: PInvoke Marshalling....

                    Daniel,

                    My previous post outlines what you have to do with allocating the
                    buffer.

                    When you pass a StringBuilder, the P/Invoke layer creates a buffer of
                    unmanaged memory, and passes the pointer to that, populated with the
                    contents of the string builder. Upon return, the P/Invoke layer marshals
                    the information from that unmanaged buffer back into the StringBuilder, and
                    disposes of the pointer.

                    However, this API is holding onto the pointer, so you have to do the
                    same.

                    --
                    - Nicholas Paldino [.NET/C# MVP]
                    - mvp@spam.guard. caspershouse.co m

                    "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                    news:O78SjhYFIH A.4228@TK2MSFTN GP02.phx.gbl...
                    Well, kind of...
                    >
                    A little context may help. I'm writing a front end into a driver for a USB
                    connected imaging scanner.
                    >
                    DeviceHandle is the handle that I keep hold of for the currently connected
                    device.
                    >
                    The first call I make into the API though, is
                    [DllImport("Depe ndencies\\SNAPI .DLL")]
                    public static extern int SNAPI_Init(IntP tr hwend, IntPtr[]
                    DeviceHandles, ref int NumDevices);
                    This basically expects a windows handler, along with a buffer array which
                    it uses to populate with scanners that are currently attached to the
                    system.
                    >
                    I've overriden WndProc, and it's correctly getting the message I'd expect,
                    in this case it's the WM_VERSION message. All I'm trying to do is
                    initially query the scanner for the firmware version as a simple way of
                    exchanging data before I get onto imaging and video!
                    >
                    OnConnect type event does this:
                    int status = 0;
                    status = DriverProxy.SNA PI_SetVersionBu ffer(handle,
                    _versionBuffer, _versionBuffer. Length);
                    status = DriverProxy.SNA PI_TransmitVers ion(handle);
                    _versionBuffer is global StringBuilder, and transmit version tells the
                    scan to please send me the firmware version to the allocated buffer.
                    >
                    In WndProc override:
                    protected override void WndProc(ref Message m)
                    {
                    switch ((uint)m.Msg)
                    {
                    case DriverProxy.WM_ SWVERSION:
                    // should now have a _versionbuffer full of grand stuff
                    FirmwareVersion Label.Text = _versionBuffer. ToString();
                    break;
                    >
                    }
                    Debug.WriteLine If(m.Msg 0x8000 && m.Msg < 0xBFFF, "HIT! " +
                    m.Msg.ToString( ));
                    base.WndProc(re f m);
                    }
                    >
                    Now I've a label that gets the Firmware version text assigned to it, but
                    this is currently blank, and can confirm that the WM_SWVERSION message
                    comes through...
                    >
                    Hope that helps to explain what I'm trying to achieve.
                    Thanks again.
                    Dan.
                    >
                    >
                    "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                    in message news:OadAbZYFIH A.3716@TK2MSFTN GP03.phx.gbl...
                    >Daniel,
                    >>
                    > I was thinking this is a little odd, since the parameter is named
                    >"DeviceHandl e" and not indicative that it is a windows handle. If it is
                    >indeed a windows handle you are passing to the method, then you can
                    >override the WndProc method of the control that contains that windows
                    >handle to look for the message sent to you.
                    >>
                    > You will have to change your API declaration to this:
                    >>
                    >[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                    >public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
                    >IntPtr pData, int max_length);
                    >>
                    > And then call it like this:
                    >>
                    >// dataBuffer need to be accessible by the override of WndProc as well.
                    >dataBuffer = Marshal.AllocHG lobal(dataBuffe rLength);
                    >>
                    >// Make the API call:
                    >SNAPI_SetVersi onBuffer(window Handle, dataBuffer, dataBufferLengt h);
                    >>
                    > Then, in your override of WndProc, in the section that handles the
                    >message to the window:
                    >>
                    >// Get the string.
                    >string data = Marshal.PtrToSt ringAnsi(dataBu ffer);
                    >>
                    >// Free the memory.
                    >Marshal.FreeHG lobal(dataBuffe r);
                    >>
                    >// Work with the string.
                    >>
                    >>
                    >--
                    > - Nicholas Paldino [.NET/C# MVP]
                    > - mvp@spam.guard. caspershouse.co m
                    >>
                    >>
                    >"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                    >news:O3sK%23VY FIHA.3548@TK2MS FTNGP06.phx.gbl ...
                    >>>
                    >>I pass in a handle of the windows into the API as part of an
                    >>initialisatio n call. Could I then just override "WndProc"?
                    >>>
                    >>It's doing the latter, and only sending a message when the parameter has
                    >>been sent to the buffer. When you say "allocate the memory" yourself,
                    >>I'm not sure what you mean. I'll provide the IntPtr parameter, and
                    >>according the API manual, I'll have a global buffer space that I
                    >>register with the API which should be populated with the event call...
                    >>Does that sound feasible?
                    >>>
                    >>Thanks for your help and guidance!
                    >>>
                    >>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                    >>in message news:OovEiMYFIH A.5208@TK2MSFTN GP04.phx.gbl...
                    >>>Daniel,
                    >>>>
                    >>> Yes, there is. You can create a class which implements the
                    >>>IMessageFilt er interface and then call the AddMessageFilte r method on
                    >>>the Application class, passing your implementation. Then, in the
                    >>>PreFilterMes sage method, you would check for your message.
                    >>>>
                    >>> There might be a more subtle issue here. When the function returns,
                    >>>is the string already written to? Or is the string written to when the
                    >>>message is sent to the application? If it is the former, then the code
                    >>>you have is ok. If it is the latter, you will have to change your
                    >>>declaratio n of the unsigned char * parameter to an IntPtr, and allocate
                    >>>the memory that you need yourself.
                    >>>>
                    >>> Then, in the handler for the message, you will have to manually
                    >>>marshal the string to managed code using the static methods on the
                    >>>Marshal class (freeing the memory of course as well).
                    >>>>
                    >>>--
                    >>> - Nicholas Paldino [.NET/C# MVP]
                    >>> - mvp@spam.guard. caspershouse.co m
                    >>>>
                    >>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                    >>>news:u%23iPB KYFIHA.4140@TK2 MSFTNGP03.phx.g bl...
                    >>>>Nicholas,
                    >>>>>
                    >>>>I've just been reading through the API guide, and realised that it
                    >>>>won't pass me back the data in a synchronous manner.
                    >>>>>
                    >>>>To quote:
                    >>>>"A command function returns immediately to the host application...
                    >>>>After the command is processed, by the scanner, the host application
                    >>>>received a Windows message indicating the command was processed. The
                    >>>>host applicaition provides a message handler for the ack from the
                    >>>>connected device."
                    >>>>>
                    >>>>Eeek! In .Net, is there a way to listen for messages? I've worked a
                    >>>>little with message maps, but that was way back and have not see this
                    >>>>sort of basic message handling in .net before...
                    >>>>>
                    >>>>Cheers.
                    >>>>Dan.
                    >>>>>
                    >>>>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                    >>>>wrote in message news:%23Wy5GFYF IHA.5328@TK2MSF TNGP05.phx.gbl. ..
                    >>>>>Daniel,
                    >>>>>>
                    >>>>> Yes, if the API function is going to write to the buffer, then
                    >>>>>passing a StringBuilder will cause the data to be marshaled back to
                    >>>>>you correctly.
                    >>>>>>
                    >>>>>>
                    >>>>>--
                    >>>>> - Nicholas Paldino [.NET/C# MVP]
                    >>>>> - mvp@spam.guard. caspershouse.co m
                    >>>>>>
                    >>>>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in
                    >>>>>message news:%23EkQlBYF IHA.1212@TK2MSF TNGP05.phx.gbl. ..
                    >>>>>>Nichola s,
                    >>>>>>>
                    >>>>>>Excellent , thanks for the prompt reply!
                    >>>>>>>
                    >>>>>>pData is a buffer that I create, then pass into the function to
                    >>>>>>populat e. Does the parameter as a StringBuilder marshall this data
                    >>>>>>correctly ?
                    >>>>>>>
                    >>>>>>Thanks.
                    >>>>>>Dan.
                    >>>>>>>
                    >>>>>>"Nichol as Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                    >>>>>>wrote in message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
                    >>>>>>>Daniel ,
                    >>>>>>>>
                    >>>>>>> Actually, it's not pretty obvious. In C++, long corresponds to
                    >>>>>>>a 32-bit integer, which in C#, is an int. Also, you should declare
                    >>>>>>>how your strings are marshaled in the DllImport attribute.
                    >>>>>>>All-in-all, your declaration should look like this:
                    >>>>>>>>
                    >>>>>>>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                    >>>>>>>public static extern int SNAPI_SetVersio nBuffer(IntPtr
                    >>>>>>>DeviceHa ndle, StringBuilder pData, int max_length);
                    >>>>>>>>
                    >>>>>>> Also, if the pData parameter is not going to be written to by
                    >>>>>>>the API function, you can pass it as a string.
                    >>>>>>>>
                    >>>>>>>>
                    >>>>>>>--
                    >>>>>>> - Nicholas Paldino [.NET/C# MVP]
                    >>>>>>> - mvp@spam.guard. caspershouse.co m
                    >>>>>>>>
                    >>>>>>>>
                    >>>>>>>"Danie l Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in
                    >>>>>>>messag e news:u83rn0XFIH A.1056@TK2MSFTN GP03.phx.gbl...
                    >>>>>>>>Greetin gs!
                    >>>>>>>>>
                    >>>>>>>>I'm trying to call this method in a c# app...
                    >>>>>>>>>
                    >>>>>>>> SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
                    >>>>>>>>DeviceH andle, unsigned char *pData, long max_length);
                    >>>>>>>>>
                    >>>>>>>>So far I've got this:
                    >>>>>>>> [DllImport("Depe ndencies\\SNAPI .DLL")]
                    >>>>>>>> public static extern int SNAPI_SetVersio nBuffer(IntPtr
                    >>>>>>>>DeviceH andle, StringBuilder pData, long max_length);
                    >>>>>>>>>
                    >>>>>>>>Keep getting a PInvokeStackImb alance error and I think it's the
                    >>>>>>>>2nd paramter pData because I've referenced the device handler and
                    >>>>>>>>the long typedef is pretty obvious.
                    >>>>>>>>>
                    >>>>>>>>For the 2nd paramter I've tried the following without success:
                    >>>>>>>> byte[]
                    >>>>>>>> char[]
                    >>>>>>>> string
                    >>>>>>>> StringBuilder
                    >>>>>>>> [MarshalAs(Unman agedType.AnsiBS tr)] string
                    >>>>>>>>>
                    >>>>>>>>HELP!
                    >>>>>>>>Thank s.
                    >>>>>>>>Dan.
                    >>>>>>>>>
                    >>>>>>>>
                    >>>>>>>>
                    >>>>>>>
                    >>>>>>>
                    >>>>>>
                    >>>>>>
                    >>>>>
                    >>>>>
                    >>>>
                    >>>>
                    >>>
                    >>>
                    >>
                    >>
                    >
                    >

                    Comment

                    • Daniel Bass

                      #11
                      Re: PInvoke Marshalling....

                      That's excellent! Thanks for your help.

                      One last question...

                      The wParam is a pointer to a API defined structure (containing a Low DWORD
                      and a High DWORD), how would I cast this back into the same structure I've
                      written in my C# proxy in the WndProc?


                      "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote in
                      message news:eWDNBtYFIH A.5160@TK2MSFTN GP05.phx.gbl...
                      Daniel,
                      >
                      My previous post outlines what you have to do with allocating the
                      buffer.
                      >
                      When you pass a StringBuilder, the P/Invoke layer creates a buffer of
                      unmanaged memory, and passes the pointer to that, populated with the
                      contents of the string builder. Upon return, the P/Invoke layer marshals
                      the information from that unmanaged buffer back into the StringBuilder,
                      and disposes of the pointer.
                      >
                      However, this API is holding onto the pointer, so you have to do the
                      same.
                      >
                      --
                      - Nicholas Paldino [.NET/C# MVP]
                      - mvp@spam.guard. caspershouse.co m
                      >
                      "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                      news:O78SjhYFIH A.4228@TK2MSFTN GP02.phx.gbl...
                      >Well, kind of...
                      >>
                      >A little context may help. I'm writing a front end into a driver for a
                      >USB connected imaging scanner.
                      >>
                      >DeviceHandle is the handle that I keep hold of for the currently
                      >connected device.
                      >>
                      >The first call I make into the API though, is
                      > [DllImport("Depe ndencies\\SNAPI .DLL")]
                      > public static extern int SNAPI_Init(IntP tr hwend, IntPtr[]
                      >DeviceHandle s, ref int NumDevices);
                      >This basically expects a windows handler, along with a buffer array which
                      >it uses to populate with scanners that are currently attached to the
                      >system.
                      >>
                      >I've overriden WndProc, and it's correctly getting the message I'd
                      >expect, in this case it's the WM_VERSION message. All I'm trying to do is
                      >initially query the scanner for the firmware version as a simple way of
                      >exchanging data before I get onto imaging and video!
                      >>
                      >OnConnect type event does this:
                      > int status = 0;
                      > status = DriverProxy.SNA PI_SetVersionBu ffer(handle,
                      >_versionBuffer , _versionBuffer. Length);
                      > status = DriverProxy.SNA PI_TransmitVers ion(handle);
                      >_versionBuff er is global StringBuilder, and transmit version tells the
                      >scan to please send me the firmware version to the allocated buffer.
                      >>
                      >In WndProc override:
                      > protected override void WndProc(ref Message m)
                      > {
                      > switch ((uint)m.Msg)
                      > {
                      > case DriverProxy.WM_ SWVERSION:
                      > // should now have a _versionbuffer full of grand
                      >stuff
                      > FirmwareVersion Label.Text = _versionBuffer. ToString();
                      > break;
                      >>
                      > }
                      > Debug.WriteLine If(m.Msg 0x8000 && m.Msg < 0xBFFF, "HIT! " +
                      >m.Msg.ToString ());
                      > base.WndProc(re f m);
                      > }
                      >>
                      >Now I've a label that gets the Firmware version text assigned to it, but
                      >this is currently blank, and can confirm that the WM_SWVERSION message
                      >comes through...
                      >>
                      >Hope that helps to explain what I'm trying to achieve.
                      >Thanks again.
                      >Dan.
                      >>
                      >>
                      >"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                      >in message news:OadAbZYFIH A.3716@TK2MSFTN GP03.phx.gbl...
                      >>Daniel,
                      >>>
                      >> I was thinking this is a little odd, since the parameter is named
                      >>"DeviceHandle " and not indicative that it is a windows handle. If it is
                      >>indeed a windows handle you are passing to the method, then you can
                      >>override the WndProc method of the control that contains that windows
                      >>handle to look for the message sent to you.
                      >>>
                      >> You will have to change your API declaration to this:
                      >>>
                      >>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                      >>public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
                      >>IntPtr pData, int max_length);
                      >>>
                      >> And then call it like this:
                      >>>
                      >>// dataBuffer need to be accessible by the override of WndProc as well.
                      >>dataBuffer = Marshal.AllocHG lobal(dataBuffe rLength);
                      >>>
                      >>// Make the API call:
                      >>SNAPI_SetVers ionBuffer(windo wHandle, dataBuffer, dataBufferLengt h);
                      >>>
                      >> Then, in your override of WndProc, in the section that handles the
                      >>message to the window:
                      >>>
                      >>// Get the string.
                      >>string data = Marshal.PtrToSt ringAnsi(dataBu ffer);
                      >>>
                      >>// Free the memory.
                      >>Marshal.FreeH Global(dataBuff er);
                      >>>
                      >>// Work with the string.
                      >>>
                      >>>
                      >>--
                      >> - Nicholas Paldino [.NET/C# MVP]
                      >> - mvp@spam.guard. caspershouse.co m
                      >>>
                      >>>
                      >>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                      >>news:O3sK%23V YFIHA.3548@TK2M SFTNGP06.phx.gb l...
                      >>>>
                      >>>I pass in a handle of the windows into the API as part of an
                      >>>initialisati on call. Could I then just override "WndProc"?
                      >>>>
                      >>>It's doing the latter, and only sending a message when the parameter
                      >>>has been sent to the buffer. When you say "allocate the memory"
                      >>>yourself, I'm not sure what you mean. I'll provide the IntPtr
                      >>>parameter, and according the API manual, I'll have a global buffer
                      >>>space that I register with the API which should be populated with the
                      >>>event call... Does that sound feasible?
                      >>>>
                      >>>Thanks for your help and guidance!
                      >>>>
                      >>>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                      >>>wrote in message news:OovEiMYFIH A.5208@TK2MSFTN GP04.phx.gbl...
                      >>>>Daniel,
                      >>>>>
                      >>>> Yes, there is. You can create a class which implements the
                      >>>>IMessageFil ter interface and then call the AddMessageFilte r method on
                      >>>>the Application class, passing your implementation. Then, in the
                      >>>>PreFilterMe ssage method, you would check for your message.
                      >>>>>
                      >>>> There might be a more subtle issue here. When the function
                      >>>>returns, is the string already written to? Or is the string written
                      >>>>to when the message is sent to the application? If it is the former,
                      >>>>then the code you have is ok. If it is the latter, you will have to
                      >>>>change your declaration of the unsigned char * parameter to an IntPtr,
                      >>>>and allocate the memory that you need yourself.
                      >>>>>
                      >>>> Then, in the handler for the message, you will have to manually
                      >>>>marshal the string to managed code using the static methods on the
                      >>>>Marshal class (freeing the memory of course as well).
                      >>>>>
                      >>>>--
                      >>>> - Nicholas Paldino [.NET/C# MVP]
                      >>>> - mvp@spam.guard. caspershouse.co m
                      >>>>>
                      >>>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                      >>>>news:u%23iP BKYFIHA.4140@TK 2MSFTNGP03.phx. gbl...
                      >>>>>Nicholas ,
                      >>>>>>
                      >>>>>I've just been reading through the API guide, and realised that it
                      >>>>>won't pass me back the data in a synchronous manner.
                      >>>>>>
                      >>>>>To quote:
                      >>>>>"A command function returns immediately to the host application...
                      >>>>>After the command is processed, by the scanner, the host application
                      >>>>>received a Windows message indicating the command was processed. The
                      >>>>>host applicaition provides a message handler for the ack from the
                      >>>>>connecte d device."
                      >>>>>>
                      >>>>>Eeek! In .Net, is there a way to listen for messages? I've worked a
                      >>>>>little with message maps, but that was way back and have not see this
                      >>>>>sort of basic message handling in .net before...
                      >>>>>>
                      >>>>>Cheers.
                      >>>>>Dan.
                      >>>>>>
                      >>>>>"Nichola s Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                      >>>>>wrote in message news:%23Wy5GFYF IHA.5328@TK2MSF TNGP05.phx.gbl. ..
                      >>>>>>Daniel,
                      >>>>>>>
                      >>>>>> Yes, if the API function is going to write to the buffer, then
                      >>>>>>passing a StringBuilder will cause the data to be marshaled back to
                      >>>>>>you correctly.
                      >>>>>>>
                      >>>>>>>
                      >>>>>>--
                      >>>>>> - Nicholas Paldino [.NET/C# MVP]
                      >>>>>> - mvp@spam.guard. caspershouse.co m
                      >>>>>>>
                      >>>>>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in
                      >>>>>>message news:%23EkQlBYF IHA.1212@TK2MSF TNGP05.phx.gbl. ..
                      >>>>>>>Nicholas ,
                      >>>>>>>>
                      >>>>>>>Excellen t, thanks for the prompt reply!
                      >>>>>>>>
                      >>>>>>>pData is a buffer that I create, then pass into the function to
                      >>>>>>>populate . Does the parameter as a StringBuilder marshall this data
                      >>>>>>>correctl y?
                      >>>>>>>>
                      >>>>>>>Thanks .
                      >>>>>>>Dan.
                      >>>>>>>>
                      >>>>>>>"Nichola s Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                      >>>>>>>wrote in message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
                      >>>>>>>>Danie l,
                      >>>>>>>>>
                      >>>>>>>> Actually, it's not pretty obvious. In C++, long corresponds to
                      >>>>>>>>a 32-bit integer, which in C#, is an int. Also, you should
                      >>>>>>>>decla re how your strings are marshaled in the DllImport attribute.
                      >>>>>>>>All-in-all, your declaration should look like this:
                      >>>>>>>>>
                      >>>>>>>>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                      >>>>>>>>publi c static extern int SNAPI_SetVersio nBuffer(IntPtr
                      >>>>>>>>DeviceH andle, StringBuilder pData, int max_length);
                      >>>>>>>>>
                      >>>>>>>> Also, if the pData parameter is not going to be written to by
                      >>>>>>>>the API function, you can pass it as a string.
                      >>>>>>>>>
                      >>>>>>>>>
                      >>>>>>>>--
                      >>>>>>>> - Nicholas Paldino [.NET/C# MVP]
                      >>>>>>>> - mvp@spam.guard. caspershouse.co m
                      >>>>>>>>>
                      >>>>>>>>>
                      >>>>>>>>"Dani el Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in
                      >>>>>>>>messa ge news:u83rn0XFIH A.1056@TK2MSFTN GP03.phx.gbl...
                      >>>>>>>>>Greeti ngs!
                      >>>>>>>>>>
                      >>>>>>>>>I'm trying to call this method in a c# app...
                      >>>>>>>>>>
                      >>>>>>>>> SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
                      >>>>>>>>>Device Handle, unsigned char *pData, long max_length);
                      >>>>>>>>>>
                      >>>>>>>>>So far I've got this:
                      >>>>>>>>> [DllImport("Depe ndencies\\SNAPI .DLL")]
                      >>>>>>>>> public static extern int SNAPI_SetVersio nBuffer(IntPtr
                      >>>>>>>>>Device Handle, StringBuilder pData, long max_length);
                      >>>>>>>>>>
                      >>>>>>>>>Keep getting a PInvokeStackImb alance error and I think it's the
                      >>>>>>>>>2nd paramter pData because I've referenced the device handler and
                      >>>>>>>>>the long typedef is pretty obvious.
                      >>>>>>>>>>
                      >>>>>>>>>For the 2nd paramter I've tried the following without success:
                      >>>>>>>>> byte[]
                      >>>>>>>>> char[]
                      >>>>>>>>> string
                      >>>>>>>>> StringBuilder
                      >>>>>>>>> [MarshalAs(Unman agedType.AnsiBS tr)] string
                      >>>>>>>>>>
                      >>>>>>>>>HELP !
                      >>>>>>>>>Thanks .
                      >>>>>>>>>Dan.
                      >>>>>>>>>>
                      >>>>>>>>>
                      >>>>>>>>>
                      >>>>>>>>
                      >>>>>>>>
                      >>>>>>>
                      >>>>>>>
                      >>>>>>
                      >>>>>>
                      >>>>>
                      >>>>>
                      >>>>
                      >>>>
                      >>>
                      >>>
                      >>
                      >>
                      >
                      >

                      Comment

                      • Nicholas Paldino [.NET/C# MVP]

                        #12
                        Re: PInvoke Marshalling....

                        Daniel,

                        Can you provide a delcaration for the structure in C#? Or C++? If you
                        have a structure declaration in C#, you can call the static PtrToStructure
                        method on the Marshal class to marshal the values from the memory pointed to
                        by the unmanaged pointer to managed code.


                        --
                        - Nicholas Paldino [.NET/C# MVP]
                        - mvp@spam.guard. caspershouse.co m

                        "Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                        news:OzWx9OZFIH A.4748@TK2MSFTN GP06.phx.gbl...
                        That's excellent! Thanks for your help.
                        >
                        One last question...
                        >
                        The wParam is a pointer to a API defined structure (containing a Low DWORD
                        and a High DWORD), how would I cast this back into the same structure I've
                        written in my C# proxy in the WndProc?
                        >
                        >
                        "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                        in message news:eWDNBtYFIH A.5160@TK2MSFTN GP05.phx.gbl...
                        >Daniel,
                        >>
                        > My previous post outlines what you have to do with allocating the
                        >buffer.
                        >>
                        > When you pass a StringBuilder, the P/Invoke layer creates a buffer of
                        >unmanaged memory, and passes the pointer to that, populated with the
                        >contents of the string builder. Upon return, the P/Invoke layer marshals
                        >the information from that unmanaged buffer back into the StringBuilder,
                        >and disposes of the pointer.
                        >>
                        > However, this API is holding onto the pointer, so you have to do the
                        >same.
                        >>
                        >--
                        > - Nicholas Paldino [.NET/C# MVP]
                        > - mvp@spam.guard. caspershouse.co m
                        >>
                        >"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                        >news:O78SjhYFI HA.4228@TK2MSFT NGP02.phx.gbl.. .
                        >>Well, kind of...
                        >>>
                        >>A little context may help. I'm writing a front end into a driver for a
                        >>USB connected imaging scanner.
                        >>>
                        >>DeviceHandl e is the handle that I keep hold of for the currently
                        >>connected device.
                        >>>
                        >>The first call I make into the API though, is
                        >> [DllImport("Depe ndencies\\SNAPI .DLL")]
                        >> public static extern int SNAPI_Init(IntP tr hwend, IntPtr[]
                        >>DeviceHandles , ref int NumDevices);
                        >>This basically expects a windows handler, along with a buffer array
                        >>which it uses to populate with scanners that are currently attached to
                        >>the system.
                        >>>
                        >>I've overriden WndProc, and it's correctly getting the message I'd
                        >>expect, in this case it's the WM_VERSION message. All I'm trying to do
                        >>is initially query the scanner for the firmware version as a simple way
                        >>of exchanging data before I get onto imaging and video!
                        >>>
                        >>OnConnect type event does this:
                        >> int status = 0;
                        >> status = DriverProxy.SNA PI_SetVersionBu ffer(handle,
                        >>_versionBuffe r, _versionBuffer. Length);
                        >> status = DriverProxy.SNA PI_TransmitVers ion(handle);
                        >>_versionBuffe r is global StringBuilder, and transmit version tells the
                        >>scan to please send me the firmware version to the allocated buffer.
                        >>>
                        >>In WndProc override:
                        >> protected override void WndProc(ref Message m)
                        >> {
                        >> switch ((uint)m.Msg)
                        >> {
                        >> case DriverProxy.WM_ SWVERSION:
                        >> // should now have a _versionbuffer full of grand
                        >>stuff
                        >> FirmwareVersion Label.Text =
                        >>_versionBuffe r.ToString();
                        >> break;
                        >>>
                        >> }
                        >> Debug.WriteLine If(m.Msg 0x8000 && m.Msg < 0xBFFF, "HIT! " +
                        >>m.Msg.ToStrin g());
                        >> base.WndProc(re f m);
                        >> }
                        >>>
                        >>Now I've a label that gets the Firmware version text assigned to it, but
                        >>this is currently blank, and can confirm that the WM_SWVERSION message
                        >>comes through...
                        >>>
                        >>Hope that helps to explain what I'm trying to achieve.
                        >>Thanks again.
                        >>Dan.
                        >>>
                        >>>
                        >>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                        >>in message news:OadAbZYFIH A.3716@TK2MSFTN GP03.phx.gbl...
                        >>>Daniel,
                        >>>>
                        >>> I was thinking this is a little odd, since the parameter is named
                        >>>"DeviceHandl e" and not indicative that it is a windows handle. If it
                        >>>is indeed a windows handle you are passing to the method, then you can
                        >>>override the WndProc method of the control that contains that windows
                        >>>handle to look for the message sent to you.
                        >>>>
                        >>> You will have to change your API declaration to this:
                        >>>>
                        >>>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                        >>>public static extern int SNAPI_SetVersio nBuffer(IntPtr DeviceHandle,
                        >>>IntPtr pData, int max_length);
                        >>>>
                        >>> And then call it like this:
                        >>>>
                        >>>// dataBuffer need to be accessible by the override of WndProc as well.
                        >>>dataBuffer = Marshal.AllocHG lobal(dataBuffe rLength);
                        >>>>
                        >>>// Make the API call:
                        >>>SNAPI_SetVer sionBuffer(wind owHandle, dataBuffer, dataBufferLengt h);
                        >>>>
                        >>> Then, in your override of WndProc, in the section that handles the
                        >>>message to the window:
                        >>>>
                        >>>// Get the string.
                        >>>string data = Marshal.PtrToSt ringAnsi(dataBu ffer);
                        >>>>
                        >>>// Free the memory.
                        >>>Marshal.Free HGlobal(dataBuf fer);
                        >>>>
                        >>>// Work with the string.
                        >>>>
                        >>>>
                        >>>--
                        >>> - Nicholas Paldino [.NET/C# MVP]
                        >>> - mvp@spam.guard. caspershouse.co m
                        >>>>
                        >>>>
                        >>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in message
                        >>>news:O3sK%23 VYFIHA.3548@TK2 MSFTNGP06.phx.g bl...
                        >>>>>
                        >>>>I pass in a handle of the windows into the API as part of an
                        >>>>initialisat ion call. Could I then just override "WndProc"?
                        >>>>>
                        >>>>It's doing the latter, and only sending a message when the parameter
                        >>>>has been sent to the buffer. When you say "allocate the memory"
                        >>>>yourself, I'm not sure what you mean. I'll provide the IntPtr
                        >>>>parameter , and according the API manual, I'll have a global buffer
                        >>>>space that I register with the API which should be populated with the
                        >>>>event call... Does that sound feasible?
                        >>>>>
                        >>>>Thanks for your help and guidance!
                        >>>>>
                        >>>>"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                        >>>>wrote in message news:OovEiMYFIH A.5208@TK2MSFTN GP04.phx.gbl...
                        >>>>>Daniel,
                        >>>>>>
                        >>>>> Yes, there is. You can create a class which implements the
                        >>>>>IMessageFi lter interface and then call the AddMessageFilte r method on
                        >>>>>the Application class, passing your implementation. Then, in the
                        >>>>>PreFilterM essage method, you would check for your message.
                        >>>>>>
                        >>>>> There might be a more subtle issue here. When the function
                        >>>>>returns, is the string already written to? Or is the string written
                        >>>>>to when the message is sent to the application? If it is the former,
                        >>>>>then the code you have is ok. If it is the latter, you will have to
                        >>>>>change your declaration of the unsigned char * parameter to an
                        >>>>>IntPtr, and allocate the memory that you need yourself.
                        >>>>>>
                        >>>>> Then, in the handler for the message, you will have to manually
                        >>>>>marshal the string to managed code using the static methods on the
                        >>>>>Marshal class (freeing the memory of course as well).
                        >>>>>>
                        >>>>>--
                        >>>>> - Nicholas Paldino [.NET/C# MVP]
                        >>>>> - mvp@spam.guard. caspershouse.co m
                        >>>>>>
                        >>>>>"Daniel Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in
                        >>>>>message news:u%23iPBKYF IHA.4140@TK2MSF TNGP03.phx.gbl. ..
                        >>>>>>Nichola s,
                        >>>>>>>
                        >>>>>>I've just been reading through the API guide, and realised that it
                        >>>>>>won't pass me back the data in a synchronous manner.
                        >>>>>>>
                        >>>>>>To quote:
                        >>>>>>"A command function returns immediately to the host application...
                        >>>>>>After the command is processed, by the scanner, the host application
                        >>>>>>receive d a Windows message indicating the command was processed. The
                        >>>>>>host applicaition provides a message handler for the ack from the
                        >>>>>>connect ed device."
                        >>>>>>>
                        >>>>>>Eeek! In .Net, is there a way to listen for messages? I've worked a
                        >>>>>>little with message maps, but that was way back and have not see
                        >>>>>>this sort of basic message handling in .net before...
                        >>>>>>>
                        >>>>>>Cheers.
                        >>>>>>Dan.
                        >>>>>>>
                        >>>>>>"Nichol as Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                        >>>>>>wrote in message news:%23Wy5GFYF IHA.5328@TK2MSF TNGP05.phx.gbl. ..
                        >>>>>>>Daniel ,
                        >>>>>>>>
                        >>>>>>> Yes, if the API function is going to write to the buffer, then
                        >>>>>>>passin g a StringBuilder will cause the data to be marshaled back to
                        >>>>>>>you correctly.
                        >>>>>>>>
                        >>>>>>>>
                        >>>>>>>--
                        >>>>>>> - Nicholas Paldino [.NET/C# MVP]
                        >>>>>>> - mvp@spam.guard. caspershouse.co m
                        >>>>>>>>
                        >>>>>>>"Danie l Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in
                        >>>>>>>messag e news:%23EkQlBYF IHA.1212@TK2MSF TNGP05.phx.gbl. ..
                        >>>>>>>>Nichola s,
                        >>>>>>>>>
                        >>>>>>>>Excelle nt, thanks for the prompt reply!
                        >>>>>>>>>
                        >>>>>>>>pData is a buffer that I create, then pass into the function to
                        >>>>>>>>populat e. Does the parameter as a StringBuilder marshall this data
                        >>>>>>>>correct ly?
                        >>>>>>>>>
                        >>>>>>>>Thank s.
                        >>>>>>>>Dan.
                        >>>>>>>>>
                        >>>>>>>>"Nichol as Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                        >>>>>>>>wrote in message news:ecx5T6XFIH A.280@TK2MSFTNG P03.phx.gbl...
                        >>>>>>>>>Daniel ,
                        >>>>>>>>>>
                        >>>>>>>>> Actually, it's not pretty obvious. In C++, long corresponds
                        >>>>>>>>>to a 32-bit integer, which in C#, is an int. Also, you should
                        >>>>>>>>>declar e how your strings are marshaled in the DllImport
                        >>>>>>>>>attrib ute. All-in-all, your declaration should look like this:
                        >>>>>>>>>>
                        >>>>>>>>>[DllImport("Depe ndencies\\SNAPI .DLL", CharSet=CharSet .Ansi)]
                        >>>>>>>>>publ ic static extern int SNAPI_SetVersio nBuffer(IntPtr
                        >>>>>>>>>Device Handle, StringBuilder pData, int max_length);
                        >>>>>>>>>>
                        >>>>>>>>> Also, if the pData parameter is not going to be written to by
                        >>>>>>>>>the API function, you can pass it as a string.
                        >>>>>>>>>>
                        >>>>>>>>>>
                        >>>>>>>>>--
                        >>>>>>>>> - Nicholas Paldino [.NET/C# MVP]
                        >>>>>>>>> - mvp@spam.guard. caspershouse.co m
                        >>>>>>>>>>
                        >>>>>>>>>>
                        >>>>>>>>>"Danie l Bass" <danREMOVEbass@ blueCAPSbottle. comFIRSTwrote in
                        >>>>>>>>>messag e news:u83rn0XFIH A.1056@TK2MSFTN GP03.phx.gbl...
                        >>>>>>>>>>Greet ings!
                        >>>>>>>>>>>
                        >>>>>>>>>>I'm trying to call this method in a c# app...
                        >>>>>>>>>>>
                        >>>>>>>>>> SNAPIDLL_API int __stdcall SNAPI_SetCapabi litiesBuffer(HA NDLE
                        >>>>>>>>>>Devic eHandle, unsigned char *pData, long max_length);
                        >>>>>>>>>>>
                        >>>>>>>>>>So far I've got this:
                        >>>>>>>>>> [DllImport("Depe ndencies\\SNAPI .DLL")]
                        >>>>>>>>>> public static extern int SNAPI_SetVersio nBuffer(IntPtr
                        >>>>>>>>>>Devic eHandle, StringBuilder pData, long max_length);
                        >>>>>>>>>>>
                        >>>>>>>>>>Kee p getting a PInvokeStackImb alance error and I think it's the
                        >>>>>>>>>>2nd paramter pData because I've referenced the device handler
                        >>>>>>>>>>and the long typedef is pretty obvious.
                        >>>>>>>>>>>
                        >>>>>>>>>>For the 2nd paramter I've tried the following without success:
                        >>>>>>>>>> byte[]
                        >>>>>>>>>> char[]
                        >>>>>>>>>> string
                        >>>>>>>>>> StringBuilder
                        >>>>>>>>>> [MarshalAs(Unman agedType.AnsiBS tr)] string
                        >>>>>>>>>>>
                        >>>>>>>>>>HEL P!
                        >>>>>>>>>>Thank s.
                        >>>>>>>>>>Dan .
                        >>>>>>>>>>>
                        >>>>>>>>>>
                        >>>>>>>>>>
                        >>>>>>>>>
                        >>>>>>>>>
                        >>>>>>>>
                        >>>>>>>>
                        >>>>>>>
                        >>>>>>>
                        >>>>>>
                        >>>>>>
                        >>>>>
                        >>>>>
                        >>>>
                        >>>>
                        >>>
                        >>>
                        >>
                        >>
                        >
                        >

                        Comment

                        Working...