Link to home
Start Free TrialLog in
Avatar of rockyaldrich
rockyaldrich

asked on

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
Avatar of vo1d
vo1d
Flag of Germany image

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?
Avatar of rockyaldrich
rockyaldrich

ASKER

Hi vo1d,
I just tried that and got the same results.
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?

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?
Even by specifing MAX_BYTES_TO_READ in the StringBuilder constuctor it is freezing on the first file about half the time now.
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?
MAX_BYTES_TO_READ = 8192
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#.
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);
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?
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.
Cool, just one more thnig, how do I configure the CLR?
ASKER CERTIFIED SOLUTION
Avatar of vo1d
vo1d
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial