C# Interop with WinInet

I have a C# FTP Class that connects to WININET through the PInoke Interop stuff.  When I use this to connect to a remote site and read a batch of files to save to my local machine the code will "freeze" on a call to InternetReadFile and FtpGetFile.  The file it freezes on is always random (sometimes it will get 10 files, sometimes it will get 20).  When I stop the program and restart it, it will pick up where it left off and freeze again 20 or 30 files down the line.  Here are the import tags:

        [DllImport("WININET.DLL", EntryPoint = "FtpGetFile", SetLastError = true)]
        private static extern bool FtpGetFile(IntPtr hFtpConn
            ,string strSource
            ,string strTarget
            ,bool bFailIfExists
            ,uint nFlagsAndAtrribute
            ,uint nFlags
            ,uint nContext);

        [DllImport("WININET.DLL", EntryPoint = "FtpOpenFile", SetLastError = true)]
        private static extern IntPtr FtpOpenFile(IntPtr hFtpConn
            ,string strFileName
            ,uint nAccess
            ,uint nFlags
            ,uint nContext);

        [DllImport("WININET.DLL", EntryPoint = "InternetReadFile", SetLastError=true)]
        private static extern bool InternetReadFile(IntPtr hFileFind
            ,byte[] pBuffer
            ,uint nBytesToRead
            ,ref uint nBytesRead);

And here is the implementation:

        public bool ReadRemoteFile(string strFileName, out string strBuffer)
        {
            bool bRetCode;
            IntPtr hFoundFile;
            uint nBytesRead = 0;
            byte[] arBuffer = new byte[MAX_BYTES_TO_READ];

            try
            {
                hFoundFile = FtpOpenFile(m_hFtpConnection, strFileName, GENERIC_READ, FTP_TRANSFER_TYPE_BINARY, 1);
                strBuffer = "";

                if (hFoundFile != IntPtr.Zero)
                {
                    bRetCode = true;
                    do
                    {
                        bRetCode = InternetReadFile(hFoundFile, arBuffer, MAX_BYTES_TO_READ, ref nBytesRead);

                        if (bRetCode && nBytesRead > 0)
                        {
                            strBuffer += Encoding.ASCII.GetString(arBuffer, 0, (int)nBytesRead);
                        }
                        else if (!bRetCode)
                        {
                            m_nLastErrorCode = Marshal.GetLastWin32Error();
                        }

                    }
                    while (nBytesRead > 0);
                    InternetCloseHandle(hFoundFile);
                }
                else
                {
                    bRetCode = false;
                }
            }
            catch (Exception ex)
            {
                bRetCode = false;
                throw ex;
            }

            return bRetCode;
        }

It freezes on the line:
bRetCode = InternetReadFile(hFoundFile, arBuffer, MAX_BYTES_TO_READ, ref nBytesRead);
       

I'm at my wits end and any help would be greatly appreciated.

Thanks
rockyaldrichAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

vo1dCommented:
byte[] arBuffer = new byte[MAX_BYTES_TO_READ];

have you tried to put that line as classmember and only initialize its data with '0' before filling it in your method?
0
rockyaldrichAuthor Commented:
Hi vo1d,
I just tried that and got the same results.
0
vo1dCommented:
i dont know, if it works, but what if you try to change your byte buffert to a stringbuilder? does this work?
maybe this?
[DllImport("WININET.DLL", EntryPoint = "InternetReadFile", SetLastError=true)]
        private static extern bool InternetReadFile(IntPtr hFileFind
            ,StringBuilder buffer
            ,uint nBytesToRead
            ,ref uint nBytesRead);


StringBuilder buffer = new StringBuilder(MAX_BYTES_TO_READ);
bRetCode = InternetReadFile(hFoundFile, buffer, (uint)buffer.Capacity, ref nBytesRead);

maybe this works, if not, uncomment this line:
strBuffer += Encoding.ASCII.GetString(arBuffer, 0, (int)nBytesRead);

try again and see, if your app do not hang.maybe the problem is, that it is written from an unmanaged context into the buffer but readed from a managed context.
that is only an idea. maybe the problem is not your code but the InternetReadFile function itself?

