tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルwininet.dllを使用したftpについて
記事No10202
投稿日: 2010/08/24(Tue) 10:06
投稿者エイジ
いつも参考にさせていただいています。エイジと申します。
以下の環境で開発しております。
言語 VB2008 Compact Framework Ver3.5
開発OS WindowsXp SP3
実行機OS WindowsMobile6.5 Professional
ftpサーバのOS WindowsServer2003

Compact Framework Ver3.5にftpクラスがないためwininet.dllを使用して
ftp処理をしたいと思っています。
色々なホームページを検索しましてその中にあるソースを見つけまして
それを利用しようとしました。(記載のあったホームページは覚えていません)
ftpの接続や、接続先でのフォルダの作成、移動、削除及びファイルの移動は
正常に処理されたのですが(ftpサーバのフォルダやファイルで確認)、ファイル
のftpサーバからのダウンロード及びftpサーバへのアップロードが正常に処理
されません。Err.LastDllErrorでエラー内容を取得したところ以下のような
エラーになっていました。
エラーコード:122
エラー内容:200 Type set to I. 500 Invalid PORT Command
エラーの原因や対処方法など教えて頂けないでしょうか。
よろしくお願い致します。

ソースを抜粋しまして以下に記載します。
    ' API定義
    Private Declare Function InternetOpen Lib "wininet.dll" Alias _
        "InternetOpenW" (ByVal sAgent As String, ByVal lAccessType As Integer, _
         ByVal sProxyName As String, ByVal sProxyBypass As String, _
         ByVal lFlags As Integer) As Integer
    Private Declare Function InternetConnect Lib "wininet.dll" Alias _
        "InternetConnectW" (ByVal hInternetSession As Integer, _
         ByVal sServerName As String, ByVal nServerPort As Integer, _
         ByVal sUsername As String, ByVal sPassword As String, _
         ByVal lService As Integer, ByVal lFlags As Integer, _
         ByVal lContext As Integer) As Integer
    Private Declare Function FtpGetFile Lib "wininet.dll" Alias _
        "FtpGetFileW" (ByVal hFtpSession As Integer, ByVal lpszRemoteFile As String, _
         ByVal lpszNewFile As String, ByVal fFailIfExists As Boolean, _
         ByVal dwFlagsAndAttributes As Integer, ByVal dwFlags As Integer, _
         ByVal dwContext As Integer) As Integer
    Private Declare Function FtpPutFile Lib "wininet.dll" Alias _
        "FtpPutFileW" (ByVal hFtpSession As Integer, ByVal lpszLocalFile As String, _
         ByVal lpszRemoteFile As String, ByVal dwFlags As Integer, _
         ByVal dwContext As Integer) As Integer


            Dim strServer As String    'ftpサーバ名
            Dim strUser As String    'ユーザ名
            Dim strPswd As String    'パスワード
            Dim strLocalPath As String    'ローカルファイルのフルパス
            Dim strRemotePath As String    'ftpサーバファイルのパス

            ' インターネットオープン(FTPサーバ接続準備)
            lngInternetOpen = InternetOpen("WININET", _
                INTERNET_OPEN_TYPE_DIRECT, vbNullString, vbNullString, 0)
            If lngInternetOpen = 0 Then
                MsgBox("インターネットオープン" & Err.LastDllError.ToString)
                Exit Function
            End If

            ' FTPサーバ接続
            Dim lngPassive As Long : lngPassive = 0
            If blnPassive Then lngPassive = INTERNET_FLAG_PASSIVE
            lngInternetConnect = InternetConnect( _
                lngInternetOpen, strServer, INTERNET_INVALID_PORT_NUMBER, _
                strUser, strPswd, INTERNET_SERVICE_FTP, lngPassive, 0)
            If lngInternetConnect = 0 Then
                MsgBox("FTPサーバ接続" & Err.LastDllError.ToString)
                Exit Function
            End If

            ' バイナリまたはアスキーモードの設定
            Dim lngtype As Long
            lngtype = FTP_TRANSFER_TYPE_BINARY
            ' ファイルをFTPサーバへ送信
            Dim lngRtn As Long
            lngRtn = FtpPutFile(lngInternetConnect, _
                strLocalPath, strRemotePath, lngtype, 0)
            If lngRtn = 0 Then
                Dim errer As String
                Dim errlen As Integer
                InternetGetLastResponseInfo(Err.LastDllError, vbNullString, errlen)
                errer = New String(Chr(0), errlen + 1)
                InternetGetLastResponseInfo(Err.LastDllError, errer, errlen)

                MsgBox("ファイルをFTPサーバへ送信" & Err.LastDllError.ToString & "/" & errer)
                Exit Function
            End If

