Search code examples
c++winapimetafile

EmfToWmfBits api always returns 0


I want to use the EmfToWmfBits api. And first I will try to create a Metafile class then call this api. I think the problem is in the way I create the class.

 Metafile myMetafile(szArglist[1]);

This way gives me the object myMetafile, but it contains nothing. I mean the nativeimage in this object is NULL, which is supposed to point to the metafile on my disk. So later when I call the EmfToWmfBits api, it gives me zero.

I guess the problem might be the Metafile class should take a wchar string. And the filename on the disk is not wchar? I tried like this.

 Metafile myMetafile(L"bird.emf");

And also this.

 Metafile myMetafile(L"鸟.emf");

I am sure that the emf file is in the same directory with the exe. But all of them failed.

This is the code I used.

#include <iostream>
#include <stdio.h>
#include <WINDOWS.H>
#include <shellapi.h>
#include <gdiplus.h>

#pragma comment(lib,"gdiplus.lib")
#pragma comment(lib, "shell32.lib")

using namespace Gdiplus;


int main(int argc, char **argv)
{
    UINT size1 = 0;
    int argcount;
    LPWSTR* szArglist;

    if (argc < 2) {
        std::cout << "Please input a file name" << std::endl;
        return 0;
    }


    szArglist = CommandLineToArgvW(GetCommandLineW(), &argcount);
    Metafile myMetafile(szArglist[1]);
    LocalFree(szArglist);
    HENHMETAFILE hEmf = myMetafile.GetHENHMETAFILE();
    size1 = Metafile::EmfToWmfBits(
        hEmf,
        0,
        NULL,
        MM_ANISOTROPIC,
        EmfToWmfBitsFlagsEmbedEmf);
    std::cout << size1 << std::endl;

}

Normally, this EmfToWmfBits api should return the length of the converted file. The detail of this api is here. https://learn.microsoft.com/en-us/windows/win32/api/gdiplusheaders/nf-gdiplusheaders-metafile-emftowmfbits I would appreciate if anyone can help me here.


Solution

  • You need to initialize GDI+.

    The GdiplusStartup function initializes Windows GDI+. Call GdiplusStartup before making any other GDI+ calls, and call GdiplusShutdown when you have finished using GDI+.

    Add:

    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    

    This is the modified code, for reference only.

    #include <iostream>
    #include <stdio.h>
    #include <WINDOWS.H>
    #include <shellapi.h>
    #include <gdiplus.h>
    #include <Shlwapi.h>
    
    #pragma comment (lib,"Shlwapi.lib")
    #pragma comment(lib,"gdiplus.lib")
    #pragma comment(lib, "shell32.lib")
    
    using namespace Gdiplus;
    
    int main(int argc, char **argv)
    {
        UINT size1 = 0;
        WCHAR path[MAX_PATH];
    
        GdiplusStartupInput gdiplusStartupInput;
        ULONG_PTR gdiplusToken;
        GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    
        GetModuleFileNameW(NULL, path, MAX_PATH);
        PathRemoveFileSpecW(path);
        PathAppendW(path, L"temp.emf");
        Metafile myMetafile(path);
    
        HENHMETAFILE hEmf = myMetafile.GetHENHMETAFILE();
        size1 = Metafile::EmfToWmfBits(
            hEmf,
            0,
            NULL,
            MM_ANISOTROPIC,
            EmfToWmfBitsFlagsEmbedEmf);
        std::cout << size1 << std::endl;
        GdiplusShutdown(gdiplusToken);
        return 0;
    }
    

    I use GetModuleFileNameW to retrieve the fully qualified path for the file that contains the specified module.