0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

rockyaldrichAuthor Commented:
Wow, I'm getting some really weird stuff here.  When I create a new StringBuiler without specifying a size:

           StringBuilder buffer = new StringBuilder()

it froze on the first file.

When I created it and passed MAX_BYTES_TO_READ to the constructor it read in the file and then read in what looks like an ls -l unix command.  The StringBuilder buffer looks like this (Everything up to EOF0000013 is what is in the file then after that comes the garbage):

Normal file data
Normal file data
Normal file data
EOF000013
08843_041906_1775.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1775.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers     12730 Apr 20 01:06 008843_041906_1776.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1776.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers      7030 Apr 20 01:06 008843_041906_1777.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1777.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers      9880 Apr 20 01:06 008843_041906_1778.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1778.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers      7505 Apr 20 01:06 008843_041906_1779.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1779.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers     13395 Apr 20 01:06 008843_041906_1780.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1780.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers      7695 Apr 20 01:06 008843_041906_1781.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1781.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers     12730 Apr 20 01:06 008843_041906_1782.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1782.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers      4845 Apr 20 01:06 008843_041906_1783.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1783.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers     13775 Apr 20 01:06 008843_041906_1784.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1784.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers      6175 Apr 20 01:06 008843_041906_1785.rtn
-rw-rw-rw-   1 brasma     ftpusers         1 Apr 20 01:06 008843_041906_1785.rtn.tag
-rw-rw-rw-   1 brasma     ftpusers     11400 Apr 20 01:06 008843_041906_1786.rtn
-r8
-


Any thoughts?
0
rockyaldrichAuthor Commented:
Even by specifing MAX_BYTES_TO_READ in the StringBuilder constuctor it is freezing on the first file about half the time now.
0
vo1dCommented:
very interesting but i expected, that stringbuilder would not fit in this.
was only a thought cause in c you use char if you wanna read bytes.
so what happens with the second approach, uncomment the reading from buffert line:
strBuffer += Encoding.ASCII.GetString(arBuffer, 0, (int)nBytesRead);

just to see, if this could be a problem between switching the context from unmanaged to managed.
give it a try.
one question, which size has your const  MAX_BYTES_TO_READ?
0
vo1dCommented:
0
rockyaldrichAuthor Commented:
MAX_BYTES_TO_READ = 8192
0
rockyaldrichAuthor Commented:
What do you mean by switching the context from managed to unmanaged and how do I do it?  Do you mean try the same thing in unmanaged code?  If so I have an old Win32 program I wrote and I'm still using it in production.  This one works fine for doing what we are trying to accomplish, I just want to get it all in C#.
0
vo1dCommented:
no, i mean that interop is the bridge between unmanaged to managed context.
your buffer is a managed object, which is filled from an unmanged method via interop. after that, you read it again from your managed code.
uncommend the following line to check, if your app still hangs after alot of files:
strBuffer += Encoding.ASCII.GetString(arBuffer, 0, (int)nBytesRead);
0
rockyaldrichAuthor Commented:
I commented that out and it still has the same effect, however I did find something else out.  I was running this on a Windows 2003 Server and SQL Server 2005 and it kept freezing.  When I run it on my client machine (Windows XP Sp1) it blazes through all the files without any problems.  Do you think that this could be something with SQL and the CLR or some sort of CLR hosting problem?
0
vo1dCommented:
possibly, maybe win2003 has the same tcp ristriction as xp_sp2, you should try a xp_sp2 version to doublecheck.
but as a first try, you should configure your clr to run your app in server mode.
0
rockyaldrichAuthor Commented:
Cool, just one more thnig, how do I configure the CLR?
0
vo1dCommented:
you can set this up with the Microsoft .NET Framework 2.0 Configuration,with which you can configure your application.
start the tool, in Applications, add your app. after that, view the application's properties. there you can select between both modes for the garbage collection, how it should work.
some information about the gc dirrerences can be found here: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/dotnetperftechs.asp
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.