質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

FTP

FTP(File Transfer Protocol)は、ネットワークでのファイル転送を行うための通信プロトコルの1つである。

.NET Framework 3.5

.NET Framework-3.5は、NET Framework 2.0にアセンブリを追加(3.0も含む)したものをベースにしています。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

1回答

13371閲覧

WIN32API FtpGetFile関数 使用する際、引数のファイルパスの正しい型は?

ARADDIO

総合スコア160

VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

FTP

FTP(File Transfer Protocol)は、ネットワークでのファイル転送を行うための通信プロトコルの1つである。

.NET Framework 3.5

.NET Framework-3.5は、NET Framework 2.0にアセンブリを追加(3.0も含む)したものをベースにしています。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

0グッド

0クリップ

投稿2016/09/06 02:13

お世話になっています。

###前提
過去に書かれたVB6のソースコードを
VB.NETへアップグレードする作業を行っています。
VB6でWIN32APIを使用していたコード(以下、旧ソース)を、VB.NETにアップグレードする際
WIN32API関数 FtpGetFileを使用する箇所で疑問発生しました。
(.Net Framework 3.5です)

またFTPコマンドおよび、旧ソースでのFileGetには成功しており、FTPサーバ側の問題でないことは確認できています。

###謎
発生している問題として、
WIN32API関数 FtpGetFile をVB.NETで使用すると
戻り値0(ファイル取得失敗)が返ってきます。

Visual Basic6 リファレンス FtpGetFile
によると、転送元ファイル名および 転送先ファイル名は文字列の引数として使用すると書いてあります。

ところが、旧ソース(VB6)の定義部では、型はAnyとなっていました。

VB6 FtpGetFile 定義部

VB6

1Private Declare Function FtpGetFile Lib "wininet.dll" _ 2 Alias "FtpGetFileA" _ 3 (ByVal hFtpSession As Long, _ 4 ByRef lpszRemoteFile As Any, _ 5 ByRef lpszNewFile As Any, _ 6 ByVal fFailIfExists As Long, _ 7 ByVal dwFlagsAndAttributes As Long, _ 8 ByVal dwFlags As Long, _ 9 ByVal dwContext As Long _ 10 ) As Long

↑をVisual Studio 2015による自動アップグレード実施すると、
Any は String として解釈されています。

アップグレードされたVB.NET FtpGetFile 定義部

VBNET

1'UPGRADE_ISSUE: パラメータ 'As Any' の宣言はサポートされません。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="FAE78A8D-8978-4FD4-8208-5B7324A8F795"' をクリックしてください。 2 Private Declare Function FtpGetFile Lib "wininet.dll" Alias "FtpGetFileA" (ByVal hFtpSession As Integer, ByRef lpszRemoteFile As String, ByRef lpszNewFile As String, ByVal fFailIfExists As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal dwFlags As Integer, ByVal dwContext As Integer) As Integer

ところが、これをこのまま使用すると、戻り値0(ファイル取得失敗)が返ってきます。

VB.NET使用箇所コード

VBNET

1' GetFileName PutFileName にはそれぞれ XXX/XX/XXX.xxx形式の文字列が入っています。 2Result = FtpGetFile(ssnFtp, GetFileName, PutFileName, 1, FILE_ATTRIBUTE_NORMAL, 1, 0)

そこで旧ソースの使用箇所を確認すると、引数にByte型に変換した値を使用していました。
旧ソース(VB6)使用箇所コード

VB6

1' 2 bytGetFile = StrConv((GetFileName& vbNullChar), vbFromUnicode) 3 bytPutFile = StrConv((PutFileName& vbNullChar), vbFromUnicode) 4 lngRet = FtpGetFile(lngFtp, _ 5 bytGetFile (0), _ 6 bytPutFile (0), _ 7 1&, _ 8 FILE_ATTRIBUTE_NORMAL&, _ 9 1&, _ 10 0&)

※ためしにVB6側のソース修正し、ファイルパスの箇所を文字列で渡したところ、ファイル取得に失敗しました。
(ファイルパスの引数箇所が原因と推察した理由はここになります。)

ということで、VB.NET側で以下のようにしてみたところ

VBNET

