// ePassEncryptSamp.cpp : Defines the entry point for the DLL application.
//


#include "stdafx.h"

//
// Initialize GUIDs (should be done only and at-least once per DLL/EXE)
//
#pragma data_seg(".text")
#define INITGUID
#include <initguid.h>
#include <shlguid.h>
#include "ShellExt.h"
#pragma data_seg()

//
// Global variables
//
UINT      g_nRefThisDll = 0;    // Reference count of this DLL.
HINSTANCE g_hModThisDll = NULL;	// Handle to this DLL itself.

extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	if (dwReason == DLL_PROCESS_ATTACH)
    {        
        g_hModThisDll = hInstance;
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {        
    }
    return TRUE;
}

STDAPI DllCanUnloadNow(void)
{
    return (g_nRefThisDll == 0 ? S_OK : S_FALSE);
}

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)
{
    *ppvOut = NULL;

    if (IsEqualIID(rclsid, CLSID_ShellExtension))
    {
        CShellExtClassFactory *pcf = new CShellExtClassFactory;

        return pcf->QueryInterface(riid, ppvOut);
    }

    return CLASS_E_CLASSNOTAVAILABLE;
}

bool GetThisDLLFileName(PVOID FuncAddr, LPTSTR szFileName, DWORD dwLen)
{
	HMODULE hm;
	MEMORY_BASIC_INFORMATION mbi;

//	if(NULL == szName || dwLen < MAX_PATH)
//		return false;

	if(0 != VirtualQuery(FuncAddr, &mbi, sizeof(mbi)))
	{
		hm = (HMODULE)mbi.AllocationBase;
		DWORD dwRet = GetModuleFileName(hm, szFileName, dwLen);

		if(0 != dwRet)
			return true;
	}
	return false;
}

#define SZ_GUID TEXT("{0a554e65-af65-4d29-9c10-5dc49969b490}")

#define SZ_CLSID				TEXT("CLSID\\") SZ_GUID
#define SZ_INPROCSERVER32		TEXT("CLSID\\") SZ_GUID TEXT("\\InprocServer32")
#define SZ_DEFAULT				TEXT("")
#define SZ_APARTMENT			TEXT("Apartment")
#define SZ_APPROVED				TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved")
#define SZ_DESC					TEXT("ePass1000 Encrypting Sample")

#define SZ_FILECTXMENU	TEXT("*\\shellex\\ContextMenuHandlers\\ePassEncSampMenu")

/*{{{The DllRegisterServer Entry Point*/
STDAPI DllRegisterServer(void)
{
	HRESULT hr = E_UNEXPECTED;

	// Get this DLL's path.
	TCHAR szFileName[MAX_PATH] = {0};
	bool bRet = GetThisDLLFileName(GetThisDLLFileName, szFileName, MAX_PATH);
	if(!bRet)
		return hr;

	// Create SZ_CLSID
	HKEY hKeyCLSID = NULL;
	if (::RegCreateKey(HKEY_CLASSES_ROOT, SZ_CLSID, &hKeyCLSID) != ERROR_SUCCESS)
	{
		return hr;	// No point in continuing further
	}
	::RegCloseKey(hKeyCLSID);

	HKEY hkeyInprocServer32 = NULL;
	if (::RegCreateKey(HKEY_CLASSES_ROOT, SZ_INPROCSERVER32, &hkeyInprocServer32) == ERROR_SUCCESS)
	{
		static TCHAR szApartment[] = SZ_APARTMENT;
		if (::RegSetValueEx(hkeyInprocServer32, SZ_DEFAULT, 0, REG_SZ, 
				(const BYTE*)(szFileName), (lstrlen(szFileName) + 1) * sizeof(TCHAR)) == ERROR_SUCCESS)
		{
			hr = S_OK;
		}
		::RegCloseKey(hkeyInprocServer32);
	}

	if(S_OK != hr)
		return hr;

	HKEY hKeyApproved = NULL;
	hr = E_UNEXPECTED;
	LONG lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_APPROVED, 0, KEY_SET_VALUE, &hKeyApproved);
	if (lRet == ERROR_ACCESS_DENIED)
	{
		MessageBox(NULL, TEXT("Can not register."), TEXT("Error"), MB_OK | MB_ICONERROR);
	}
	else if (lRet == ERROR_FILE_NOT_FOUND)
	{
		// Its okay.. The key doesn't exist. May be its Win95/98 or older verion of NT
	}

	if (hKeyApproved)
	{
		if (RegSetValueEx(hKeyApproved, SZ_GUID, 0, REG_SZ, 
			(const BYTE*)SZ_DESC, (lstrlen(SZ_DESC)+1) * sizeof(TCHAR)) == ERROR_SUCCESS)
		{
			hr = S_OK;
		}
	}

	//All type of file context menu.
	HKEY hKeyCtxFileMenu = NULL;
	if (::RegCreateKey(HKEY_CLASSES_ROOT, SZ_FILECTXMENU, &hKeyCtxFileMenu)==ERROR_SUCCESS)
	{
		if(::RegSetValueEx(hKeyCtxFileMenu,SZ_DEFAULT,0,REG_SZ,
			(const BYTE*)SZ_GUID,strlen(SZ_GUID)+1)==ERROR_SUCCESS)
		{
			hr=S_OK;
		}
	}
	::RegCloseKey(hKeyCtxFileMenu);

	return hr;
}

STDAPI DllUnregisterServer(void)
{
	HRESULT hr = E_UNEXPECTED;
	
	::RegDeleteKey(HKEY_CLASSES_ROOT, SZ_FILECTXMENU);
	
	::RegDeleteKey(HKEY_CLASSES_ROOT, SZ_INPROCSERVER32);

	if (::RegDeleteKey(HKEY_CLASSES_ROOT, SZ_CLSID) == ERROR_SUCCESS)
	{
		hr = S_OK;
	}
	HKEY hKeyApproved = NULL;
	LONG lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_APPROVED, 0, KEY_SET_VALUE, &hKeyApproved);
	if (lRet == ERROR_ACCESS_DENIED)
	{
		MessageBox(NULL, TEXT("Can not unregister."), TEXT("Error"), MB_OK | MB_ICONERROR);
		hr = E_UNEXPECTED;
	}
	else if (lRet == ERROR_FILE_NOT_FOUND)
	{
		// Its okay.. The key doesn't exist. May be its Win95 or older verion of NT
		NULL;
	}
	if (hKeyApproved)
	{
		if (::RegDeleteValue(hKeyApproved, SZ_GUID) != ERROR_SUCCESS)
		{
			hr &= E_UNEXPECTED;
		}
		::RegCloseKey(hKeyApproved);
	}
	
	return hr;
}