1

getJob()を 64 ビットの printerspooler API から動作させようとしています。

私は次の定義を使用します(他の人がSOで使用しているように)

[DllImport("winspool.drv", EntryPoint = "GetJob", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetJob([In] IntPtr hPrinter, [In] Int32 dwJobId, [In] Int32 Level, [Out] IntPtr lpJob, [In] Int32 cbBuf, ref IntPtr lpbSizeNeeded);

しかし、これはデバッグ中でなく、64ビットではない場合にのみ機能します。

64ビットでは、Windowsエラーが発生します:パラメーターが正しくありません。

これを修正するにはどうすればよいですか?

Int32 を IntPtr (64 ビットで 4=>8 バイト) に変更し、逆の IntPtr => Int32 に変更してみました。無駄に..

ドキュメントはこちら: https://docs.microsoft.com/en-us/windows/desktop/printdocs/getjob :

BOOL GetJob(
  _In_  HANDLE  hPrinter,
  _In_  DWORD   JobId,
  _In_  DWORD   Level,
  _Out_ LPBYTE  pJob,
  _In_  DWORD   cbBuf,
  _Out_ LPDWORD pcbNeeded
);

また、ref を out に変更し、ref/out を lpJob パラメータに入れてみましたが、これでもうまくいかないようです。

次に何を試すことができますか?

編集

うまくいくように見えるのは次のとおりです。

[DllImport("winspool.drv", EntryPoint = "GetJob", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetJob([In] IntPtr hPrinter, [In] Int32 dwJobId, [In] Int32 Level, [Out] byte[] lpJob, [In] Int32 cbBuf, ref Int32 lpbSizeNeeded);

次のように使用します。

public JOB_INFO_1(IntPtr hPrinter, Int32 dwJobId)
{
  var BytesWritten = new Int32();
  var ptBuf = new byte[0];


  if (PrinterMonitorComponent.ComponentTraceSwitch.TraceVerbose)
    Console.WriteLine("JOB_INFO_1 new(" + hPrinter.ToString() + "," + dwJobId.ToString() + ")");


  // \\ Get the required buffer size
  if (!UnsafeNativeMethods.GetJob(hPrinter, dwJobId, 1, ptBuf, 0, ref BytesWritten))
  {
    if (BytesWritten == 0)
    {
      var ex = new Win32Exception();
      if (PrinterMonitorComponent.ComponentTraceSwitch.TraceError)
        Console.WriteLine("{0} GetJob for JOB_INFO_1 failed on handle: {1} for job: {2} - {3}", this.GetType().ToString(), hPrinter, dwJobId, ex.Message);
      throw ex;
    }
  }

  // \\ Allocate a buffer the right size
  if (BytesWritten > 0)
    ptBuf = new byte[BytesWritten]; // Marshal.AllocHGlobal(BytesWritten);

  //Console.WriteLine($"Buffer {BytesWritten} x"); // uncommenting this code somehow breaks it again -.-
  // \\ Populate the JOB_INFO_1 structure
  if (!UnsafeNativeMethods.GetJob(hPrinter, dwJobId, 1, ptBuf, BytesWritten, ref BytesWritten))
  {
    if (PrinterMonitorComponent.ComponentTraceSwitch.TraceError)
      Console.WriteLine("GetJob for JOB_INFO_1 failed on handle: " + hPrinter.ToString() + " for job: " + dwJobId, this.GetType().ToString());
    throw new Win32Exception();
  }
  else
  {
    GCHandle handle = GCHandle.Alloc(ptBuf, GCHandleType.Pinned);
    Marshal.PtrToStructure(handle.AddrOfPinnedObject(), this);
    handle.Free();
    //Marshal.PtrToStructure(ptBuf, this);

  }

  // \\ Free the allocated memory
  //Marshal.FreeHGlobal(ptBuf);
}

編集2

動作しないようですが、動作するように見えることもありますが、単体テストでは csproj ファイルの変更に気付かなかったので、最終的に 32 ビットに対してテストを続けていました。

csproj に次の行を追加すると機能します (32 ビットで実行し、64 ビットにすると失敗します)。

<PlatformTarget>x86</PlatformTarget>
4

1 に答える 1