WriteFile関数の引数について

このQ&Aのポイント
  • WriteFile関数の引数について説明します。
  • WriteFile関数は、指定したファイルにデータを書き込むために使用されます。
  • 具体的には、lpBufferには書き込むデータが格納されており、nNumberOfBytesToWriteには書き込むバイト数が指定されます。書き込まれたバイト数はlpNumberOfBytesWrittenに格納されます。Pathが指定されていない場合は、デフォルトの保存場所にファイルが作成されます。
回答を見る
  • ベストアンサー

WriteFileの引数について

APIを学習中の初心者です。 サンプルコードにあったのですが、test0623.txt のテキストを作成し、「abcde」と書き込むというものです。 Const GENERIC_WRITE = &H40000000 Const GENERIC_READ = &H80000000 Const FILE_ATTRIBUTE_NORMAL = &H80 Const CREATE_ALWAYS = 2 Const OPEN_ALWAYS = 4 Const INVALID_HANDLE_VALUE = -1 Private Declare Function CloseHandle Lib "kernel32" ( _ ByVal hObject As Long) As Long Private Declare Function WriteFile Lib "kernel32" ( _ ByVal hFile As Long, lpBuffer As Any, _ ByVal nNumberOfBytesToWrite As Long, _ lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Long) As Long Private Declare Function CreateFile Lib "kernel32" _ Alias "CreateFileA" (ByVal lpFileName As String, _ ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, _ ByVal lpSecurityAttributes As Long, _ ByVal dwCreationDisposition As Long, _ ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long Sub test1() Dim hFile As Long Dim FileName As String Dim Sampledata() As Byte Dim BytesToWritten As Long Dim SC As Long FileName = "test0623.txt" SC = StrConv("abcde", vbFromUnicode) hFile = CreateFile(FileName, GENERIC_WRITE Or GENERIC_READ, _ 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) SC = WriteFile(hFile, Sampledata(0), _ UBound(Sampledata), BytesToWritten, 0) Call CloseHandle(hFile) End Sub とあったのですが質問は以下の通りです。    (1) SC = WriteFile(hFile, Sampledata(0), UBound(Sampledata), BytesWritten, 0) で、な ぜ、lpBuffer(第1引数)にSampledata(0)を指定すれば、ファイルに書き込むべきデータを保持しているバッファへのポインタになるのか?またSampledata(0)のように配列にする理由が不明? (2) SC = WriteFile(hFile, Sampledata(0), UBound(Sampledata), BytesWritten, 0) で、なぜ、  nNumberOfBytesToWrite(第2引数)に UBound(Sampledata)を指定すれば、ファイルに書き込むべきバイト数になるのか?ここで、0を指定すると、何も書き込まないらしい。 (3) SC = WriteFile(hFile, Sampledata(0), UBound(Sampledata), BytesWritten, 0) で、なぜ、lpNumberOfBytesWritten(第3引数)に何の値も格納していない BytesWritten を記述しているのか?MSDNライブラリには、「関数から制御が返ると、この変数に、実際に書き込まれたバイト数が格納されます。」とあるので、指定しなくてよいのか?    (4) Pathを指定していないが、なぜか、C:\Users\123\Documents に作成される。 以上です。よろしくお願いします

質問者が選んだベストアンサー

  • ベストアンサー
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.1

SC = StrConv("abcde", vbFromUnicode) は Sampledata = StrConv("abcde", vbFromUnicode) の間違いかな? その前提で、 (1)それはVisual BasicとWin32APIの相互運用でそういう事になってるとしか・・・・。Win32APIは元々C言語用のAPIなので、VBから呼び出す時はケースバイケースで妙なお作法があったりするのです。 (2)それはSampledataがByteの配列だからだ。UBoundは配列の最大要素番号を返すものだが、StrConvが返したバイト数を指定する場面ではByteの配列の要素数がそのままバイト数になる。ただ・・・・StrConv("abcde", vbFromUnicode)をByteの配列に代入してUBoundを取ると1少なくなるんじゃないかなぁ。UBound(Sampledata)は4になるんじゃなかろうか。 (3)この第三引数は、入力じゃなくて出力だ。つまり、あなたが値を設定してWriteFileに渡すのではなく、WriteFile内で値を設定してあなたに返してくれるものだ。だからあなたは何の値も格納しなくてよい。Declareを見ると、そこだけByValが無い事に気づくだろう。それが、VBで言うところのByRef、呼び元と呼び先で変数を共有する仕組みだ。 (4)それは「カレントディレクトリ」と呼ばれる仕組みによって実現されている。カレントディレクトリとは、「ディレクトリを指定せずにファイルを読み書きしたらそのディレクトリが補完される」ディレクトリの事で、VB6やVBAではChDirステートメントで変更する事ができる。

tfkae0124
質問者

お礼

 回答ありがとうございます。    Byteの配列を初めて見たのですが、回答のおかげで理解できました。UBound値も4になっていました。    (1)や(4)のようにお約束になっていることがかなりあるのですね。    わかりやすい解説で理解できました。

関連するQ&A

  • 「コンパイルエラー End Subが必要です。」

    Access2016でファイルを作成しているのですが、下記のVBAを実行しようとすると、「コンパイルエラー End Subが必要です。」とエラーメッセージが返ってきてしまいます。 構文の修正が必要であるとお気づきであれば、その箇所を教えていただけないでしょうか。初歩的な質問で恥ずかしい限りですが、何卒よろしくお願い致します。 Option Compare Database Option Explicit Public Declare PtrSafe Function SetWindowPos Lib "user32" _ (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, _ ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, _ ByVal fuFlags As Long) As Long Public Declare PtrSafe Function GetSystemMenu Lib "user32" _ (ByVal hWnd As Long, ByVal fRever As Long) As Long Public Declare PtrSafe Function RemoveMenu Lib "user32" _ (ByVal hMenu As Long, ByVal uItem As Long, ByVal fuFlags As Long) As Long Public Const SWP_NOMOVE = &H2 Public Const SWP_NOSIZE = &H1 Public Const HWND_TOP = &H0 Public Const SC_SIZE = &HF000 Public Const SC_MAXIMIZE = &HF030 Public Const SC_CLOSE = &HF060 Public Const SC_RESTORE = &HF120 Public Const MF_BYCOMMAND = &H0& Public Sub test() Private Sub Form_Open(Cancel As Integer) Dim hWnd As Long hWnd = Application.hWndAccessApp SetWindowPos hWnd, HWND_TOP, 0, 0, 800, 600, SWP_NOMOVE hWnd = GetSystemMenu(hWnd, 0) RemoveMenu hWnd, SC_SIZE, MF_BYCOMMAND End Sub

  • ExcelVBAでのkernel32(64bit)

    今までExcel2000のVBAから、以下のようなコードを使ってC++で作ったコマンドプロンプトで動くプログラムを動かすプログラムを作っていましたが、これを64bitのWindows7上で動いているExcel2010で使おうとしたらメッセージが出ました。いろいろ調べてみたところ、たぶんDeclareにPtrSafeを付ければ良いようなのですが、その際、他のコードはそのままで良いのでしょうか。特に、コード中のLongはそのままで良いのか気になるのですが...。ちなみに、下記コードの条件コンパイルはネットで調べて見よう見まねで付けたもので、Excel2000のときには付けていないものでした。ご存じの方がいらっしゃいましたらご教授ください。 '------------------------------------------------------------------------------ ' Win32 API関数・定数の宣言 '------------------------------------------------------------------------------ #If VBA7 And Win64 Then '64bit Declare PtrSafe Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, _   ByVal dwMilliseconds As Long) As Long Declare PtrSafe Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, _   ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long #Else '32bit Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, _   ByVal dwMilliseconds As Long) As Long Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, _   ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long #End If Private Const PROCESS_ALL_ACCESS As Long = &H1F0FFF Private Const INFINITE As Long = &HFFFF '------------------------------------------------------------------------------ ' Run '------------------------------------------------------------------------------ Public Sub Run(ByVal project_name As String)   Dim program As String   Dim task_id As Long   Dim h_proc As Variant   program = mdlFunc.ProgramPath() & mdlFunc.ProgramOption(project_name) 'プログラム名   task_id = Shell(program, vbHide)   h_proc = OpenProcess(PROCESS_ALL_ACCESS, False, task_id)   If OpenProcess(PROCESS_ALL_ACCESS, False, task_id) <> vbNull Then     Call WaitForSingleObject(h_proc, INFINITE)     CloseHandle h_proc   End If End Sub

  • GetProcessWorkingSetSizeでエラーが発生します

    VB6で画像処理アプリケーションの開発を行っている者です。 下記記述でワーキングセット領域を変更しようとしていますが、GetProcessWorkingSetSizeの部分でエラーが発生します。 使用PCにより、「問題が発生したため、Visual Basic を終了します。 ご不便をおかけして申し訳ありません。」や有無を言わさず開発環境が終了してしまう場合がありますが、いずれにしても原因が分かりません。 どなたかアドバイスいただけませんでしょうか? よろしくお願い致します。 (標準モジュールで宣言) Declare Function GetCurrentProcessId Lib "kernel32.dll" () As Long Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessID As Long) As Long Declare Function GetProcessWorkingSetSize Lib "kernel32" (ByVal qq As Integer, ByVal pp As Integer, ByVal rr As Integer) As Long Declare Function SetProcessWorkingSetSize Lib "kernel32" (ByVal phph1 As Long, ByVal wkminwkmin1 As Long, ByVal wkmaxwkmax1 As Long) As Long Declare Function GetLastError Lib "kernel32.dll" () As Long (実行部) Sub WorkingSetChange() Dim id As Long 'アプリケーションプログラムのID用変数 Dim ph As Long 'アプリケーションプログラムのハンドル用変数 Dim wkmin As Long '最小ワーキングセット用変数 Dim wkmax As Long '最大ワーキングセット用変数 Dim bret As Long Const PROCESS_SET_QUOTA = &H100 Const PROCESS_QUERY_INFORMATION = &H400 'アプリケーションプログラムのIDを取得する id = GetCurrentProcessId() 'アプリケーションプログラムのハンドルをオープンする ph = OpenProcess(PROCESS_SET_QUOTA + PROCESS_QUERY_INFORMATION, False, id) 'アプリケーションプログラムの最大ワーキングセット値と最小ワーキングセット値を取得 bret = GetProcessWorkingSetSize(ph, wkmin, wkmax) '最小ワーキングセット値を1MBに設定 wkmin = 1 * 1024 * 1024 '最大ワーキングセット値を3MBに設定 wkmax = 3 * 1024 * 1024 'アプリケーションプログラムの最大ワーキングセット値と最小ワーキングセット値を変更 bret = SetProcessWorkingSetSize(ph, wkmin, wkmax) 'アプリケーションプログラムのハンドルをクローズする bret = CloseHandle(ph) End Sub

  • EXCELVBA フォルダ検索API

    エクセルからVBAでフォルダを選択させるコマンドを、APIを使ってフォルダ検索ダイアログボックスを出すまでは見よう見真似でできるのですが、このとき「あたらしいフォルダ」のボタンは必要ないので出したくないのですが、どこかに定数を指定すればよろしいかご存知でしたら教えてください。 (使用OS: Windows2000,Excel:2003) ちなみにコピペした宣言部分は以下のものです。 *************** Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _ (ByVal pidl As Long, ByVal pszPath As String) As Long Declare Function SHBrowseForFolder Lib "shell32.dll" Alias "SHBrowseForFolderA" _ (lpBrowseInfo As BROWSEINFO) As Long Declare Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As Long) Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hwnd As Long, ByVal wMsg As Long, _ ByVal wParam As Long, lParam As Any) As Long Public Const WM_USER = &H400 Public Const BFFM_SETSELECTIONA = (WM_USER + 102) Public Const BFFM_INITIALIZED = 1 ********************

  • ExcelVBAでフォームのタイトルバーで右クリックした場合などに閉じるボタンが有効化されないようにするコード

    Excelのプログラムで、最小化ボタンを有効にし、閉じるボタンを無効にする質問をしたんですが、うまくいったと思ったのですがフォームが開き、タイトルバーで右クリックした場合などは閉じるボタンが有効化されてしまうのでこれを無効のままにするコードを教えてください。 作ったプログラムは以下の通りです。 標準モジュール Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _ (ByVal hWnd As Long, ByVal nIndex As Long) As Long Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Public Declare Function DrawMenuBar Lib "user32" _ (ByVal hWnd As Long) As Long Public Declare Function GetSystemMenu Lib "user32.dll" _ (ByVal hWnd As Long, ByVal bRevert As Long) As Long Public Declare Function EnableMenuItem Lib "user32" _ (ByVal hMenu As Long, ByVal wIDEnableItem As Long, ByVal wEnable As Long) As Long Public Const MF_DISABLED = &H2& Public Const GWL_STYLE = (-16) Public Const WS_MINIMIZEBOX = &H20000 Public Const MF_BYCOMMAND = &H0& Public Const SC_CLOSE = &HF060& Dim hSysMenu As Long UserForm_Initializeプロシージャ Dim fRet As Long Dim hWnd As Long Dim fStyle As Long hWnd = FindWindow("ThunderDFrame", "UserForm1") fStyle = GetWindowLong(hWnd, GWL_STYLE) fStyle = (fStyle Or WS_THICKFRAME Or WS_MINIMIZEBOX) fRet = SetWindowLong(hWnd, GWL_STYLE, fStyle) hSysMenu = GetSystemMenu(hWnd, 0) EnableMenuItem hSysMenu, SC_CLOSE, MF_BYCOMMAND Or MF_DISABLED fRet = DrawMenuBar(hWnd) 回答よろしくお願いします。

  • DataReport(PrintReport)の同期(待ち)について教えてください

    只今、VB6のDataReportを使用して500ページほど 印刷したいのですが100ページほどしか印刷されません。 原因は印刷が完了する前にDataReportの解放を行っているためです。 DataReportの解放前に数秒プログラムを停止させる方法があるのですが できればPrintreportメソッドで出力が完了したかの判断を行いたいです。 それに近い質問があり以下のように実行したのですがうまくいきませんでした。 具体的な解決方法があればとてもありがたいです。 【プログラムロジック.vbs】 '起動プロセスのオープン(状態の取得準備) Public Declare Function OpenProcess Lib "KERNEL32" _ (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _ ByVal dwProcessId As Long) As Long '起動プロセスとのシンクロ(待機する) Public Declare Function WaitForSingleObject Lib "KERNEL32" _ (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long '起動プロセスのクローズ(終了) Public Declare Function CloseHandle Lib "KERNEL32" _ (ByVal hObject As Long) As Long '起動プロセスが実行中か調べる(状態の取得) Public Declare Function GetExitCodeProcess Lib "KERNEL32" _ (ByVal hProcess As Long, lpExitCode As Long) As Long Public Const SYNCHRONIZE = &H100000 Public Const INFINITE = &HFFFF 【プログラムロジック.frm】 Dim IDProcess As Long Dim hProcess As Long Dim ret As Long IDProcess = Control.PrintReport hProcess = OpenProcess(SYNCHRONIZE, 1, IDProcess) ret = WaitForSingleObject(hProcess, INFINITE) ret = CloseHandle(hProcess) 上記方法でテストしたのですが 「IDProcess」には「1」が返ります。 「hProcess」には「0」が返ります。 スプールにJOBがたまるまで「WaitForSingleObject」で WAITされると思ったのですがとくに待ちになりませんでした。 環境はWindowsXP、Windows2003サーバです。 よろしくお願いします。

  • ExcelVBAで他のアプリをスクロールさせたい

    エクセルVBAから 他のアプリのスクロールバーを操作して、指定範囲で画面スクロールしたいと思っています。 キー入力では操作出来ない(マウス操作でのみスクロールされる)アプリなので、 Sendkeysは使えないのではないかと思い、 APIでハンドルを取得して、 SendMessageすればできるかなと思いましたが、APIについてよく分からないので、 とりあえず、メモ帳で以下を作成してみました。しかし、スクロールされません。 どこがいけないのか教えていただけないでしょうか? よろしくお願いします。 *************** Public Declare Function FindWindowA Lib "User32" (ByVal cnm As String, ByVal cap As String) As Long Public Declare Function SendMessage Lib "User32" Alias "SendMessageA" _ (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long Public Const WM_VSCROLL = &H115 Public Const WM_HSCROLL = &H114 Public Const SB_TOP = &H6& Public Const SB_BOTTOM = &H7& Sub handle_get()  Dim Handle As Long  Dim Ap1 As String  Ap1 = "a.txt - メモ帳"  AppActivate Ap1  Handle = FindWindowA(vbNullString, Ap1)  SendMessage Handle, WM_VSCROLL, SB_BOTTOM, ByVal CLng(0)  SendMessage Handle, WM_HSCROLL, SB_TOP, ByVal CLng(0) End Sub ***************

  • ウエッブ上の画像データの保存

    いつもお世話になっています。 仕事で使ったことがない我流vbユーザーです。 例えば、web上の https://sc.pia.jp/captcha/98066a0d3b053e55c307.jpg の画像をieでは「ファイル」-「名前を付けて保存」でファイルに落とすことができます。 それを Public Declare Function InternetReadFile Lib "wininet.dll" _ (ByVal hFile As Long, _ ByVal sBuffer As Byte, _ ByVal lNumBytesToRead As Long, _ ByVal lNumberOfBytesRead As Long) As Long を使って、ファイルに読み込もうとすると、0バイトしか(?)読めなくて、失敗して戻ってきます。 どこに問題があって、改善したら良いのでしょうか。 経験のある方がおられたら、よろしくおねがいします。

  • VBAでのカーソル移動とマウスクリック

    業務上の単純作業の自動化のため、VBAから他のアプリケーションを操作することが目的です。 以前、ブラウザ上での作業の時に使用した、下記2つのAPIでは今回はマウスカーソルが指定した座標に動いてくれません、、、 Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal Y As Long) As Long Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long) この2つのAPI以外で、カーソル移動とマウスクリックを実現する方法は何かありますでしょうか? 色々な方法を教えていただけるとVBAの勉強にもなり幸いです。 ' // 標準モジュール Option Explicit Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal Y As Long) As Long Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long) Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long) Private Type POINTAPI     x As Long     y As Long End Type Private Sub クリックテスト() Call SetCursorPos(216, 421) Sleep 400 Call mouse_event(&H2, 0, 0, 0, 0) Call mouse_event(&H4, 0, 0, 0, 0) End Sub

  • Formを動かせるようにしたい

    お世話になります。 OS XP PRO  VB6(SP5)で開発しています。 ディスプレイのサイズによりFormを動かせたり固定させたりしたいのですが、 規定値は固定にしたいのでFormプロパティのMoveableはFalseにしてあります。 下記のようにプログラミングしたのですが固定されたままです。 Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long Private Declare Function GetSystemMenu Lib "user32" (ByVal _ hwnd As Long _ , ByVal bRevert As Long) As Long Private Declare Function RemoveMenu Lib "user32" ( _ ByVal hMenu As Long, ByVal nPosition As Long, _ ByVal wFlags As Long) As Long Private Declare Function DrawMenuBar Lib "user32" ( _ ByVal hwnd As Long) As Long Private Const MF_BYCOMMAND = &H0 Private Const SC_MOVE = &HF010 Private Sub Form_Load() Dim kk As Long kk = GetSystemMenu(.hwnd, bb) Call RemoveMenu(kk, SC_MOVE, MF_BYCOMMAND) Call DrawMenuBar(.hwnd) End Sub アドバイス頂きたくよろしくお願いします。 以上です。