Calling a Windows API Function

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Stewart Berman

    Calling a Windows API Function

    I am trying to develop a wrapper class for the Windows API functions in Visual Studio 2008:
    GetOpenFileName
    GetSaveFileName

    I put together a starter class:

    using System;
    using System.Collecti ons.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime. InteropServices ;

    [System.Runtime. InteropServices .StructLayout(L ayoutKind.Seque ntial, CharSet=CharSet .Auto)]
    public class OpenFileName
    {
    int lstructSize;
    int hwndOwner;
    int hInstance;
    string lpstrFilter = null;
    string lpstrCustomFilt er = null;
    int lMaxCustomFilte r;
    int lFilterIndex;
    string lpstrFile = null;
    int lMaxFile = 0;
    string lpstrFiteTitle = null;
    int lMaxFileTitle = 0;
    string lpstrInitialDir = null;
    string lpstrTitle = null;
    int lFlags;
    ushort nFileOffset;
    ushort nFileExtension;
    string lpstrDefExt = null;
    int lCustData;
    int lpfHook;
    int lpTemplateName;
    }

    [DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
    static extern bool GetOpenFileName ([In, Out] OpenFileName ofn);
    [DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
    static extern bool GetSaveFileName ([In, Out] OpenFileName ofn);

    namespace myNameSpace
    {
    class GetFileNames
    {
    }
    }

    The compilier complains:

    Error 1 Expected class, delegate, enum, interface, or struct
    E:\myNameSpace\ myNameSpace\Get FileNames.cs 33 15 myNameSpace
    Error 2 Expected class, delegate, enum, interface, or struct
    E:\myNameSpace\ myNameSpace\Get FileNames.cs 33 46 myNameSpace
    Error 3 Expected class, delegate, enum, interface, or struct
    E:\myNameSpace\ myNameSpace\Get FileNames.cs 35 15 myNameSpace
    Error 4 Expected class, delegate, enum, interface, or struct
    E:\myNameSpace\ myNameSpace\Get FileNames.cs 35 46 myNameSpace
    Error 5 The modifier 'extern' is not valid for this item
    E:\myNameSpace\ myNameSpace\Get FileNames.cs 32 70 myNameSpace
    Error 6 The modifier 'extern' is not valid for this item
    E:\myNameSpace\ myNameSpace\Get FileNames.cs 34 70 myNameSpace

    Errors 1 and 3 refer to the bool.qualifier
    Errors 2 and 4 refer to the OpenFileName qualifier
    Errors 5 and 6 refer to the extern

    The DLLImport statements were originally retrieved from pinvoke.net using the PInvoke.net add-in.
    They were modified to use the fully qualified System.Runtime. InteropServices .DllImport reference.

    What am I doing wrong?
  • Rudy Velthuis

    #2
    Re: Calling a Windows API Function

    Stewart Berman wrote:
    I put together a starter class:
    >
    using System;
    using System.Collecti ons.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime. InteropServices ;
    >
    [System.Runtime. InteropServices .StructLayout(L ayoutKind.Seque ntial,
    CharSet=CharSet .Auto)] public class OpenFileName
    {
    int lstructSize;
    int hwndOwner;
    int hInstance;
    string lpstrFilter = null;
    string lpstrCustomFilt er = null;
    int lMaxCustomFilte r;
    int lFilterIndex;
    string lpstrFile = null;
    int lMaxFile = 0;
    string lpstrFiteTitle = null;
    int lMaxFileTitle = 0;
    string lpstrInitialDir = null;
    string lpstrTitle = null;
    int lFlags;
    ushort nFileOffset;
    ushort nFileExtension;
    string lpstrDefExt = null;
    int lCustData;
    int lpfHook;
    int lpTemplateName;
    }
    >
    [DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
    static extern bool GetOpenFileName ([In, Out] OpenFileName ofn);
    [DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
    static extern bool GetSaveFileName ([In, Out] OpenFileName ofn);
    >
    What am I doing wrong?
    Your static extern etc. functions should be declared as static members
    of a class (even if, in reality, they are extern). And I would really
    make OpenFileName a struct instead, passing it by reference.

    --
    Rudy Velthuis http://rvelthuis.de

    "There are only two tragedies in life: one is not getting what
    one wants, and the other is getting it."
    -- Oscar Wilde (1854-1900)

    Comment

    • Rudy Velthuis

      #3
      Re: Calling a Windows API Function

      Stewart Berman wrote:
      I am trying to develop a wrapper class for the Windows API functions
      in Visual Studio 2008:
      FWIW:





      --
      Rudy Velthuis http://rvelthuis.de

      "Each problem that I solved became a rule which served afterwards
      to solve other problems."
      -- Rene Descartes (1596-1650), "Discours de la Methode"

      Comment

      • Mark Rae [MVP]

        #4
        Re: Calling a Windows API Function

        "Stewart Berman" <saberman@nospa m.nospamwrote in message
        news:mc0fh45hch 7oa8c15mhp3pinn bqmrbvdui@4ax.c om...
        >I am trying to develop a wrapper class for the Windows API functions in
        >Visual Studio 2008:
        GetOpenFileName
        GetSaveFileName
        Have you seen this:?



        --
        Mark Rae
        ASP.NET MVP


        Comment

        • Stewart Berman

          #5
          Re: Calling a Windows API Function

          The definition you pointed to is:
          [DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
          static extern bool GetOpenFileName ([In, Out] OpenFileName ofn);

          Which is what I had as I got it from pinvoke.net:
          [DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
          static extern bool GetOpenFileName ([In, Out] OpenFileName ofn);

          Am I missing something?

          "Rudy Velthuis" <newsgroups@rve lthuis.dewrote:
          >Stewart Berman wrote:
          >
          >I am trying to develop a wrapper class for the Windows API functions
          >in Visual Studio 2008:
          >
          >FWIW:
          >
          >http://pinvoke.net/default.aspx/comd...nFileName.html
          >http://pinvoke.net/default.aspx/comd...eFileName.html

          Comment

          • Stewart Berman

            #6
            Re: Calling a Windows API Function

            >Your static extern etc. functions should be declared as static members
            >of a class (even if, in reality, they are extern).
            I am new to C# and do not understand your suggestions. Can you please provide a link to code?
            And I would really
            >make OpenFileName a struct instead, passing it by reference.
            My limited understanding is that the only difference between a class and a structure is that a class
            is allocated in the heap and passed by reference while a structure is allocated on the stack and
            passed by either value or reference. I have always thought that the stack should be limited to
            simple arguments passed by value and pointers to complex structures. The OpenFileName structure
            seems a bit much to put on the stack. However, I am new to C# and maybe a bit confused.

            Is that another difference between a class and a stack?

            "Rudy Velthuis" <newsgroups@rve lthuis.dewrote:
            >Stewart Berman wrote:
            >
            >I put together a starter class:
            >>
            >using System;
            >using System.Collecti ons.Generic;
            >using System.Linq;
            >using System.Text;
            >using System.Runtime. InteropServices ;
            >>
            >[System.Runtime. InteropServices .StructLayout(L ayoutKind.Seque ntial,
            >CharSet=CharSe t.Auto)] public class OpenFileName
            >{
            > int lstructSize;
            > int hwndOwner;
            > int hInstance;
            > string lpstrFilter = null;
            > string lpstrCustomFilt er = null;
            > int lMaxCustomFilte r;
            > int lFilterIndex;
            > string lpstrFile = null;
            > int lMaxFile = 0;
            > string lpstrFiteTitle = null;
            > int lMaxFileTitle = 0;
            > string lpstrInitialDir = null;
            > string lpstrTitle = null;
            > int lFlags;
            > ushort nFileOffset;
            > ushort nFileExtension;
            > string lpstrDefExt = null;
            > int lCustData;
            > int lpfHook;
            > int lpTemplateName;
            >}
            >>
            >[DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
            >static extern bool GetOpenFileName ([In, Out] OpenFileName ofn);
            >[DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
            >static extern bool GetSaveFileName ([In, Out] OpenFileName ofn);
            >>
            >What am I doing wrong?
            >
            >Your static extern etc. functions should be declared as static members
            >of a class (even if, in reality, they are extern). And I would really
            >make OpenFileName a struct instead, passing it by reference.

            Comment

            • Stewart Berman

              #7
              Re: Calling a Windows API Function

              No. I don't take free trials unless I actually believe the site will be worth paying for.

              On Mon, 10 Nov 2008 01:48:45 -0000, you wrote:

              "Mark Rae [MVP]" <mark@markNOSPA Mrae.netwrote:
              >"Stewart Berman" <saberman@nospa m.nospamwrote in message
              >news:mc0fh45hc h7oa8c15mhp3pin nbqmrbvdui@4ax. com...
              >
              >>I am trying to develop a wrapper class for the Windows API functions in
              >>Visual Studio 2008:
              >GetOpenFileNam e
              >GetSaveFileNam e
              >
              >Have you seen this:?
              >http://www.experts-exchange.com/Prog..._21017042.html

              Comment

              • Rudy Velthuis

                #8
                Re: Calling a Windows API Function

                Stewart Berman wrote:
                The definition you pointed to is:
                [DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
                static extern bool GetOpenFileName ([In, Out] OpenFileName ofn);
                >
                Which is what I had as I got it from pinvoke.net:
                [DllImport("comd lg32.dll", SetLastError=tr ue, CharSet = CharSet.Auto)]
                static extern bool GetOpenFileName ([In, Out] OpenFileName ofn);
                >
                Am I missing something?
                That in the example (OK, it is VB, but I assume you can read that) it
                is part of a class.


                --
                Rudy Velthuis http://rvelthuis.de

                "I've always wanted to be somebody, but I should have been
                more specific." -- George Carlin

                Comment

                • Rudy Velthuis

                  #9
                  Re: Calling a Windows API Function

                  Stewart Berman wrote:
                  Your static extern etc. functions should be declared as static
                  members of a class (even if, in reality, they are extern).
                  >
                  I am new to C# and do not understand your suggestions. Can you
                  please provide a link to code?
                  >
                  And I would really
                  make OpenFileName a struct instead, passing it by reference.
                  >
                  My limited understanding is that the only difference between a class
                  and a structure is that a class is allocated in the heap and passed
                  by reference while a structure is allocated on the stack and passed
                  by either value or reference. I have always thought that the stack
                  should be limited to simple arguments passed by value and pointers to
                  complex structures. The OpenFileName structure seems a bit much to
                  put on the stack. However, I am new to C# and maybe a bit confused.
                  >
                  Is that another difference between a class and a stack?
                  >
                  "Rudy Velthuis" <newsgroups@rve lthuis.dewrote:
                  >
                  Stewart Berman wrote:
                  I put together a starter class:
                  >
                  using System;
                  using System.Collecti ons.Generic;
                  using System.Linq;
                  using System.Text;
                  using System.Runtime. InteropServices ;
                  >
                  [System.Runtime. InteropServices .StructLayout(L ayoutKind.Seque ntial,
                  CharSet=CharSet .Auto)] public class OpenFileName
                  {
                  Make all members public:
                  public int lstructSize;
                  public int hwndOwner;
                  public int hInstance;
                  public string lpstrFilter = null;
                  public string lpstrCustomFilt er = null;
                  public int lMaxCustomFilte r;
                  public int lFilterIndex;
                  public string lpstrFile = null;
                  etc...

                  Like I said, they should be static functions of a class:

                  public class APILib
                  {
                  [DllImport("comd lg32.dll", SetLastError=tr ue,
                  CharSet = CharSet.Auto)]
                  static extern bool GetOpenFileName ([In, Out] OpenFileName ofn);
                  [DllImport("comd lg32.dll", SetLastError=tr ue,
                  CharSet = CharSet.Auto)]
                  static extern bool GetSaveFileName ([In, Out]
                  OpenFileName ofn);
                  }

                  Now you can use them like below:

                  OpenFileName ofn = new OpenFileName();
                  ofn.structSize = Marshal.SizeOf( ofn);
                  ofn.filter = filter;
                  ofn.file = new string(new Char[256] {});
                  ofn.maxFile = ofn.file.Length ;

                  // etc...

                  if (APILib.GetOpen FileName(ofn))
                  {
                  // get data from ofn
                  }


                  --
                  Rudy Velthuis http://rvelthuis.de

                  "Maybe this world is another planet's Hell."
                  -- Aldous Huxley (1894-1963)

                  Comment

                  • Family Tree Mike

                    #10
                    Re: Calling a Windows API Function

                    I agree with you, in particular about that site.

                    "Stewart Berman" <saberman@nospa m.nospamwrote in message
                    news:upafh4lrlv ouip4s5076u1e92 0s3s5jc07@4ax.c om...
                    No. I don't take free trials unless I actually believe the site will be
                    worth paying for.
                    >

                    Comment

                    • Stewart Berman

                      #11
                      Re: Calling a Windows API Function

                      "Rudy Velthuis" <newsgroups@rve lthuis.dewrote:
                      >Stewart Berman wrote:
                      >
                      Your static extern etc. functions should be declared as static
                      members of a class (even if, in reality, they are extern).
                      >>
                      >I am new to C# and do not understand your suggestions. Can you
                      >please provide a link to code?
                      >>
                      And I would really
                      make OpenFileName a struct instead, passing it by reference.
                      >>
                      >My limited understanding is that the only difference between a class
                      >and a structure is that a class is allocated in the heap and passed
                      >by reference while a structure is allocated on the stack and passed
                      >by either value or reference. I have always thought that the stack
                      >should be limited to simple arguments passed by value and pointers to
                      >complex structures. The OpenFileName structure seems a bit much to
                      >put on the stack. However, I am new to C# and maybe a bit confused.
                      >>
                      >Is that another difference between a class and a stack?
                      >>
                      >"Rudy Velthuis" <newsgroups@rve lthuis.dewrote:
                      >>
                      Stewart Berman wrote:
                      >
                      >I put together a starter class:
                      >>
                      >using System;
                      >using System.Collecti ons.Generic;
                      >using System.Linq;
                      >using System.Text;
                      >using System.Runtime. InteropServices ;
                      >>
                      >[System.Runtime. InteropServices .StructLayout(L ayoutKind.Seque ntial,
                      >CharSet=CharSe t.Auto)] public class OpenFileName
                      >{
                      >
                      >Make all members public:
                      >
                      > public int lstructSize;
                      > public int hwndOwner;
                      > public int hInstance;
                      > public string lpstrFilter = null;
                      > public string lpstrCustomFilt er = null;
                      > public int lMaxCustomFilte r;
                      > public int lFilterIndex;
                      > public string lpstrFile = null;
                      >
                      >etc...
                      >
                      >Like I said, they should be static functions of a class:
                      >
                      public class APILib
                      {
                      [DllImport("comd lg32.dll", SetLastError=tr ue,
                      CharSet = CharSet.Auto)]
                      static extern bool GetOpenFileName ([In, Out] OpenFileName ofn);
                      [DllImport("comd lg32.dll", SetLastError=tr ue,
                      CharSet = CharSet.Auto)]
                      static extern bool GetSaveFileName ([In, Out]
                      OpenFileName ofn);
                      }
                      >
                      >Now you can use them like below:
                      >
                      OpenFileName ofn = new OpenFileName();
                      ofn.structSize = Marshal.SizeOf( ofn);
                      ofn.filter = filter;
                      ofn.file = new string(new Char[256] {});
                      ofn.maxFile = ofn.file.Length ;
                      >
                      // etc...
                      >
                      if (APILib.GetOpen FileName(ofn))
                      {
                      // get data from ofn
                      }
                      >
                      I assume the need to imbed the imports in a class is due to the dot net framework. I don't
                      understand the need to make the members of the OpenFileName class public. They will only be
                      referred to with the code that instantiated the class. Why do they need to be public?

                      Comment

                      • Peter Duniho

                        #12
                        Re: Calling a Windows API Function

                        On Sun, 09 Nov 2008 20:05:14 -0800, Stewart Berman
                        <saberman@nospa m.nospamwrote:
                        [...]
                        I assume the need to imbed the imports in a class is due to the dot net
                        framework. I don't
                        understand the need to make the members of the OpenFileName class
                        public. They will only be
                        referred to with the code that instantiated the class. Why do they need
                        to be public?
                        All due respect, your messages in this thread suggest that you may not
                        really understand C# well enough to effectively use a more advanced
                        feature like p/invoke. Rather than run the risk of engaging in a
                        variation of "cargo cult programming"
                        (http://en.wikipedia.org/wiki/Cargo_cult_programming) in which you engage
                        in canned rituals to achieve certain goals without really understanding
                        what's behind those rituals, you should probably spend more time learning
                        the basics before moving on to the more complicated things.

                        Practically all of these questions are simply basic rules that are part of
                        the C# language, fundamental to all class design. They aren't even all
                        that unique to C#, as they are shared in some form by other
                        object-oriented languages like C++ and Java as well.

                        I'd like to suggest that you really should spend a fair amount more time
                        learning OOP concepts in general, and the C# language specifically, before
                        you attempt to successfully use p/invoke or other advanced C#/.NET
                        features.

                        Pete

                        Comment

                        • Rudy Velthuis

                          #13
                          Re: Calling a Windows API Function

                          Stewart Berman wrote:
                          I assume the need to imbed the imports in a class is due to the dot
                          net framework.
                          It is actually due to the C# language. Not all languages on .NET
                          require this.
                          I don't understand the need to make the members of
                          the OpenFileName class public. They will only be referred to with
                          the code that instantiated the class. Why do they need to be public?
                          Because otherwise they'll be private (which is the default
                          accessibility for class members), and so no code in any other class
                          would be able to access them.
                          --
                          Rudy Velthuis http://rvelthuis.de

                          "Wagner's music is better than it sounds."
                          -- Mark Twain (1835-1910)

                          Comment

                          • \Ji Zhou [MSFT]\

                            #14
                            RE: Calling a Windows API Function

                            Hello Stewart Berman,

                            Thanks for using Microsoft Newsgroup Support Service, my name is Ji Zhou
                            [MSFT] and I will be working on this issue with you.

                            As you already found the imported function's declaration should be embedded
                            in a class. Otherwise we will receive the error you mentioned in your first
                            post. The reason is, in C# language, there is not a concept of global
                            function or global variable while the C++ does have. If we want to simulate
                            the global function using C#, we need to create a host class and put the
                            function declaration in that class as public static type. Then, we can
                            access it via NameSpace.Class .Function everywhere else in the project.

                            As to why the fields of the class OpenFileName should be declared as
                            public, the public fields can be accessed from the OpenFileName instance
                            directly. If we use the private field, after we create an instance of
                            OpenFileName, we cannot initialize the private fields value. The P/Invoke
                            may fails for the incorrect parameter.

                            One more thing to state is that, what is the business reason for calling
                            the native API GetOpenFileName and GetSaveFileName from C#. Based on my
                            experience, since the .NET Framework provide this function in the assembly
                            System.Windows. Forms.dll, why not directly use the SaveFileDialog and
                            OpenFileDialog in .NET?

                            Codes look like,

                            private void button1_Click(o bject sender, System.EventArg s e)
                            {
                            Stream myStream = null;
                            OpenFileDialog openFileDialog1 = new OpenFileDialog( );

                            openFileDialog1 .InitialDirecto ry = "c:\\" ;
                            openFileDialog1 .Filter = "txt files (*.txt)|*.txt|A ll files (*.*)|*.*" ;
                            openFileDialog1 .FilterIndex = 2 ;
                            openFileDialog1 .RestoreDirecto ry = true ;

                            if(openFileDial og1.ShowDialog( ) == DialogResult.OK )
                            {
                            try
                            {
                            if ((myStream = openFileDialog1 .OpenFile()) != null)
                            {
                            using (myStream)
                            {
                            // Insert code to read the stream here.
                            }
                            }
                            }
                            catch (Exception ex)
                            {
                            MessageBox.Show ("Error: Could not read file from disk. Original
                            error: " + ex.Message);
                            }
                            }
                            }

                            We firstly create an instance of OpenFileDialog and set its properties like
                            the InitialDirector y, Filter, Filter Index and so on. After that, we can
                            call its.ShowDialog( ) to pop up the open file dialog. You can get more
                            information in the following two MSDN articles.

                            http://msdn.microsoft.com/en-us/libr...openfiledialog.
                            aspx
                            http://msdn.microsoft.com/en-us/libr...savefiledialog.
                            aspx

                            If you have any future questions or concerns, please feel free to let me
                            know and I will try my best to follow up. Have a nice day, Stewart!


                            Best regards,
                            Ji Zhou (v-jzho@online.mic rosoft.com, remove 'online.')
                            Microsoft Online Community Support

                            Delighting our customers is our #1 priority. We welcome your comments and
                            suggestions about how we can improve the support we provide to you. Please
                            feel free to let my manager know what you think of the level of service
                            provided. You can send feedback directly to my manager at:
                            msdnmg@microsof t.com.

                            =============== =============== =============== =====
                            Get notification to my posts through email? Please refer to
                            http://msdn.microsoft.com/en-us/subs...#notifications.

                            Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
                            where an initial response from the community or a Microsoft Support
                            Engineer within 1 business day is acceptable. Please note that each follow
                            up response may take approximately 2 business days as the support
                            professional working with you may need further investigation to reach the
                            most efficient resolution. The offering is not appropriate for situations
                            that require urgent, real-time or phone-based interactions or complex
                            project analysis and dump analysis issues. Issues of this nature are best
                            handled working with a dedicated Microsoft Support Engineer by contacting
                            Microsoft Customer Support Services (CSS) at
                            http://support.microsoft.com/select/...tance&ln=en-us.
                            =============== =============== =============== =====
                            This posting is provided "AS IS" with no warranties, and confers no rights.

                            Comment

                            • Stewart Berman

                              #15
                              Re: Calling a Windows API Function

                              "Rudy Velthuis" <newsgroups@rve lthuis.dewrote:
                              >Stewart Berman wrote:
                              >
                              >I assume the need to imbed the imports in a class is due to the dot
                              >net framework.
                              >
                              >It is actually due to the C# language. Not all languages on .NET
                              >require this.
                              >
                              >I don't understand the need to make the members of
                              >the OpenFileName class public. They will only be referred to with
                              >the code that instantiated the class. Why do they need to be public?
                              >
                              >Because otherwise they'll be private (which is the default
                              >accessibilit y for class members), and so no code in any other class
                              >would be able to access them.
                              I realized that about three seconds after I hit the send button on the message.

                              Comment

                              Working...