1'FtpGetFile 定義変更 2 'Private Declare Function FtpGetFile Lib "wininet.dll" Alias "FtpGetFileA" (ByVal hFtpSession As Integer, ByRef lpszRemoteFile As String, ByRef lpszNewFile As String, ByVal fFailIfExists As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal dwFlags As Integer, ByVal dwContext As Integer) As Integer 3 Private Declare Function FtpGetFile Lib "wininet.dll" Alias "FtpGetFileA" (ByVal hFtpSession As Integer, ByRef lpszRemoteFile As Byte, ByRef lpszNewFile As Byte, ByVal fFailIfExists As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal dwFlags As Integer, ByVal dwContext As Integer) As Integer 4 5 6 'UPGRADE_TODO: System.Text.UnicodeEncoding.Unicode.GetBytes() を使うためにコードがアップグレードされましたが、動作が異なる可能性があります。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="93DD716C-10E3-41BE-A4A8-3BA40157905B"' をクリックしてください。 7 bytGetFile= System.Text.Encoding.GetEncoding(932).GetBytes(GetFileName & vbNullChar) 8 'UPGRADE_ISSUE: 定数 vbFromUnicode はアップグレードされませんでした。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="55B59875-9A95-4B71-9D6A-7C294BF7139D"' をクリックしてください。 9 'UPGRADE_TODO: System.Text.UnicodeEncoding.Unicode.GetBytes() を使うためにコードがアップグレードされましたが、動作が異なる可能性があります。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="93DD716C-10E3-41BE-A4A8-3BA40157905B"' をクリックしてください。 10 bytPutFile= System.Text.Encoding.GetEncoding(932).GetBytes(PutFileName & vbNullChar) 11 12 Result = FtpGetFile(ssnFtp, bytGetFile(0), bytPutFile(0), 1, FILE_ATTRIBUTE_NORMAL, 1, 0) 13

うまく取得できました。

###質問
上記のような動作になってしまうのはなぜなのでしょうか?(Stringで渡すとダメだがByteだとOK)
FtpGetFileの仕様で、ファイルパスはByteでしか受け付けないようになっているのでしょうか
(だとするとVisual StudioのUpgrade ToolでStringになるのは不親切な気もしますが。)

ご存知の方いらっしゃいましたら教えていただけないでしょうか。

###補足情報(言語/FW/ツール等のバージョンなど)
Visual Studio 2015 / .Net Framework 3.5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Win32APIはANSI文字列を受け取るバージョン(関数名最後に’A'が付く)とUnicode文字列を受け取るバージョン(関数名最後に'W'が付く)と同じ機能で二つの関数が存在します。

今回のソースには"FtpGetFileA"が使用されていましたので、この場合の文字列引数はANSI文字列で渡す必要があります。.NETだとこの場合Byte配列となります。

なので、"FtpGetFileW"の方を使用されれば、Stringを引数にとる形で使用できるはずです。

このあたりの仕組みはちょっと古い記事ですが連載:VB 6ユーザーのためのこれならマスターできるVB 2005超入門 第12回 VB 2005でWin32 APIを利用するにまとめられていますので、ご参考まで。

【コメントを受けての追記】

文字列の引数を扱う場合Win32 APIやDLL関数に文字列や文字列バッファを渡すには?が参考になると思います。こちらもおなじく@ITの記事からになります。

投稿2016/09/06 03:21

編集2016/09/06 05:00
KoichiSugiyama

総合スコア3041

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ARADDIO

2016/09/06 04:49

回答ありがとうございます。 >Win32APIはANSI文字列を受け取るバージョン(関数名最後に’A'が付く)とUnicode文字列を受け取るバージョン(関数名最後に'W'が付く)と同じ機能で二つの関数が存在します。 これは知りませんでした。 そういうことだったのですね。 >今回のソースには"FtpGetFileA"が使用されていましたので、この場合の文字列引数はANSI文字列で渡す必要があります。.NETだとこの場合Byte配列となります。 ここなのですが、.NetではUnicodeしか扱えないため、FtpGetFileAがマルチバイト文字(ANSI)として扱うためにByte変換するということなのでしょうか? >なので、"FtpGetFileW"の方を使用されれば、Stringを引数にとる形で使用できるはずです。 こちらについては↓のように定義変更しましたが、実行すると0が返ってきてしまいました。(渡す変数もStringに変更しました。) 何か間違っているでしょうか? Private Declare Function FtpGetFile Lib "wininet.dll" Alias "FtpGetFileW" (ByVal hFtpSession As Integer, ByRef lpszRemoteFile As String, ByRef lpszNewFile As String, ByVal fFailIfExists As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal dwFlags As Integer, ByVal dwContext As Integer) As Integer
KoichiSugiyama

2016/09/06 04:58

参考にするサイトがもう一つありました。文字列の引数に関してはこちらの方が判りやすいと思います。追記で回答の方に挙げておきますので、参照してみてください。
ARADDIO

2016/09/06 08:54

追記ありがとうございます。 もう少し試行錯誤してみます。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問