VideoHelp Forum
+ Reply to Thread
Results 1 to 24 of 24
Thread
  1. Hi all,

    I'd like to have a bash at writing GUI's for a couple of commandline apps I use quite a lot.

    I have a reasonable amount of experience in writing apps in Java, and I also have MS Visual Studio 6 - although I haven't had much experience with it.

    Can anyone recommend:

    1. Which language would be easiest to use (I'd like to use Java, but am not sure how well a Java app would be suited to the task). I'd be open to other suggestions, but preferably not anything where I'd have to pay for the IDE/complier etc..

    2. Any resources/sites which might be useful - google's not been very helpful to me on this one.

    Obviously if I have any success, the result will be freeware! (are there any licensing issues with this if I were to use VS6?)

    cheers,
    mcdruid.
    Quote Quote  
  2. Member
    Join Date
    Sep 2001
    Location
    Japan
    Search Comp PM
    Using VS6 and the redistribution dlls are no problem.Normally all the necessary system dlls are in the Windows OS distribution under system32.
    If your app needs other mcvc... or mfc dlls (in the restribution dir on the VS CD), you can give them away.JAVA is a little difficult in starting external processes.
    The author of svcd2dvd uses .net development, but IMHO VS with MFC is the simplest way to go.
    Quote Quote  
  3. Thanks mate - that's what I thought about Java - and it wouldn't really be taking advantage of the platform independance if I'm writing GUI's for Windoze commandline app's.

    I'll have a look into VS6.

    cheers,
    mcdruid.
    Quote Quote  
  4. Member SaSi's Avatar
    Join Date
    Jan 2003
    Location
    Hellas
    Search Comp PM
    If you decide to use VS6, then your choice would be mainly between C++ and VB.

    Writing a GUI in C++ is hard. While in VB you would drag and drop and resize controls (like textboxes, buttons and checkboxes), in C++ you need to create classes, interfaces and stuff.

    I'm not really into C++. I need to write some C code for a project and a friend created the dll "enclosure" and project and I'm adding relativelly plain C code in it. It's hard.

    Other options would include Delphi. I got hands on Delphi 6, personal edition for free. The CD came with a magazine. I can upgrade to Professional edition or something for $99 but the personal edition is more than enough for writing small apps, like a GUI. And Delphi is very similar to VB in concept.
    The more I learn, the more I come to realize how little it is I know.
    Quote Quote  
  5. Thanks SaSi,

    yeah - I've done a little C, and I wasn't that keen! I've also had to write GUI's for Java app's from scratch without using a visual IDE, which again was not much fun.

    It's sounding like VB might be worth a try - although if I could get hold of a free edition of Delphi, I'd be willing to have a look at that (whenever there's a viable alternative to M$... )

    I'll let you all know how I'm getting on - it sounds like building the GUI (buttons/menus etc..) will not be too hard - but calling the external program might be more tricky!

    Could anyone point me in the direction of a tutorial or something similar about how to do this? As I say, I've not had much luck with Google - maybe I'm searching with the wrong terms.

    cheers,
    mcdruid.
    Quote Quote  
  6. Member
    Join Date
    Dec 2001
    Location
    United States
    Search Comp PM
    Programming GUIs in VC++6 is an exercise in pain. So if you want to use VS6, you definately want to stick with visual basic.

    Another option is to use something like wxwindows with perl or python. wxwindows is a cross-platform GUI framework, and perl/python are scripting languages. All opensource, completely free.
    Quote Quote  
  7. I've written some GUIs ( VCDImager Tools GUI ) with VB5 (similar to VB6) and although some things are easier, there are other things which are a pain in the arse. One limitation (with VB5 at least -- don't know about VB6) is that I don't think you can pipe the output from a command console app.

    This is irritating to say the least -- and I had to use all sorts of tricks to get the GUI for VCDImager Tools GUI to actually know what was happening with the state of the command console apps.

    Regards.
    Michael Tam
    w: Morsels of Evidence
    Quote Quote  
  8. Visual Basic is to programming as Microsoft Frontpage is to HTML with its GI.
    Quote Quote  
  9. Member
    Join Date
    Mar 2003
    Location
    Uranus
    Search Comp PM
    Virtualis
    I'm fascinated with that. If it's not too lengthy
    how do you execute a program and grab its output ?
    All I've found so far is "shell" to execute.
    I know there are strange VB extensions to directly access the API
    but I don't know any of it.
    all I need is a hint.
    Quote Quote  
  10. Member Roderz's Avatar
    Join Date
    Jul 2003
    Location
    the armpit ofthe Midlands
    Search Comp PM
    All I can recomend is Borland C++Builder 6 very easy to throw an app togeather, but you still need to know 'under the bonet'
    Only draw back (or plus?) is that the apps can be bigger because it tends not to relie on MS dll or comctls.

    BTW I just wrote a GUI for ac3fix (not that it really needs one - but did see a request for it this morning)
    Anyone want to try it
    http://www.roderz.pwp.blueyonder.co.uk/euro2/

    BTW should I be posting in the tools section?
    Quote Quote  
  11. Renegade gll99's Avatar
    Join Date
    May 2002
    Location
    Canadian Tundra
    Search Comp PM
    Roderz
    BTW I just wrote a GUI for ac3fix (not that it really needs one - but did see a request for it this morning)
    Anyone want to try it
    http://www.roderz.pwp.blueyonder.co.uk/euro2/

    BTW should I be posting in the tools section?
    If this new thread is to be usefull someone will have to start posting some source code. I could be mistaken but one reason for this area is to provide some help in programming. Don't get me wrong, but testing your gui may be nice but are you willing to share your programming expertise?

    I have an old video capture app lying around (VB code). I didn't write the original (based on MS vbvidcap) but made significant mods to it. I have 3 or 4 test versions and lost my best near final stuff somewhere but still have some of the early rough and dirty source code that someone can toy with. I am willing to post that and some other small sample vb apps from my win95 /win98 vb3,vb4 and vb5 stuff. I have vb6 and c++ but have not spent much time with it. There is lots of vb code all over the net but if the intent is to bring some of that discussion here then I'm all for that.

    I've just noticed this new area so am just geting a feel for it right now.
    Quote Quote  
  12. Originally Posted by FOO
    Virtualis
    I'm fascinated with that. If it's not too lengthy
    how do you execute a program and grab its output ?
    All I've found so far is "shell" to execute.
    I know there are strange VB extensions to directly access the API
    but I don't know any of it.
    all I need is a hint.
    I suggest that you download the source code to VCDImager Tools GUI at http://www.michaeltam.com/vcdimager_tools_gui.html

    What I did was (by scavagening code off the net) the following...

    You can use VB to load/open a "console window". This is actually a function of VB rather than by using the shell command and loading "cmd". Then, in the console window, you can output text into it or run a program in it by using shell. The problem however, remains that the program that is executed by the shell command runs asyncronously with the VB program. However, since the program is running inside the VB console window, you can use a number of functions that grab text out of the console window.

    What I did was for VB to basically loop and "look" at the text in the console window every now and then (every quarter second I believe) looking for specific strings. When it saw it, it would know that the console app had passed a certain stage.

    To my knowledge (which is very limited in VB programming) I don't know any other way to pipe output to the VB app from a command console program (unlike Delphi or VC++). Unfortunately, this method is somewhat ugly as for it to work, VB needs to open a visible console window.

    As to why VB doesn't understand all the standard Windows API calls, I don't know except to say that Microsoft is evil.

    Regards.
    Michael Tam
    w: Morsels of Evidence
    Quote Quote  
  13. Member
    Join Date
    Mar 2003
    Location
    Uranus
    Search Comp PM
    Thank lots.
    I might look into VC++ also as it allows more control.
    VB is just so easy.
    If they would just make the IDE for VC as easy as VB
    I might get productiive.

    I also have .NET and C# looks like it has interesting possibilities.
    Even simple numbers are objects and have properties
    and methods e.g. 1234.ToString()
    Still doesn't help much with the Windows interface.
    Quote Quote  
  14. Member
    Join Date
    Sep 2001
    Location
    Japan
    Search Comp PM
    IF you use MFC with VC++ and the Classwizard, developing a GUI is as easy as VB.The resource editor is very good at that.
    Quote Quote  
  15. Member vhelp's Avatar
    Join Date
    Mar 2001
    Location
    New York
    Search Comp PM
    Hi guys,

    I didn't even know this FORUM existed :P

    Nobody mentioned Delphi for GUI creations

    I've made a few GUIs too. But, I'd also like to point out that you can do
    just as much w/ DELPHI as you can w/ C++ and even if you have DLL's
    that you need to comunicate or write front-end or shells, etc. w/ then DELPHI
    will quite easily do it, and youcan build ALL your GUI's to glory high.

    IMO, Delphi would be the easyiest to play w/ in these areas of GUI's. I know
    that VB is another easy toy too, and I've use it for many years, but Delphi
    all the way for me. Yes, VB can also use DLL's too. You just have to play
    w/ it sometimes.. and..watch out for syntax like "Alias" when dealing w/
    DLL's in VB. They can be tricky to work w/ when trying to cook up a sweet
    dish (gui) or something..

    VB example:
    Private Declare Function apiGetUserName Lib "advapi32.dll" _
    Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

    Delphi example:
    Function BS_VERSION(var buf):buffer; stdcall; external '..\besweet.dll' index 2;

    Anyways.. GUI development is fun stuff ta get into :P

    -vhelp
    Quote Quote  
  16. Member
    Join Date
    Mar 2003
    Location
    Uranus
    Search Comp PM
    I don't see a clear way yet assuming the idea is to
    take control ( fork/exec - spawn) of a console app and essentially
    substitute yourself for stdio.
    I'm an old Unix creature but I don't know how to exec a process and
    open a pipe to it in windows. (or unix either probably)

    I'm still reading.
    Quote Quote  
  17. Member
    Join Date
    Sep 2001
    Location
    Japan
    Search Comp PM
    Originally Posted by FOO
    I don't see a clear way yet assuming the idea is to
    take control ( fork/exec - spawn) of a console app and essentially
    substitute yourself for stdio.
    I'm an old Unix creature but I don't know how to exec a process and
    open a pipe to it in windows. (or unix either probably)

    I'm still reading.
    Here you are (Creating and Piping from MSDN library):

    Creating a Child Process with Redirected Input and Output
    The example in this topic demonstrates how to create a child process from a console process. It also demonstrates a technique for using anonymous pipes to redirect the child process's standard input and output handles. Note that named pipes can also be used to redirect process I/O.


    The CreatePipe function uses the SECURITY_ATTRIBUTES structure to create inheritable handles to the read and write ends of two pipes. The read end of one pipe serves as standard input for the child process, and the write end of the other pipe is the standard output for the child process. These pipe handles are specified in the SetStdHandle function, which makes them the standard handles inherited by the child process. After the child process is created, SetStdHandle is used again to restore the original standard handles for the parent process.

    The parent process uses the other ends of the pipes to write to the child process's input and read the child process's output. The handles to these ends of the pipe are also inheritable. However, the handle must not be inherited. Before creating the child process, the parent process must use DuplicateHandle to create a duplicate of the application-defined hChildStdinWr global variable that cannot be inherited. It then uses CloseHandle to close the inheritable handle. For more information, see Pipes.

    The following is the parent process.

    #include <stdio.h>
    #include <windows.h>

    #define BUFSIZE 4096

    HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
    hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
    hInputFile, hSaveStdin, hSaveStdout;

    BOOL CreateChildProcess(VOID);
    VOID WriteToPipe(VOID);
    VOID ReadFromPipe(VOID);
    VOID ErrorExit(LPTSTR);
    VOID ErrMsg(LPTSTR, BOOL);

    DWORD main(int argc, char *argv[])
    {
    SECURITY_ATTRIBUTES saAttr;
    BOOL fSuccess;

    // Set the bInheritHandle flag so pipe handles are inherited.

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

    // The steps for redirecting child process's STDOUT:
    // 1. Save current STDOUT, to be restored later.
    // 2. Create anonymous pipe to be STDOUT for child process.
    // 3. Set STDOUT of the parent process to be write handle to
    // the pipe, so it is inherited by the child process.
    // 4. Create a noninheritable duplicate of the read handle and
    // close the inheritable read handle.

    // Save the handle to the current STDOUT.

    hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    // Create a pipe for the child process's STDOUT.

    if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
    ErrorExit("Stdout pipe creation failed\n");

    // Set a write handle to the pipe to be STDOUT.

    if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
    ErrorExit("Redirecting STDOUT failed");

    // Create noninheritable read handle and close the inheritable read
    // handle.

    fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
    GetCurrentProcess(), &hChildStdoutRdDup , 0,
    FALSE,
    DUPLICATE_SAME_ACCESS);
    if( !fSuccess )
    ErrorExit("DuplicateHandle failed");
    CloseHandle(hChildStdoutRd);

    // The steps for redirecting child process's STDIN:
    // 1. Save current STDIN, to be restored later.
    // 2. Create anonymous pipe to be STDIN for child process.
    // 3. Set STDIN of the parent to be the read handle to the
    // pipe, so it is inherited by the child process.
    // 4. Create a noninheritable duplicate of the write handle,
    // and close the inheritable write handle.

    // Save the handle to the current STDIN.

    hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);

    // Create a pipe for the child process's STDIN.

    if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
    ErrorExit("Stdin pipe creation failed\n");

    // Set a read handle to the pipe to be STDIN.

    if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
    ErrorExit("Redirecting Stdin failed");

    // Duplicate the write handle to the pipe so it is not inherited.

    fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
    GetCurrentProcess(), &hChildStdinWrDup, 0,
    FALSE, // not inherited
    DUPLICATE_SAME_ACCESS);
    if (! fSuccess)
    ErrorExit("DuplicateHandle failed");

    CloseHandle(hChildStdinWr);

    // Now create the child process.

    fSuccess = CreateChildProcess();
    if (! fSuccess)
    ErrorExit("Create process failed");

    // After process creation, restore the saved STDIN and STDOUT.

    if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))
    ErrorExit("Re-redirecting Stdin failed\n");

    if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
    ErrorExit("Re-redirecting Stdout failed\n");

    // Get a handle to the parent's input file.

    if (argc > 1)
    hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL,
    OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
    else
    hInputFile = hSaveStdin;

    if (hInputFile == INVALID_HANDLE_VALUE)
    ErrorExit("no input file\n");

    // Write to pipe that is the standard input for a child process.

    WriteToPipe();

    // Read from pipe that is the standard output for child process.

    ReadFromPipe();

    return 0;
    }

    BOOL CreateChildProcess()
    {
    PROCESS_INFORMATION piProcInfo;
    STARTUPINFO siStartInfo;
    BOOL bFuncRetn = FALSE;

    // Set up members of the PROCESS_INFORMATION structure.

    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

    // Set up members of the STARTUPINFO structure.

    ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
    siStartInfo.cb = sizeof(STARTUPINFO);

    // Create the child process.

    bFuncRetn = CreateProcess(NULL,
    "child", // command line
    NULL, // process security attributes
    NULL, // primary thread security attributes
    TRUE, // handles are inherited
    0, // creation flags
    NULL, // use parent's environment
    NULL, // use parent's current directory
    &siStartInfo, // STARTUPINFO pointer
    &piProcInfo); // receives PROCESS_INFORMATION

    if (bFuncRetn == 0) {
    ErrorExit("CreateProcess failed\n");
    return 0;
    } else {
    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);
    return bFuncRetn;
    }
    }
    }

    VOID WriteToPipe(VOID)
    {
    DWORD dwRead, dwWritten;
    CHAR chBuf[BUFSIZE];

    // Read from a file and write its contents to a pipe.

    for (;;)
    {
    if (! ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ||
    dwRead == 0) break;
    if (! WriteFile(hChildStdinWrDup, chBuf, dwRead,
    &dwWritten, NULL)) break;
    }

    // Close the pipe handle so the child process stops reading.

    if (! CloseHandle(hChildStdinWrDup))
    ErrorExit("Close pipe failed\n");
    }

    VOID ReadFromPipe(VOID)
    {
    DWORD dwRead, dwWritten;
    CHAR chBuf[BUFSIZE];
    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    // Close the write end of the pipe before reading from the
    // read end of the pipe.

    if (!CloseHandle(hChildStdoutWr))
    ErrorExit("Closing handle failed");

    // Read output from the child process, and write to parent's STDOUT.

    for (;;)
    {
    if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead,
    NULL) || dwRead == 0) break;
    if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL))
    break;
    }
    }

    VOID ErrorExit (LPTSTR lpszMessage)
    {
    fprintf(stderr, "%s\n", lpszMessage);
    ExitProcess(0);
    }

    // The code for the child process.

    #include <windows.h>
    #define BUFSIZE 4096

    VOID main(VOID)
    {
    CHAR chBuf[BUFSIZE];
    DWORD dwRead, dwWritten;
    HANDLE hStdin, hStdout;
    BOOL fSuccess;

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    hStdin = GetStdHandle(STD_INPUT_HANDLE);
    if ((hStdout == INVALID_HANDLE_VALUE) ||
    (hStdin == INVALID_HANDLE_VALUE))
    ExitProcess(1);

    for (;;)
    {
    // Read from standard input.
    fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
    if (! fSuccess || dwRead == 0)
    break;

    // Write to standard output.
    fSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);
    if (! fSuccess)
    break;
    }
    }
    Quote Quote  
  18. Member dlawedor's Avatar
    Join Date
    May 2003
    Location
    Grosskrotzenburg, Germany
    Search Comp PM
    You can use this code snippet out of all mfc-code to start a childprocess... it works ...

    implementation:

    #include "stdafx.h"
    #include "ORProcessMgr.h"

    CORProcessMgr::CORProcessMgr(void)
    {
    m_bProcess = FALSE;
    m_sProcName.Empty();
    m_sCmdLine.Empty();

    m_hwndWnd = NULL;
    ZeroMemory(&m_si, sizeof(m_si));
    m_si.cb = sizeof(m_si);
    ZeroMemory(&m_pi, sizeof(m_pi));
    }

    CORProcessMgr::~CORProcessMgr(void)
    {
    if(m_bProcess == TRUE)
    StopProcess();
    }

    void CORProcessMgr::Init(CString sProcName, CString sCmdLine)
    {
    if(m_bProcess == TRUE)
    StopProcess();

    m_hwndWnd = NULL;
    ZeroMemory(&m_si, sizeof(m_si));
    m_si.cb = sizeof(m_si);
    ZeroMemory(&m_pi, sizeof(m_pi));
    m_sProcName = sProcName;
    m_sCmdLine = sCmdLine;
    }

    BOOL CORProcessMgr::StartProcess(void)
    {
    char * pCmdLine = NULL;
    if(!m_sCmdLine.IsEmpty())
    {
    pCmdLine = m_sCmdLine.GetBuffer(m_sCmdLine.GetLength() + 1);
    m_sCmdLine.ReleaseBuffer();
    }

    LPCTSTR pProcName = NULL;
    if(!m_sProcName.IsEmpty())
    pProcName = (LPCTSTR)m_sProcName;

    if(!pCmdLine && !pProcName)
    {
    return FALSE;
    }

    // Prozess starten
    if(!CreateProcess(pProcName, // Modulname
    pCmdLine, // Kommandozeilenparameter
    NULL, // Vererbung Processhandle
    NULL, // Vererbung Threadhandle
    FALSE, // Vererbung unterbinden
    0, // Creationflags
    NULL, // Environment-Block
    NULL, // StartVerzeichnis
    &m_si, // Startup-Info
    &m_pi)) // Process-Info
    {
    CString sErrMsg;
    sErrMsg.Format("Konnte Prozess %s nicht starten !", m_sProcName);
    AfxMessageBox(sErrMsg, MB_OK | MB_ICONERROR);
    return FALSE;
    }

    m_bProcess = TRUE;
    return TRUE;
    }

    void CORProcessMgr::StopProcess(void)
    {
    if(m_bProcess == FALSE)
    return;

    ::CloseHandle(m_pi.hProcess);
    HANDLE process = OpenProcess(PROCESS_TERMINATE, 0, m_pi.dwProcessId);
    ::TerminateProcess(process, 0);
    Sleep(400);

    m_bProcess = FALSE;
    }

    the class header:

    #ifndef __ORPROCESSMGR__
    #define __ORPROCESSMGR__ 1

    class CORProcessMgr : public CObject
    {
    public:
    CORProcessMgr(void);
    ~CORProcessMgr(void);

    BOOL StartProcess(void);
    void StopProcess(void);
    void Init(CString sProcName, CString sCmdLine);

    BOOL m_bProcess;

    protected:
    HWND m_hwndWnd;
    STARTUPINFO m_si;
    PROCESS_INFORMATION m_pi;
    CString m_sProcName;
    CString m_sCmdLine;
    };

    #endif

    Much luck and success ... dlawedor [/b]
    In the middle of every difficulty lies opportunity. Albert Einstein
    Quote Quote  
  19. Member
    Join Date
    Sep 2001
    Location
    Japan
    Search Comp PM
    Nice try, but you missed the bit about redirecting stdin/stdout.
    Quote Quote  
  20. Member
    Join Date
    Mar 2003
    Location
    Uranus
    Search Comp PM
    Obviosly I'm no expert at this, but why does it take
    so much code to start another process

    doesn't spawn() jut do it in one line ?
    Quote Quote  
  21. Member
    Join Date
    Sep 2001
    Location
    Japan
    Search Comp PM
    Originally Posted by FOO
    Obviosly I'm no expert at this, but why does it take
    so much code to start another process

    doesn't spawn() jut do it in one line ?
    Under MS-DOS, it would have done.But you are in a Windows environment abd you want some control over the process.
    And most of the code is beacuse of security reason.You don't really want to give some unknown proccess all the rights, don't you?
    Quote Quote  
  22. Member dlawedor's Avatar
    Join Date
    May 2003
    Location
    Grosskrotzenburg, Germany
    Search Comp PM
    Baldrick ... I think it would be a nice thing to offer a own forum-section for those questions (programming or lets say developing something) ... so it is easier to search for and to find it ... what do you think about it !!! :P dlawedor
    In the middle of every difficulty lies opportunity. Albert Einstein
    Quote Quote  
  23. I'm a MEGA Super Moderator Baldrick's Avatar
    Join Date
    Aug 2000
    Location
    Sweden
    Search Comp PM
    Originally Posted by dlawedor
    Baldrick ... I think it would be a nice thing to offer a own forum-section for those questions (programming or lets say developing something) ... so it is easier to search for and to find it ... what do you think about it !!! :P dlawedor
    okey....done.
    Quote Quote  
  24. Member dlawedor's Avatar
    Join Date
    May 2003
    Location
    Grosskrotzenburg, Germany
    Search Comp PM
    thanx, dlawedor
    In the middle of every difficulty lies opportunity. Albert Einstein
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!