[ツリー表示へ]
タイトルRe: wininet.dllを使用したftpについて
記事No10205
投稿日: 2010/08/24(Tue) 11:09
投稿者魔界の仮面弁士
> エラー内容:200 Type set to I. 500 Invalid PORT Command
『不正な PORT コマンドが送出されました』と言われていますね。

コードの間違いなどで、文字列のマーシャリングで失敗していた場合、
500 Invalid PORT Command が返されるケースがあったかと思います。

とりあえず、ポート番号の指定を、INTERNET_INVALID_PORT_NUMBER ではなく
(INTERNET_DEFAULT_FTP_PORT などの)固定値に変えた場合はどうなりますか?


> Private Declare Function
Private Declare Unicode Function で記述した方が安全かと。


> hInternetSession As Integer
hInternetSession 等は、本来は IntPtr 等の方が良いと思いますよ。
(Integer でも動くとは思いますけれども)


> lngInternetOpen = InternetOpen("WININET", _
API の戻り値は Integer なのに、それを Long で受けるのですか?


> Exit Function
接続が開きっぱなしです。
InternetCloseHandle で後始末すべきかと。


どうしてもうまくいかない場合には、OpenNETCF.Net.Ftp などの
出来合いのライブラリを使うのも手です。
http://www.opennetcf.com/FreeSoftware/tabid/84/Default.aspx
http://www.opennetcf.com/library/sdf/html/35dea976-f2b7-94c9-88b5-2760b2f0b630.htm
http://www.opennetcf.com/library/sdf/

[ツリー表示へ]
タイトルRe^2: wininet.dllを使用したftpについて
記事No10211
投稿日: 2010/08/24(Tue) 15:30
投稿者エイジ
魔界の仮面弁士様、お返事ありがとうございます。

> とりあえず、ポート番号の指定を、INTERNET_INVALID_PORT_NUMBER ではなく
> (INTERNET_DEFAULT_FTP_PORT などの)固定値に変えた場合はどうなりますか?
ポート番号をftpサーバに設定しています21にしましたが同じエラーが表示されました。

>
> > Private Declare Function
> Private Declare Unicode Function で記述した方が安全かと。
上記のようにUnicodeと記載できるのですが、以下のようなエラーになります。
対象の .NET Compact Framework バージョンは、ANSI、Auto、または Unicode 修飾子の使用をサポートしていません。

>
> > hInternetSession As Integer
> hInternetSession 等は、本来は IntPtr 等の方が良いと思いますよ。
> (Integer でも動くとは思いますけれども)
IntPtrに変更しました。

>
> > lngInternetOpen = InternetOpen("WININET", _
> API の戻り値は Integer なのに、それを Long で受けるのですか?
気がつきませんでした。Integerに変更します。

>
> > Exit Function
> 接続が開きっぱなしです。
> InternetCloseHandle で後始末すべきかと。
先ほど記載のソースをTryの中に記載し、切断のロジックはFinallyの中に
記載していました。細かい箇所までのアドバイスありがとうございます。


上記、教えていただいた内容の変更できる箇所は変更しましたが、エラー内容は
変わらない状態です。
> コードの間違いなどで、文字列のマーシャリングで失敗していた場合
この意味がよく分かりません。
ftpの接続ができ、ftpサーバ内にありますフォルダやファイルをftpサーバ内で
コピーや削除、移動などはできるのに、実行機とftpサーバとのやりとり時に
エラーになります。
実行機は携帯電話(NTT DocomoのT-01A)です。携帯電話からftpサーバへは、Vpnで
接続しています。実行機内のファイルのパスの書き方に問題があるのでしょうか?
ファイルのパスは、実行機内でファイルコピーなどで使用している方法と同じで
[\フォルダ名\ファイル名]としています。
何かアドバイスお願い致します。

> どうしてもうまくいかない場合には、OpenNETCF.Net.Ftp などの
> 出来合いのライブラリを使うのも手です。
> http://www.opennetcf.com/FreeSoftware/tabid/84/Default.aspx
> http://www.opennetcf.com/library/sdf/html/35dea976-f2b7-94c9-88b5-2760b2f0b630.htm
> http://www.opennetcf.com/library/sdf/
出口が見えなくなりましたら、上記サイトも参考にさせていただきたいと思います。

[ツリー表示へ]
タイトルRe^3: wininet.dllを使用したftpについて
記事No10213
投稿日: 2010/08/24(Tue) 16:39
投稿者魔界の仮面弁士
エラーの発生箇所は、FtpPutFile の実行時でしょうか?
(InternetOpen や InternetConnect は問題なし?)


> 対象の .NET Compact Framework バージョンは、ANSI、Auto、または Unicode 修飾子の使用をサポートしていません。
あ、そういえばそうでしたね。失礼しました。


>>> lngInternetOpen = InternetOpen("WININET", _
>> API の戻り値は Integer なのに、それを Long で受けるのですか?
> 気がつきませんでした。Integerに変更します。
IntPtr にしたのではありませんでしたっけ。

InternetOpen にしても InternetConnect にしても、
その戻り値はインターネットハンドル(HINTERNET)ですよね。


>> コードの間違いなどで、文字列のマーシャリングで失敗していた場合
> この意味がよく分かりません。
.NET Framework (≠.NET Compact Framework)で実行した場合、
Unicode 指定無しで「Declare Function 〜 Alias "〜W"」と
宣言した場合に、同じエラーが返された事があったのです。

.NET Compact Framework は、常に Unicode 指定になるので
無関係かも知れませんけれども。



> 実行機とftpサーバとのやりとり時にエラーになります。
Port 21 でのコマンド送受信はできているものの、
Port 20(等)でのデータ交換に失敗している感じでしょうか。

・今回、INTERNET_FLAG_PASSIVE は使いますか? 使いませんか?
・サーバー側の FTP アクセスログに、T-01A からの接続は記録されていますか?
・CE 機用の FTP ツール(SyncFTP等)を使っての送受信はできますか?

[ツリー表示へ]
タイトルRe^4: wininet.dllを使用したftpについて
記事No10214
投稿日: 2010/08/25(Wed) 10:13
投稿者エイジ
魔界の仮面弁士様、お返事ありがとうございます。

> エラーの発生箇所は、FtpPutFile の実行時でしょうか?
> (InternetOpen や InternetConnect は問題なし?)
>
エラーというより Private Declare Function InternetOpen Lib "wininet.dll" Alias
などの戻り値を見てゼロの場合は、エラーと判断しています。
(ネットで見つけたままのソースをそのまま使用しているため理由は分かりません)
InternetOpenの戻り値は13369348、InternetConnectの戻り値は13369352、
FtpPutFileの戻り値はゼロになっています。
戻り値がゼロの場合、その原因を探すため、InternetGetLastResponseInfoで
エラーの内容を取得しています。

> IntPtr にしたのではありませんでしたっけ。
ftp関係ではIntegerは使用せずIntPtrを使用したほうがいいということでしょうか。
全てIntPtrにしましたが、結果は変わりません。

> InternetOpen にしても InternetConnect にしても、
> その戻り値はインターネットハンドル(HINTERNET)ですよね。
インターネットハンドル(HINTERNET)かは不明ですが、以下のAPIで取得しています。
    ' API定義
    Private Declare Function InternetOpen Lib "wininet.dll" Alias _
        "InternetOpenW" (ByVal sAgent As String, ByVal lAccessType As IntPtr, _
         ByVal sProxyName As String, ByVal sProxyBypass As String, _
         ByVal lFlags As IntPtr) As IntPtr
    Private Declare Function InternetConnect Lib "wininet.dll" Alias _
        "InternetConnectW" (ByVal hInternetSession As IntPtr, _
         ByVal sServerName As String, ByVal nServerPort As IntPtr, _
         ByVal sUsername As String, ByVal sPassword As String, _
         ByVal lService As IntPtr, ByVal lFlags As IntPtr, _
         ByVal lContext As IntPtr) As IntPtr

> > 実行機とftpサーバとのやりとり時にエラーになります。
> Port 21 でのコマンド送受信はできているものの、
> Port 20(等)でのデータ交換に失敗している感じでしょうか。
>
> ・今回、INTERNET_FLAG_PASSIVE は使いますか? 使いませんか?
> ・サーバー側の FTP アクセスログに、T-01A からの接続は記録されていますか?
> ・CE 機用の FTP ツール(SyncFTP等)を使っての送受信はできますか?
INTERNET_FLAG_PASSIVEは使用しません。
サーバー側の FTP アクセスログには、T-01Aから[USER]と[PASS]のログは記録されています。
SyncFtpをT-01Aにインストールしました。
接続時と切断時に、[正規表現変換でエラーが発生しました]という
メッセージがたくさん表示され、Server側のファイルが全てフォルダになり、名前も
Dateも空白になっています。
Localは正常に表示されていますのでアップロードを試しましてが、接続時と切断時に
出る[正規表現変換でエラーが発生しました]が表示されましたが、サーバを直接見ると
正常にアップロードされていました。

以上、よろしくお願い致します。

[ツリー表示へ]
タイトルRe^5: wininet.dllを使用したftpについて
記事No10217
投稿日: 2010/08/28(Sat) 00:19
投稿者よねKEN
> > IntPtr にしたのではありませんでしたっけ。
> ftp関係ではIntegerは使用せずIntPtrを使用したほうがいいということでしょうか。

そういう意味ではないでしょう。IntPtr型にすべきもの、Integer型にすべきもの、
XXX型にすべきもの、いろいろです。

wininet.dllで定義されている関数のMSDNライブラリの説明は以下にあります。

WinINet Functions
http://msdn.microsoft.com/ja-jp/library/aa385473(VS.85).aspx

ここではC言語での関数のシグネチャが書いてありますので、
引数、戻り値のC言語での型を確認してください。
その上でVB2008でDeclare宣言するために.NETのどの型を適用するのか
判断する必要があります。

> 全てIntPtrにしましたが、結果は変わりません。

引数の意味も違えば、当然とるべき型も違うので、それは無茶苦茶です。

> > InternetOpen にしても InternetConnect にしても、
> > その戻り値はインターネットハンドル(HINTERNET)ですよね。
> インターネットハンドル(HINTERNET)かは不明ですが、以下のAPIで取得しています。

上記のURLからInternetOpen関数やInternetConnect関数の定義を確認しましょう。
元の定義ではHINTERNET型です。Windows APIでは、H〜と命名されるものは
だいたいハンドルで、ハンドルは実行環境のネイティブサイズのポインタです。
そのため、最適の型がIntPtrだ、となります。
#IntPtr型でなくてもInteger型でもうまく行くのは、
#実行環境が32bitの場合だけです。

<<参考ページ>>
KEN's .NET [特集6] GetPrivateProfileStringにみるAPIの使用方法
http://www5b.biglobe.ne.jp/~yone-ken/VBNET/special/sp06_GetPrivateProfileString.html

手前味噌ですが、上記のページでは、(.NET対応版の)VBからWindows APIを呼び出す場合の
宣言方法の考え方をまとめていますの多少は参考になると思います。
(IntPtr型について残念ながら書いていませんが)

[ツリー表示へ]
タイトルRe^6: wininet.dllを使用したftpについて
記事No10218
投稿日: 2010/08/29(Sun) 19:25
投稿者魔界の仮面弁士
>> InternetOpenの戻り値は13369348、InternetConnectの戻り値は13369352、
>> FtpPutFileの戻り値はゼロになっています。
FtpPutFile だけが失敗しているようですね。

第2〜第4引数(LocalFile, NewRemoteFile, Flags)に渡している値は
それぞれどのような内容ですか? IIS6 だと、"opt utf-8 on" には
対応していないはずなので、利用可能なファイル名には制限があります。

また、FtpPutFileEx API で代用した場合はどうでしょうか?


>> 接続時と切断時に、[正規表現変換でエラーが発生しました]という
正直、FTP で正規表現変換という点が良く分かりませんでした。
このエラーは、サーバー側/クライアント側いずれで出力されていますか?

また、(T-01A ではなく) XP 上の .NET Compact Framework 3.5 から
実行した場合は、どのような結果になりますか?


>> メッセージがたくさん表示され、Server側のファイルが全てフォルダになり、名前も
>> Dateも空白になっています。
まずはパケットをキャプチャして、通信内容をトレースしてみては如何でしょうか。

あと、FTP サーバーの設定も確認してみて下さい。たとえばサーバー側が
IIS6 の場合は、ディレクトリスタイルが UNIX / MS-DOS のいずれなのかとか。


> そういう意味ではないでしょう。IntPtr型にすべきもの、Integer型にすべきもの、
> XXX型にすべきもの、いろいろです。
ですね。フォローありがとうございます。


> WinINet Functions
> http://msdn.microsoft.com/ja-jp/library/aa385473(VS.85).aspx
それはデスクトップ版の API ですね。
Windows Mobile 6.5 版はこちらです。まぁ、基本的には同じですが。
http://msdn.microsoft.com/en-us/library/aa914184.aspx


> #IntPtr型でなくてもInteger型でもうまく行くのは、
> #実行環境が32bitの場合だけです。
実際のところ、.NET Compact Framework 3.5 は 32 bit 専用であり、
現時点では 16bit や 64bit 版の環境が存在するわけではないので、
事実上、Integer や UInteger でも代用することは可能です。とはいえ、
中身がハンドルなのであれば、やはり IntPtr を使った方が自然ですね。

[ツリー表示へ]
タイトルRe^7: wininet.dllを使用したftpについて
記事No10219
投稿日: 2010/08/30(Mon) 09:22
投稿者よねKEN
> > WinINet Functions
> > http://msdn.microsoft.com/ja-jp/library/aa385473(VS.85).aspx
> それはデスクトップ版の API ですね。
> Windows Mobile 6.5 版はこちらです。まぁ、基本的には同じですが。
> http://msdn.microsoft.com/en-us/library/aa914184.aspx

魔界の仮面弁士さん、フォローありがとうございます。
Windows Mobile版は別のページがあったのですね。
#通常版とモバイル版で微妙にAPI等の制限事項が違う可能性もあるので
#専用ページがあるかもとは考えてはいましたが
#該当ページを見つけられませんでした。助かります。

エイジさん、不正確な情報提供をして申し訳ありません。
魔界の仮面弁士さんのご提示になったURLの方をご確認ください。

> 実際のところ、.NET Compact Framework 3.5 は 32 bit 専用であり、
> 現時点では 16bit や 64bit 版の環境が存在するわけではないので、

なるほど、勉強になります。

[ツリー表示へ]
タイトルRe^7: wininet.dllを使用したftpについて
記事No10221
投稿日: 2010/08/30(Mon) 15:12
投稿者エイジ
魔界の仮面弁士さん、よねKENさん、お返事ありがとうございます。
(返事が遅れまして申し訳ありません。)

引数や型について、教えていただきましたページを参考に、
IntPtr型なのか、Integer型なのかなど勉強したいと思います。
上記2つの型の根本的な違いや引数の型を理解せずに、機械的にInteger型を
IntPtr型と修正してしまっていました。

> 第2〜第4引数(LocalFile, NewRemoteFile, Flags)に渡している値は
> それぞれどのような内容ですか? IIS6 だと、"opt utf-8 on" には
> 対応していないはずなので、利用可能なファイル名には制限があります。
第2引数は、\xxx\xxx\xxx.txt
第3引数は、xxx.txt
第6引数は、FTP_TRANSFER_TYPE_BINARY ( = &H2)
第7引数は、0
を渡しています。
xxxは全て、半角英字です。

> また、FtpPutFileEx API で代用した場合はどうでしょうか?
教えていただいたページを参照し、以下のように宣言しました。
しかし、FtpPutFileと同じ内容のエラーが返されました。
    Private Declare Function FtpPutFileEx Lib "wininet.dll" Alias _
        "FtpPutFileEx" (ByVal hFtpSession As IntPtr, ByVal lpszLocalFile As String, _
         ByVal lpszRemoteFile As String, ByVal dwFlags As Integer, _
         ByVal dwContext As Integer) As Boolean


SyncFtpについてですが、サーバ側のIISのディレクトリの表示スタイルの設定を
UNIX(R)に変更しましたらら、、[正規表現変換でエラーが発生しました]の
エラーも表示されず、サーバ側のファイル名や日付も正常に表示できました。
また、ファイルのアップロード・ダウンロードもできました。

教えていただきましたホームページを参照し、引数や戻値の型をもう一度洗い直し
しながらやっていこうと思います。(ホームページを検索していましたら型の変更
だけで正常に動作するということもあったようなので)

何か注意など必要なことがありましたら教えて頂けないでしょうか。
よろしくお願い致します。

[ツリー表示へ]