- PR -

GUI登録されたタスクの編集

投稿者投稿内容
内線110
会議室デビュー日: 2004/11/23
投稿数: 1
投稿日時: 2004-11-23 22:46
初めまして、内線110です。

WindowsXP上で、他のアプリケーションが登録したスケジュール(タスク)に対して横やりを入れたいと考えています。しかしいろいろと試してみましたが、なかなかうまくいく方法が見つからないので投稿させていただきました。

[開発環境]
Windows XP SP1
VisualStudio .net 2003
[開発言語]
VB.net
[実行環境]
WindowsXP SP1

こちらの過去の投稿にもあった方法ではありますが、今までに試した方法と状況は以下の通りです。

WMI経由でWin32_ScheduleJobを・・・
  ---> GUIベースで登録したものには対応していないそうです。
  http://www.microsoft.com/japan/technet/scriptcenter/schedule/default.mspx

API経由でNetScheduleJob〜を・・・
  ---> 後述

ファイルを解析して・・・
  ---> 早々にリタイアしました

というわけで、現在はAPI経由で以下のようなサンプルを作ってみましたが、エラーコード(戻り値:lngApiResult)が1702になり、頓挫しています。長々とで申し訳ありませんが添付しましたコード上の問題点、やり方の問題点などご教授いただけたらと思います。よろしくお願いします。

-------------[ code ]----------------
'************
'タスクを取得
'************
Private Declare Auto Function NetScheduleJobEnum Lib "netapi32.dll" _
( _
 ByVal ServerName As String, _
 ByRef PointerToBuffer As Long, _
 ByVal PreferredMaximumLength As Long, _
 ByRef EntriesRead As Long, _
 ByRef TotalEntries As Long, _
 ByRef ResumeHandle As Long _
) As Long
'************
'メモリ解放
'************
Private Declare Auto Function NetApiBufferFree Lib "netapi32.dll" _
( _
 ByVal Buffer As Long _
) As Long
'************
'メモリ移動
'************
Private Declare Auto Sub RtlMoveMemory Lib "Kernel32.dll" _
( _
 ByRef Destination As AT_ENUM, _
 ByRef Source As Long, _
 ByVal Length As Long _
)
'************
'定数、クラス
'************
Private Const MAX_PREF_LEN = -1&
Private Const NERR_Success = 0
Private Const ERROR_MORE_DATA = 234&
Private Class AT_ENUM
 Public JobId As Long
 Public JobTime As Long
 Public DaysOfMonth As Long
 Public DaysOfWeek As Byte
 Public Flags As Byte
 Public dummy As Integer
 Public Command As Long
End Class
'************
'タスク取得
'************
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 Dim lngApiResult As Long

 Dim strServerName As String
 Dim lngBufferPointer As Long
 Dim lngEntriesRead As Long
 Dim lngTotalEntries As Long
 Dim lngResumeHandle As Long = Nothing
 Dim lngEntry As Long
 Dim udtAtEnum As AT_ENUM

 Dim lngTemp As Long
 Dim varTemp

 strServerName = ""

 '取得
 lngApiResult = _
  NetScheduleJobEnum( _
   strServerName, _
   lngBufferPointer, _
   MAX_PREF_LEN, _
   lngEntriesRead, _
   lngTotalEntries, _
   lngResumeHandle _
  )

 If (lngApiResult = NERR_Success) Or (lngApiResult = ERROR_MORE_DATA) Then
  For lngEntry = 0 To lngEntriesRead - 1
   lngTemp = lngBufferPointer + Len(udtAtEnum) * lngEntry
   RtlMoveMemory(udtAtEnum, lngTemp, Len(udtAtEnum))
  Next
 End If

 'メモリ解放
 If lngBufferPointer <> 0 Then
  NetApiBufferFree(lngBufferPointer)
 End If

End Sub



[ メッセージ編集済み 編集者: 内線110 編集日時 2004-11-23 22:48 ]
未記入
会議室デビュー日: 2005/08/09
投稿数: 4
投稿日時: 2005-08-09 15:19
はじめまして。Micaです。

投稿された件、解決しましたでしょうか???
実は同じような現象が起きていまして、調査しているうちににここにたどり着きました。
6.0で試してみたところ、ServerNameを指定すると上手くいくことがわかりました。
""だと1702が返ってきます。
そこでVB.Netで同じように試してみたところ、訳のわからない、桁数が随分多い値が返ってきました。
古い投稿に対して、しかも返信ではなくて申し訳ありませんが、もし解決済みであれば、ご教授いただけませんでしょうか???
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2005-08-09 15:38
件名のことについては全く詳しくありませんが、Micaさんの現象はおそらく数値型に関する変更が原因だと思います。
VB6まではLongは32ビット値でしたが、VB.NETになってLongは64ビット値に変わり、Integerがその代わりに32ビット値になりました。
またVB6の16ビット値であるInteger型はVB.NETではShort型になっています。
未記入
会議室デビュー日: 2005/08/09
投稿数: 4
投稿日時: 2005-08-12 15:57
Hongliangさま、お返事ありがとうございます。
ご指摘のとおり数値の型を変えてみましたところ、エラーコードに正しい数値が返ってくるようになり、取得も上手くいっているようです。(lngEntriesReadの値が正しいので、上手くいっていると仮定)・・・が、


