3

過去 2 週間、これに対する答えを無駄に探しましたが、困惑しています。

私はメタファイルから構築された Graphics オブジェクトからサンプル画像を作成するいくつかのコードを使用しており、Windows.Forms (コンソール アプリ) の必要性を避けるためにすべてメモリ ストリームに常駐しています。関数CopyEnhMetaFile(からインポートgdi32.dll) を使用して、メタファイルを実際の EMF としてディスクに保存します。ここここここ、およびここを参照して、これをどのようにまとめたかについての基本的なメモを確認してください。

単純な main() スクリプト ( codeprojectの例に見られるように) としてトップダウンで記述すると、問題なく動作します。しかし、メソッドを使用してメタファイル/グラフィックス オブジェクトをクラスにバンドルしようとすると、例外が返されるMetafileHandleため、 を取得できません。GetHenhmetafile()parameter is not valid

このソースによると、その例外は、メソッドが以前に少なくとも 1 回呼び出されたことを明確に示しています。しかし、私のコードを見てください。2回呼び出した場所は確かにわかりません。たぶんあなたはできる?

いずれにせよ、これらのオブジェクトを使用する方法 (MemoryStreams、Metafiles、または P/Invoked 関数) に関する基本的なことを完全に理解していないか、C# クラスの方法に関する基本的なことを見逃しているのではないかと強く思います。仕事、そして誰かが私を正しい方向に押し上げてくれることを望んでいました.

[提案に従って、成功したコードに追加し直し、壊れたコードのコンテキストビットのみを残すように編集]

動作したコードは次のとおりです。

class EmfGenerator
{
    static void Main()
    {
        const int width = 450;
        const int height = 325;

        Metafile m;
        using (var stream = new MemoryStream())
        {
            Graphics offScreenBufferGraphics; //this is a throw-away object needed for the deviceContext
            using (offScreenBufferGraphics = Graphics.FromHwndInternal(IntPtr.Zero))
            {
                IntPtr deviceContextHandle = offScreenBufferGraphics.GetHdc();

                m = new Metafile(
                stream,
                deviceContextHandle,
                new RectangleF(0, 0, width, height),
                MetafileFrameUnit.Pixel, //scaling only works properly with integers due to decimal truncation, so use milimeters or pixels here
                EmfType.EmfPlusOnly); //force GDI+ mode
                offScreenBufferGraphics.ReleaseHdc(); //once we have our metafile, we no longer need the context handle
            }
        }

        using (Graphics g = Graphics.FromImage(m))
        {
            //draw a picture
            g.Clear(Color.White);
            //etc...
        } 

        // Save it as a metafile
        IntPtr iptrMetafileHandle = m.GetHenhmetafile();
        CopyEnhMetaFile(iptrMetafileHandle, @"emf_binary_sample.emf"); //this gives us just the metafile
        DeleteEnhMetaFile(iptrMetafileHandle);

    }
}

そして、これが機能しないコードです。1 つの注記: 私は元々、上記の "using" 構造を使用して記述しましたが、同じエラーが発生しました。そのため、使用しているラッパーが何かを破壊するのが早すぎる可能性があるため、それを使用せずに再構築しました。どちらの方法でも同じエラーが発生しました。

class MetafileExperiment
{
    protected Graphics G; //the working graphics object
    protected Metafile M; //the working metafile
    protected IntPtr MetafileHandle;

    public MetafileExperiment(int startingWidth, int startingHeight)
    {
        var stream = new MemoryStream();
        var bfr = Graphics.FromHwndInternal(IntPtr.Zero);
        IntPtr dev = bfr.GetHdc();

        M = new Metafile(
            stream,
            dev,
            new RectangleF(0, 0, startingWidth, startingHeight),
            MetafileFrameUnit.Pixel, //scaling only works properly with integers due to decimal truncation, so use milimeters or pixels here
            EmfType.EmfPlusOnly); //force GDI+ mode

        //the handle is needed in order to use the P/Invoke to save out and delete the metafile in memory.
        MetafileHandle = M.GetHenhmetafile(); // Parameter is not valid 

        bfr.ReleaseHdc(); 

        G = Graphics.FromImage(M);

    }

}    

ご覧のとおりGetHenhmetafile()、メタファイル自体を作成した直後に、コンストラクターに を入れています。このメソッドは、インスタンスごとに 1 回しか呼び出すことができないというメモでこれを行いました (たとえば、こちらを参照してください)。冒険好きの方は、リポジトリ全体をここで見つけることができます。

参考になれば、壊れたコードの例外の詳細を次に示します (内部例外は null です)。

System.ArgumentException was unhandled
  _HResult=-2147024809
  _message=Parameter is not valid.
  HResult=-2147024809
  IsTransient=false
  Message=Parameter is not valid.
  Source=System.Drawing
  StackTrace:
       at System.Drawing.Imaging.Metafile.GetHenhmetafile()
       at SimpleEmfGenerator.MetafileExperiment..ctor(Int32 startingWidth, Int32 startingHeight) in c:\Users\ggauthier\Repositories\Articulate\SimpleEmfGenerator\SimpleEmfGenerator\MetafileExperiment.cs:line 40
       at SimpleEmfGenerator.EmfGenerator.Main() in c:\Users\ggauthier\Repositories\Articulate\SimpleEmfGenerator\SimpleEmfGenerator\EmfGenerator.cs:line 108
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
4

2 に答える 2

0

これが .NET 4.0 で修正されたからなのかどうかはわかりませんが、醜い DllImport に頼らずにメタファイルを保存できます。

C# ではなく VB.NET で申し訳ありませんが、私はこれを使用しています...

Public Shared Sub Test()
    Dim ms As New IO.MemoryStream()
    Dim img As New Bitmap(1000, 1000)
    Dim imgGraphics = Graphics.FromImage(img)
    Dim hdc = imgGraphics.GetHdc()
    Dim mf = New Metafile(ms, hdc, EmfType.EmfPlusOnly)
    imgGraphics.ReleaseHdc()
    ' Important - The above is just a test.  In production code, you should eventually dispose of stuff

    Using g = Graphics.FromImage(mf)
        g.DrawRectangle(Pens.Black, 20, 30, 15, 16)
        g.DrawRectangle(Pens.Black, 140, 130, 15, 16)
    End Using
    ' Note: it's important that the Graphics used to draw into the MetaFile is disposed
    ' or GDI+ won't flush.

    ' Easy Way
    Dim buffer1 = ms.GetBuffer() ' This produces a 444 byte buffer given the example above

    ' The Hard way
    Dim enhMetafileHandle = mf.GetHenhmetafile
    Dim bufferSize = GetEnhMetaFileBits(enhMetafileHandle, 0, Nothing)
    Dim buffer(bufferSize - 1) As Byte
    Dim ret = GetEnhMetaFileBits(enhMetafileHandle, bufferSize, buffer)

End Sub
于 2015-06-22T19:49:56.430 に答える