inkscapec.exe - A Command Line Wrapper for Win32

Inkscape 0.46 is finally out of the door and there are builds for all platforms (well, the important ones) available. Unfortunately I wasn't able to get this little executable into the Win32 builds. If you've read my previous posts you might have an idea what it's all about.

In a nutshell it's a tiny console application, which spawns Inkscape (with the specified arguments) and captures its stdout (default output) and stderr (default error output) streams and redirects it to this console. It also does the same with stdin for good measure. It's sole purpose is direct command line interaction (and determining which actions trigger GTK warnings). If you want to spawn Inkscape from other programs/scripts use inkscape.exe instead.

So, with this little application we get something that behaves like a console build of Inkscape, which means that we actually get some feedback if we're using some command line switches. All that for a mere 21kb. For comparison: a separate Inkscape build would have added another 12.5mb.

PNG export example:

C:\Inkscape-0.46>inkscapec.exe -e image.png ext.svg
Background RRGGBBAA: ffffff00
Area 0:0:64:64 exported to 64 x 64 pixels (90 dpi)
Bitmap saved as: image.png

It's written in C++ and a lot longer than the other 2 solutions. Unlike those old ones it's asynchronous, which means you get the messages right away instead having to wait for Inkscape's termination. This is nice if you want to check which action triggers a GTK warning for example.

A few of you may know it as "inker.exe". Aaron Spike suggested "inkscapec.exe", which is sort of along the lines of "java"/"javaw" or "python"/"pythonw"... just the other way around.

#include<windows.h>
#pragma comment(lib,"User32.lib")
void HandleOutput(HANDLE hPipeRead);
DWORD WINAPI RedirThread(LPVOID lpvThreadParam);

HANDLE hChildProcess=NULL;
HANDLE hStdIn=NULL;
BOOL bRunThread=TRUE;

int main(int argc,char *argv[]){
    HANDLE hOutputReadTemp,hOutputRead,hOutputWrite;
    HANDLE hInputWriteTemp,hInputRead,hInputWrite;
    HANDLE hErrorWrite;
    HANDLE hThread;
    DWORD ThreadId;
    SECURITY_ATTRIBUTES sa;

    sa.nLength=sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor=NULL;
    sa.bInheritHandle=TRUE;

    DWORD i;
    CHAR cmd[32767];
    cmd[0]='\0';
    strcat(cmd,"inkscape.exe");
    for(i=1;i<argc;i++){
        strcat(cmd," ");
        strcat(cmd,argv[i]);
    }

    CreatePipe(&hOutputReadTemp,&hOutputWrite,&sa,0);
    DuplicateHandle(GetCurrentProcess(),hOutputWrite,GetCurrentProcess(),&hErrorWrite,0,TRUE,DUPLICATE_SAME_ACCESS);
    CreatePipe(&hInputRead,&hInputWriteTemp,&sa,0);
    DuplicateHandle(GetCurrentProcess(),hOutputReadTemp,GetCurrentProcess(),&hOutputRead,0,FALSE,DUPLICATE_SAME_ACCESS);
    DuplicateHandle(GetCurrentProcess(),hInputWriteTemp,GetCurrentProcess(),&hInputWrite,0,FALSE,DUPLICATE_SAME_ACCESS);
    CloseHandle(hOutputReadTemp);
    CloseHandle(hInputWriteTemp);

    hStdIn=GetStdHandle(STD_INPUT_HANDLE);

    //-
    PROCESS_INFORMATION pi;
    STARTUPINFO si;

    ZeroMemory(&si,sizeof(STARTUPINFO));
    si.cb=sizeof(STARTUPINFO);
    si.dwFlags=STARTF_USESTDHANDLES;
    si.hStdOutput=hOutputWrite;
    si.hStdInput=hInputRead;
    si.hStdError=hErrorWrite;

    CreateProcess(NULL,cmd,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi);

    hChildProcess=pi.hProcess;

    CloseHandle(pi.hThread);
    //-

    CloseHandle(hOutputWrite);
    CloseHandle(hInputRead);
    CloseHandle(hErrorWrite);

    hThread=CreateThread(NULL,0,RedirThread,(LPVOID)hInputWrite,0,&ThreadId);

    HandleOutput(hOutputRead);

    CloseHandle(hStdIn);

    bRunThread=FALSE;

    WaitForSingleObject(hThread,INFINITE);
    CloseHandle(hOutputRead);
    CloseHandle(hInputWrite);

    return 0;
}

void HandleOutput(HANDLE hPipeRead){
    CHAR lpBuffer[256];
    DWORD nRead;
    DWORD nWrote;

    while(TRUE){
        if(!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),&nRead,NULL)||!nRead)
            if(GetLastError()==ERROR_BROKEN_PIPE)
                break;
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,nRead,&nWrote,NULL);
    }
}

DWORD WINAPI RedirThread(LPVOID lpvThreadParam){
    CHAR buff[256];
    DWORD nRead,nWrote;
    HANDLE hPipeWrite=(HANDLE)lpvThreadParam;

    while(bRunThread){
        ReadConsole(hStdIn,buff,1,&nRead,NULL);

        buff[nRead]='\0';

        if(!WriteFile(hPipeWrite,buff,nRead,&nWrote,NULL)){
            if(GetLastError()==ERROR_NO_DATA)
                break;
        }
    }
    return 1;
}

As usual the code is available under a zero-clause BSD-style license. You can compile it with Dev-Cpp (mingw32) for example. The code itself is sort of bad, I guess (it works fine though). Well, I don't write a lot of C++. So, please excuse my sloppiness. ;)

Download: inkscapec.exe (21kb - put it into the Inkscape's main directory)

Comments

Thank you so very much!!!

This is exactly what I've been looking for to convert SVG to PDF.

Post new comment

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options