lngTemp = lngBufferPointer + Len(udtAtEnum) * lngEntry
RtlMoveMemory(udtAtEnum, lngTemp, Len(udtAtEnum))


で構造体「udtAtEnum.JobId」にポインタがそのまま入ってきてしまい、中身の参照ができません。
お気づきの点があればご教授ください。
よろしくお願いいたします。
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2005-08-12 16:42
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=21701&forum=7&2
多分こんな感じでしょう。
.NETでポインタから構造体にするには、System.Runtime.IntoperServices.Marshal.PtrToStrucureメソッドを使用します。
未記入
会議室デビュー日: 2005/08/09
投稿数: 4
投稿日時: 2005-08-12 18:04
Hongliangさま、早速のお返事ありがとうございます。
前投稿の直後後、調査を続けていましたらそのサンプルを見つけ、現在挑戦中ですが、上手くいきません。。。


Dim obj As Object = System.Runtime.InteropServices.Marshal.PtrToStructure(current, wts)


で、値を生成できないとコンパイルエラーになります。
どのようにしたら戻り値を取得できるようになるのでしょうか???
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2005-08-12 18:33
あはは、コードを見返して唯一気になった点がばっちりヒットしちゃったようです。
コード:
Dim wts = GetType(WTS_SESSION_INFO)


ここでwtsが型指定せずに宣言されていますよね。ですからコンパイラによってObject型であると認識されます。
で、Marshal.PtrToStructureを確認すると
コード:
[Visual Basic] Overloads Public Shared Sub PtrToStructure(IntPtr, Object)
[Visual Basic] Overloads Public Shared Function PtrToStructure(IntPtr, Type) As Object


と二つのオーバーロードが見つかります。
wtsはObject型と認識されますから、上の方のオーバーロードを使っていると認識され……Subだから返値無しなのに返値があるとコーディングしてる、これはエラーだ……という寸法です。

wtsの宣言を型指定してやって下さい。それで解決するはずです。


ところで、
引用:

で、値を生成できないとコンパイルエラーになります。


エラーメッセージはできる限り正しく書くようにしましょう。
「できない」ではなく「しない」となっているはずです。こういうニュアンスも原因推定に重要ですから。
//VS2002のドキュメントエクスプローラでは何故かVB.NETのエラーコードがキーワードでも検索でも引っかからない……。
未記入
会議室デビュー日: 2005/08/09
投稿数: 4
投稿日時: 2005-08-12 20:44
コンパイルエラーとれました。ありがとうございます。
。。。とここで、本来やりたかった処理に戻って、まとめてみました。

コード:

'************ 
'タスク取得 
'************ 
Private Declare Auto Function NetScheduleJobEnum Lib "netapi32.dll" _
( _
 ByVal ServerName As String, _
 ByRef PointerToBuffer As System.IntPtr, _
 ByVal PreferredMaximumLength As Integer, _
 ByRef EntriesRead As Integer, _
 ByRef TotalEntries As Integer, _
 ByRef ResumeHandle As Integer _
) As Integer

'************ 
'定数 
'************ 
Private Const MAX_PREF_LEN = -1&
Private Const NERR_Success = 0
Private Const ERROR_MORE_DATA = 234&

Private Structure AT_INFO
    Public JobId As Long
    Public JobTime As Long
    Public DaysOfMonth As Long
    Public DaysOfWeek As Byte
    Public Flags As Byte
    Public dummy As Integer
    Public Command As String
End Structure

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim lngApiResult As Integer
    Dim strServerName As String
    Dim lngBufferPointer As System.IntPtr
    Dim lngEntriesRead As Long
    Dim lngTotalEntries As Long
    Dim lngResumeHandle As Long = Nothing
    Dim lngEntry As Long

    Dim i As Integer
    Dim typAtInfo As Type
    Dim structSize As Integer

    strServerName = "srv"

    'タスク取得 
    lngApiResult = NetScheduleJobEnum(strServerName, _
                                      lngBufferPointer, _
                                      MAX_PREF_LEN, _
                                      lngEntriesRead, _
                                      lngTotalEntries, _
                                      lngResumeHandle _
                                     )

    typAtInfo = GetType(AT_INFO)
    structSize = System.Runtime.InteropServices.Marshal.SizeOf(typAtInfo)

    If (lngApiResult = NERR_Success) Or (lngApiResult = ERROR_MORE_DATA) Then
        For lngEntry = 0 To lngEntriesRead - 1
            '開始位置から(構造体のサイズ*現在位置)ぶん進めたポインタを取得
            Dim current As New System.IntPtr(lngBufferPointer.ToInt64 + (structSize * i))
            Dim obj As Object = System.Runtime.InteropServices.Marshal.PtrToStructure(current, typAtInfo)

            Dim udtAtInfo As AT_INFO = CType(obj, AT_INFO)

            MsgBox(udtAtInfo.JobId)
        Next
    End If
End Sub




これを実行すると、

Dim obj As Object = System.Runtime.InteropServices.Marshal.PtrToStructure(current, typAtInfo)

にて、「'System.NullReferenceException' のハンドルされていない例外が mscorlib.dll で発生しました。追加情報 : オブジェクト参照がオブジェクト インスタンスに設定されていません。」・・・というエラーが発生します。

currentにはポインタが入ってきているようです。
typAtInfoの型に問題があるのでしょうか???

度々で申し訳ございませんが、お気づきの点があればご教授願います。


スキルアップ/キャリアアップ(JOB@IT)