/****************************************************************************
                       Microsoft RPC 
                Copyright Microsoft Corp. 1992
                  object call_as Example

    FILE:       client.c

    USAGE:      client 

    PURPOSE:    Client side application of remoted custom interface

    FUNCTIONS:  main() - binds to server and calls remote procedure

    COMMENTS:   This version of the Ole2 distributed application that 
                prints "hello, world" (or other string) on the server 
                features a non-rpcable custom interface being remoted with
                [call_as].

****************************************************************************/

#define INC_OLE2
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include "callas.h"     // generated by MIDL from callas.idl/.acf

// the class ID of the server exe
const 
CLSID CLSID_CallAs = 
    {0xf9246030,0x9f33,0x11cd,{0xb2,0x3f,0x00,0xaa,0x00,0x33,0x9c,0xce}};


/***********************************************************************

    set up the following registry keys:

    \Registry\Machine\Software\Classes
        CLSID
            {f9246030-9f33-11cd-b23f-00aa00339cce}
                LocalServer32
                    = server.exe
            {a46deb30-9f33-11cd-b23f-00aa00339cce}
                InProcServer32
                    = callas.dll
        Interface
            {a46deb30-9f33-11cd-b23f-00aa00339cce}
                ProxyStubClsid32
                    = {a46deb30-9f33-11cd-b23f-00aa00339cce}

    for the server, the LocalServer32 is the out-of-process server exe
    for the proxy, the InProcServer32 is the proxy dll
    for the interface, the ProxyStubClsid32 is the class id of the
        proxy class factory.

***********************************************************************/

void InitializeRegistry(char *pszProxyDll, char *pszServer)
{
    // the server exe CLSID
    const char *pszServerKey = "{f9246030-9f33-11cd-b23f-00aa00339cce}";
    
    // the interface UUID
    const char *pszInterfaceKey = "{a46deb30-9f33-11cd-b23f-00aa00339cce}";
    
    // the class factory CLSID ( the same as the interface UUID )
    const char *pszProxyDllKey = "{a46deb30-9f33-11cd-b23f-00aa00339cce}";
    

    LONG error          = 0;
    HKEY hKeyInterface;     // key for ...\Classes\Interface
    HKEY hKeyCLSID;         // key for ...\Classes\CLSID
    HKEY hKey;              // current key
    DWORD dwDisposition;

    //Register the interfaces.

    //create ...\Classes\Interface key
    error = RegCreateKeyEx(
        HKEY_CLASSES_ROOT, 
        "Interface",
        0, 
        "REG_SZ", 
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKeyInterface,
        &dwDisposition);

    // create the ...\Classes\Interface\{ <interface uuid> }  key
    error = RegCreateKeyEx(
        hKeyInterface, 
        pszInterfaceKey,
        0, 
        "REG_SZ", 
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKey,
        &dwDisposition);

    //create ProxyStubClsid32 key under the interface
    error = RegCreateKeyEx(
        hKey, 
        "ProxyStubClsid32",
        0, 
        "REG_SZ", 
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKey,
        &dwDisposition);

    //Set the class id for the PSFactoryBuffer for the interface
    error = RegSetValueEx(
        hKey, 
        "", 
        0, 
        REG_SZ, 
        pszProxyDllKey,
        strlen(pszProxyDllKey) + 1);


    //Register the classes.
    
    //create the CLSID key
    error = RegCreateKeyEx(
        HKEY_CLASSES_ROOT, 
        "CLSID",
        0, 
        "REG_SZ", 
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKeyCLSID,
        &dwDisposition);

    //create key for the server
    error = RegCreateKeyEx(
        hKeyCLSID, 
        pszServerKey,
        0, 
        "REG_SZ", 
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKey,
        &dwDisposition);

    //create LocalServer32 key.
    error = RegCreateKeyEx(
        hKey, 
        "LocalServer32",
        0, 
        "REG_SZ", 
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKey,
        &dwDisposition);

    //Set the server name.
    error = RegSetValueEx(
        hKey, 
        "", 
        0, 
        REG_SZ, 
        pszServer,
        strlen(pszServer) + 1);

    error = RegFlushKey(
        hKey );


    //create key for the proxy dll
    error = RegCreateKeyEx(
        hKeyCLSID, 
        pszProxyDllKey,
        0, 
        "REG_SZ", 
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKey,
        &dwDisposition);

    //create InProcServer32 key for the proxy dll
    error = RegCreateKeyEx(
        hKey, 
        "InProcServer32",
        0, 
        "REG_SZ", 
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKey,
        &dwDisposition);

    //register the proxy DLL
    error = RegSetValueEx(
        hKey, 
        "", 
        0, 
        REG_SZ, 
        pszProxyDll,
        strlen(pszProxyDll) + 1);

    error = RegFlushKey(
        hKey );

    //  printf("waiting for registry to update OLE\n");
    Sleep(1000);
}

void Test()
{
    IClassFactory *pClassFactory =0;
    IUnknown *punk = 0;
    IHelloCallAs *pCallAs = 0;
    HRESULT hr;

    hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        printf("CoInitialize failed with %lx\n", hr);
        return;
    }

    hr = CoGetClassObject(&CLSID_CallAs, CLSCTX_LOCAL_SERVER, 0, &IID_IClassFactory, &pClassFactory);
    if(FAILED(hr))
        printf("CoGetClassObject failed with %lx\n", hr);
    else
    {
        assert(pClassFactory);
        hr = pClassFactory->lpVtbl->CreateInstance(pClassFactory, 0, &IID_IUnknown, &punk);
        if(FAILED(hr))
            printf("IClassFactory::CreateInstance failed with %lx\n", hr);
        else
        {
            assert(punk);
            hr = punk->lpVtbl->QueryInterface(punk, &IID_IHelloCallAs, &pCallAs);
            if(FAILED(hr))
                printf("IUnknown::QueryInterface failed with %lx\n", hr);
            else
            {
                assert(pCallAs);
                hr = pCallAs->lpVtbl->HelloProc(pCallAs, "Hello World!");
                if(FAILED(hr))
                    printf("IHelloCallAs::HelloProc failed with %lx\n", hr);
                else
                    printf("IHelloCallAs::HelloProc succeeded");

                pCallAs->lpVtbl->Release(pCallAs);
                pCallAs = 0;
            }
            punk->lpVtbl->Release(punk);
            punk = 0;
        }
        pClassFactory->lpVtbl->Release(pClassFactory);
        pClassFactory = 0;
    }
    CoUninitialize();
}

void TestDll()
{
    // the dll name of the proxy dll
    const char *pszProxyDllName = "callas.dll";

    char szDrive[_MAX_DRIVE];
    char szDirectory[_MAX_DIR];
    char szFileName[_MAX_FNAME];

    char szClient[_MAX_PATH];
    char szProxyDll[_MAX_PATH];
    char szServer[_MAX_PATH];

    GetModuleFileName(0, szClient, _MAX_PATH);
    _splitpath(szClient, szDrive, szDirectory, szFileName, NULL);

    //Get the full path name of the server.
    sprintf(szServer, "%s%sserver.exe", szDrive, szDirectory);
    
    //Get the full path name of the proxy dll.
    sprintf(szProxyDll, "%s%s%s", szDrive, szDirectory, pszProxyDllName);

    printf("Testing Dll\n");
    InitializeRegistry(szProxyDll, szServer);
    
    Test();
}


void __cdecl main(int argc, char *argv[])
{
    TestDll();
}
