PDF IRM Protector For SharePoint – 2007 / 2010

Just want the code? : http://pdfirmprotector.codeplex.com

**Tested In SharePoint 2007 & SharePoint 2010**

Creating custom rights-management protectors for converting custom file types to arbitrary rights-management format(s) targeting a particular business need can be a necessary requirement depending on the company and industry. As part of this it might be necessary to break open a freshy VC++ project and start doing some code outside of the more commonly accepted business software development languages.

While I was researching this, these are…and this is literally based strictly on my experience and there might be other material freely available, is the following articles that are distributed ala MSDN:

http://msdn.microsoft.com/en-us/library/ms439253.aspx

http://msdn.microsoft.com/en-us/library/ms436515.aspx

http://msdn.microsoft.com/en-us/library/bb802693.aspx

(there are others directly on the left-hand navigation tree)

that *are* helpful as a brief introduction to the holistic architecture, and the project would be a month long deal if the VC++ reference project wasn’t available out of the ECM kit from the SDK. The header files available in the sample are literally invaluable; however the project in itself is incomplete.The aforementioned articles provide enough information that it really isn’t relevant to repeat it since it will add very little to no value for this article. Personally, it’s a little easier to start cooking up code, and when it is relevant make the appropriate back references. As an example, since it is probably the most demanded IRM protector on the market, I am going to target PDF file types.

Because of my choice of file type, things are going to get slightly complicated since Adobe made doing a client manipulation of Reader very, very difficult. IMHO, it’s hard to justify the time investment unless you are developing a COTS product, which I am not. Maybe sometime in the future, but now ain’t the time. That being said, a more practical approach since Reader has comparable control mechanisms to those that are toggled with IRM is to implement some sort of intermediate, linear transformation. In other words, based on certain IRM actions, execute certain structural, content-preserving transformations. By controlling the transformation of the PDF stream data, the amount of behavior that can be implemented is very, very robust. So, we simply introduce a tertiary step between initial content processing and the final, prepared document. Due to these requirements, I am going to use my favorite library, QPDF since it has native VC++ form and an abundance of other wrappers. Not saying it’s the be all for this requirement, but it is the only one that I have ever used.

I will post the important parts, but the code for the project is available here on CodePlex (it’s in VS2005 format [which I know is strange…it was on my 2007 VM since I usually run one version down from my version of SharePoint] but should port fine assuming the linking is taken care of if you want to use other project types).

For those folks who CodePlex’s code browser (and apparent lack of availability) does not blow their hair back, here is a brief summary of the project structure:

Since a bunch of this code is borrowed from the ECM kit, I am not going to discuss that end since it’s already canned (more commenting would of been a little kinder on the MSFT end, but it’s enough to guess at local variable intention), the more interesting stuff for this particular project  is in the PdfProtector header, the PdfIrmProtector and PdfProtector source files, and PdfIrmProtector MDIL file.

Firstly, the PdfProtector header file:

[cpp]
#pragma once
#include “PdfIrmProtector.h”
#include “resource.h”
#include
#include “Globals.h”
#include “strsafe.h”

class ATL_NO_VTABLE CPdfProtector :public I_IrmProtector,
public CComObjectRootEx,
public CComCoClass

{
public:
CPdfProtector();

DECLARE_PROTECT_FINAL_CONSTRUCT()

HRESULT FinalConstruct()
{
return S_OK;
}

void FinalRelease()
{
}

DECLARE_REGISTRY_RESOURCEID(IDR_PDFPROTECTOR)

DECLARE_NOT_AGGREGATABLE(CPdfProtector)

BEGIN_COM_MAP(CPdfProtector)
COM_INTERFACE_ENTRY(I_IrmProtector)

END_COM_MAP()

public:
~CPdfProtector();

public:
__override STDMETHOD(HrInit) (BSTR *pbstrProduct, DWORD *pdwVersion, BSTR *pbstrExtensions, BOOL *pfUseRMS);
__override STDMETHOD(HrIsProtected) (ILockBytes *pilbInput, DWORD *pdwResult);
__override STDMETHOD(HrSetLangId) (LANGID langid);
__override STDMETHOD(HrProtectRMS) (ILockBytes *pilbInput, ILockBytes *pilbOutput, I_IrmPolicyInfoRMS *piid, DWORD *pdwStatus);
__override STDMETHOD(HrUnprotectRMS) (ILockBytes *pilbInput, ILockBytes *pilbOutput, I_IrmPolicyInfoRMS *piid, DWORD *pdwStatus);
__override STDMETHOD(HrProtect) (ILockBytes *pilbInput, ILockBytes *pilbOutput, I_IrmPolicyInfo *piid, DWORD *pdwStatus);
__override STDMETHOD(HrUnprotect) (ILockBytes *pilbInput, ILockBytes *pilbOutput, I_IrmPolicyInfo *piid, DWORD *pdwStatus);

protected:
__override WCHAR *WzRegKey();

protected:
unsigned int m_uRefCount;

LANGID m_langid;
};

OBJECT_ENTRY_AUTO(__uuidof(PdfProtector), CPdfProtector)
[/cpp]

Secondly, the PdfIrmProtector file:

[cpp]
#include “stdafx.h”
#include “resource.h”
#include “PdfIrmProtector.h”

class CPdfIrmProtectorModule : public CAtlDllModuleT< CPdfIrmProtectorModule >
{
public :
DECLARE_LIBID(LIBID_PdfProtectorLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_PDFIRMPROTECTOR, “{2C16543F-AF1B-4247-B55E-C59F3F4B79D0}”)
};

CPdfIrmProtectorModule _AtlModule;

#ifdef _MANAGED
#pragma managed(push, off)
#endif

// DLL Entry Point
extern “C” BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
hInstance;
return _AtlModule.DllMain(dwReason, lpReserved);
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void)
{
return _AtlModule.DllCanUnloadNow();
}

// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
}

// DllRegisterServer – Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
// registers object, typelib and all interfaces in typelib
HRESULT hr = _AtlModule.DllRegisterServer();
return hr;
}

// DllUnregisterServer – Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
HRESULT hr = _AtlModule.DllUnregisterServer();
return hr;
}
[/cpp]

Thirdly, the PdfProtector source:

[cpp]
#include “stdafx.h”

#include
#include
#include
#include
#include
#include

#include “PdfProtector.h”

HINSTANCE g_hInstance = 0;
long g_cLocks = 0;
const WCHAR wzKey[] = L”I am protected”;
const WCHAR wzSignedIL[] = L”SignedIL”;
const WCHAR wzServerID[] = L”ServerID”;
const WCHAR wzLicenses[] = L”Licenses”;
const WCHAR wzRightsTemplate[] = L”RightsTemplate”;
const WCHAR wzListGuid[] = L”ListGuid”;
const WCHAR wzContent[] = L”Content”;
const WCHAR wzRightsMask[] = L”RightsMask”;
const WCHAR wzRequestingUser[] = L”RequestingUser”;
const WCHAR wzURL[] = L”URL”;
const WCHAR wzPolicyTitle[] = L”PolicyTitle”;
const WCHAR wzPolicyDescription[] = L”PolicyDescription”;
const WCHAR wzOfflineDays[] = L”OfflineDays”;
const int STREAM_MAX = 32;
const WCHAR wzEULPrefix[] = L”EUL-“;
#define STACK_RW_BUF_SIZE (8192)

#ifndef Unreferenced
#define Unreferenced(x) ((void)x)
#endif

#ifndef cElements
#define cElements(ary) (sizeof(ary) / sizeof(ary[0]))
#endif

#define GUIDLEN 38

HRESULT HrEnsureStg(IStorage *pistg, const WCHAR *wzStg, bool fReadWrite, IStorage **ppistg)
{
HRESULT hr = S_OK;

if (pistg == NULL || wzStg == NULL || ppistg == NULL)
return E_INVALIDARG;

*ppistg = NULL;
hr = pistg->OpenStorage(wzStg, NULL, (fReadWrite ? STGM_READWRITE : 0) | STGM_SHARE_EXCLUSIVE, NULL, 0, ppistg);
if (hr == STG_E_FILENOTFOUND && fReadWrite)
hr = pistg->CreateStorage(wzStg, STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, 0, ppistg);

if (FAILED(hr))
{
if (*ppistg != NULL)
{
(*ppistg)->Release();
*ppistg = NULL;
}
}
return hr;
}

HRESULT HrEnsureStm(IStorage *pistg, const WCHAR *wzStm, bool fReadWrite, IStream **ppistm)
{
HRESULT hr = S_OK;

if (pistg == NULL || wzStm == NULL || ppistm == NULL)
return E_INVALIDARG;

*ppistm = NULL;
hr = pistg->OpenStream(wzStm, NULL, (fReadWrite ? STGM_READWRITE : 0) | STGM_SHARE_EXCLUSIVE, 0, ppistm);
if (hr == STG_E_FILENOTFOUND && fReadWrite)
hr = pistg->CreateStream(wzStm, STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, 0, ppistm);

if (FAILED(hr))
{
if (*ppistm != NULL)
{
(*ppistm)->Release();
*ppistm = NULL;
}
}
return hr;
}

HRESULT HrWriteRaw(IStream *pistm, const WCHAR *wzData)
{
HRESULT hr = S_OK;
DWORD cbSrc = 0;
DWORD cbWritten = 0;

if (pistm == NULL || wzData == NULL)
return E_INVALIDARG;

cbSrc = ((DWORD)wcslen(wzData) + 1) * sizeof(WCHAR);
hr = pistm->Write((void*)&cbSrc, sizeof(DWORD), &cbWritten);
if (SUCCEEDED(hr) && sizeof(DWORD) != cbWritten)
hr = STG_E_WRITEFAULT;
if (FAILED(hr))
goto LExit;
if (cbSrc > 0)
{
hr = pistm->Write((void*)wzData, cbSrc, &cbWritten);
if (SUCCEEDED(hr) && cbSrc != cbWritten)
hr = STG_E_WRITEFAULT;
if (FAILED(hr))
goto LExit;
}

LExit:
return hr;
}

HRESULT HrWriteRaw(IStream *pistm, const DWORD dwData)
{
HRESULT hr = S_OK;
DWORD cbSrc = 0;
DWORD cbWritten = 0;

if (pistm == NULL || dwData == NULL)
return E_INVALIDARG;

cbSrc = sizeof(DWORD);
hr = pistm->Write((void*)&cbSrc, sizeof(DWORD), &cbWritten);
if (SUCCEEDED(hr) && sizeof(DWORD) != cbWritten)
hr = STG_E_WRITEFAULT;
if (FAILED(hr))
goto LExit;
if (cbSrc > 0)
{
hr = pistm->Write((void*)&dwData, cbSrc, &cbWritten);
if (SUCCEEDED(hr) && cbSrc != cbWritten)
hr = STG_E_WRITEFAULT;
if (FAILED(hr))
goto LExit;
}

LExit:
return hr;
}

HRESULT HrReadRaw(IStream *pistm, WCHAR **pwz)
{
HRESULT hr = S_OK;
DWORD cbSrc = 0;
DWORD cbRead = 0;

if (pistm == NULL || pwz == NULL)
{
return E_INVALIDARG;
}

*pwz = NULL;

hr = pistm->Read((void*)&cbSrc, sizeof(DWORD), &cbRead);
if (SUCCEEDED(hr) && sizeof(DWORD) != cbRead)
hr = STG_E_READFAULT;
if (FAILED(hr))
goto LExit;

*pwz = (WCHAR *)new BYTE [cbSrc];
if (*pwz == NULL)
{
hr = E_OUTOFMEMORY;
goto LExit;
}

hr = pistm->Read(*pwz, cbSrc, NULL);
if (FAILED(hr))
goto LExit;

LExit:
if (FAILED(hr) && *pwz != NULL)
{
delete [] *pwz;
*pwz = NULL;
}
return hr;
}

HRESULT HrReadRaw(IStream *pistm, DWORD *pdw)
{
HRESULT hr = S_OK;
DWORD cbSrc = 0;
DWORD cbRead = 0;

if (pistm == NULL || pdw == NULL)
return E_INVALIDARG;

*pdw = 0;

hr = pistm->Read((void*)&cbSrc, sizeof(DWORD), &cbRead);
if (SUCCEEDED(hr) && sizeof(DWORD) != cbRead)
hr = STG_E_READFAULT;
if (cbSrc != sizeof(DWORD))
hr = STG_E_READFAULT;
if (FAILED(hr))
goto LExit;

hr = pistm->Read((void*)pdw, cbSrc, NULL);
if (FAILED(hr))
goto LExit;

LExit:
return hr;
}

HRESULT HrWriteSubStream(IStorage *pistg, const WCHAR *wzStream, BSTR *pbstr)
{
HRESULT hr = S_OK;
IStream *pistmT = NULL;

if (pbstr == NULL)
{
hr = E_INVALIDARG;
goto LExit;
}

hr = HrEnsureStm(pistg, wzStream, true, &pistmT);
if (FAILED(hr))
goto LExit;
if (*pbstr == NULL)
goto LExit;
hr = HrWriteRaw(pistmT, *pbstr);
if (FAILED(hr))
goto LExit;

LExit:
if (pistmT != NULL)
pistmT->Release();
if (*pbstr != NULL)
{
SysFreeString(*pbstr);
*pbstr = NULL;
}
return hr;
}

HRESULT HrReadSubStream(IStorage *pistg, const WCHAR *wzStream, BSTR *pbstr)
{
HRESULT hr = S_OK;
IStream *pistmT = NULL;
WCHAR *wzT = NULL;

if (pbstr == NULL)
{
hr = E_INVALIDARG;
goto LExit;
}

hr = HrEnsureStm(pistg, wzStream, false, &pistmT);

if (FAILED(hr))
goto LExit;
hr = HrReadRaw(pistmT, &wzT);
if (FAILED(hr))
goto LExit;
*pbstr = SysAllocString(wzT);
if (*pbstr == NULL)
{
hr = E_OUTOFMEMORY;
goto LExit;
}

LExit:
if (wzT != NULL)
delete wzT;
if (pistmT != NULL)
pistmT->Release();
return hr;
}

CPdfProtector::CPdfProtector()
: m_uRefCount(1),
m_langid(1033)
{
::InterlockedIncrement(&g_cLocks);
}

CPdfProtector::~CPdfProtector()
{
::InterlockedDecrement(&g_cLocks);
}

HRESULT CPdfProtector::QueryInterface(const IID& riid, void** ppvObj)
{
if (riid == IID_IUnknown || riid == IID_I_IrmProtector)
{
*ppvObj = (I_IrmProtector*)this;
AddRef();
return S_OK;
}
*ppvObj = 0;
return E_NOINTERFACE;
}

unsigned long CPdfProtector::AddRef()
{
return ++m_uRefCount;
}

unsigned long CPdfProtector::Release()
{
if (–m_uRefCount != 0)
return m_uRefCount;
delete this;
return 0;
}

STDMETHODIMP CPdfProtector::HrInit(BSTR *pbstrProduct, DWORD *pdwVersion, BSTR *pbstrExtensions, BOOL *pfUseRMS)
{
if ( pbstrExtensions == NULL || pfUseRMS == NULL)
return E_INVALIDARG;

*pfUseRMS = true;
*pbstrProduct = SysAllocString(L”PdfIrmProtector”);
*pdwVersion = 1;
*pbstrExtensions = SysAllocString(L”pdf”);

return S_OK;
}

HRESULT CPdfProtector::HrIsProtected(ILockBytes *pilbInput, DWORD *pdwResult)
{
HRESULT hr = S_OK;
IStorage *pistgInput = NULL;
IStream *pistmKey = NULL;
IStream *pistmContent = NULL;

if (pilbInput == NULL || pdwResult == NULL)
{
hr = E_INVALIDARG;
goto LExit;
}

*pdwResult = MSOIPI_RESULT_UNKNOWN;
hr = StgIsStorageILockBytes(pilbInput);
if (FAILED(hr))
goto LExit;
if (hr == S_FALSE)
{
*pdwResult = MSOIPI_RESULT_UNPROTECTED;
goto LExit;
}
hr = StgOpenStorageOnILockBytes(pilbInput, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, NULL, NULL, &pistgInput);
if (FAILED(hr))
goto LExit;
hr = HrEnsureStm(pistgInput, wzKey, FALSE, &pistmKey);
if (FAILED(hr))
{
*pdwResult = MSOIPI_RESULT_UNPROTECTED;
goto LExit;
}
hr = HrEnsureStm(pistgInput, wzContent, FALSE, &pistmContent);
if (FAILED(hr))

goto LExit;
*pdwResult = MSOIPI_RESULT_PROTECTED;

LExit:
if (pistmContent != NULL)
pistmContent->Release();
if (pistmKey != NULL)
pistmKey->Release();
if (pistgInput != NULL)
pistgInput->Release();
return S_OK;
}

STDMETHODIMP CPdfProtector::HrSetLangId(LANGID langid)
{
m_langid = langid;
return S_OK;
}

HRESULT CPdfProtector::HrProtectRMS(ILockBytes *pilbInput, ILockBytes *pilbOutput, I_IrmPolicyInfoRMS *piid, DWORD *pdwStatus)
{
return E_NOTIMPL;
}

HRESULT CPdfProtector::HrUnprotectRMS(ILockBytes *pilbInput, ILockBytes *pilbOutput, I_IrmPolicyInfoRMS *piid, DWORD *pdwStatus)
{
return E_NOTIMPL;
}

HRESULT CPdfProtector::HrProtect(ILockBytes *pilbInput, ILockBytes *pilbOutput, I_IrmPolicyInfo *piid, DWORD *pdwStatus)
{
HRESULT hr = S_OK;
IStorage *pistgOutput = NULL;
IStream *pistmT = NULL;
BSTR bstr = NULL;
DWORD dw = 0;
BOOL bRequestingUserIsSystem = false;
BYTE rgbBuffer[STACK_RW_BUF_SIZE];
ULARGE_INTEGER ulOffset = { 0 };

if (pilbInput == NULL || pilbOutput == NULL || piid == NULL || pdwStatus == NULL)
{
hr = E_INVALIDARG;
goto LExit;
}

*pdwStatus = MSOIPI_STATUS_UNKNOWN;

hr = StgIsStorageILockBytes(pilbOutput);
if (FAILED(hr))
goto LExit;
if (hr != S_FALSE)
{
hr = StgOpenStorageOnILockBytes(pilbOutput, NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, NULL, &pistgOutput);
if (hr == STG_E_FILEALREADYEXISTS)
goto LCreateStorage;
}
else
{
LCreateStorage:
hr = StgCreateDocfileOnILockBytes(pilbOutput, STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, &pistgOutput);
}
if (FAILED(hr))
goto LExit;
BSTR key = SysAllocString(wzKey);
hr = HrWriteSubStream(pistgOutput, wzKey, &key);
hr = piid->HrGetListGuid(&bstr);
if (FAILED(hr) || bstr == NULL)
goto LExit;
hr = HrWriteSubStream(pistgOutput, wzListGuid, &bstr);
if (FAILED(hr))
goto LExit;
hr = piid->HrGetRightsMask(&dw);
if (FAILED(hr))
goto LExit;
hr = HrWriteSubStream(pistgOutput, wzRightsMask, &bstr);
if (FAILED(hr))
goto LExit;

hr = piid->HrGetRequestingUser(&bstr, &bRequestingUserIsSystem);
if (FAILED(hr) || bstr == NULL)
goto LExit;
hr = HrWriteSubStream(pistgOutput, wzRequestingUser, &bstr);
if (FAILED(hr))
goto LExit;

hr = piid->HrGetURL(&bstr);
if (FAILED(hr) || bstr == NULL)
goto LExit;
hr = HrWriteSubStream(pistgOutput, wzURL, &bstr);
if (FAILED(hr))
goto LExit;

hr = piid->HrGetPolicyTitle(&bstr);
if (FAILED(hr) || bstr == NULL)
goto LExit;
hr = HrWriteSubStream(pistgOutput, wzPolicyTitle, &bstr);
if (FAILED(hr))
goto LExit;

hr = piid->HrGetPolicyTitle(&bstr);
if (FAILED(hr) || bstr == NULL)
goto LExit;
hr = HrWriteSubStream(pistgOutput, wzPolicyDescription, &bstr);
if (FAILED(hr))
goto LExit;

hr = piid->HrGetOfflineDays(&dw);
if (FAILED(hr))
goto LExit;
hr = HrWriteSubStream(pistgOutput, wzOfflineDays, &bstr);
if (FAILED(hr))
goto LExit;

hr = HrEnsureStm(pistgOutput, wzContent, true, &pistmT);
if (FAILED(hr))
goto LExit;
ulOffset.QuadPart = 0;

TCHAR temp_path[ MAX_PATH ];
const DWORD temp_path_len = GetTempPath( MAX_PATH, temp_path );
if (!temp_path_len)
goto LExit;
GetTempFileName( temp_path, _T(“irm”), FALSE, temp_path );

HANDLE hTempFile = CreateFile( temp_path,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
if ( hTempFile == INVALID_HANDLE_VALUE )
goto LExit;

while (true)
{
ULONG cbRead = cElements(rgbBuffer);
ULONG cbWritten = 0;
hr = pilbInput->ReadAt(ulOffset, rgbBuffer, cbRead, &cbRead);
if (FAILED(hr))
goto LExit;
if (cbRead == 0)
goto LFinished;

WriteFile( hTempFile, rgbBuffer, cbRead, &cbWritten, NULL );

if (cbRead != cbWritten)
{
hr = STG_E_CANTSAVE;
goto LExit;
}
ulOffset.QuadPart += cbRead;
}

LFinished:
TCHAR temp_path2[ MAX_PATH ];
const DWORD temp_path2_len = GetTempPath( MAX_PATH, temp_path2 );
if (!temp_path2_len)
goto LExit;
GetTempFileName( temp_path2, _T(“irm”), FALSE, temp_path2 );

CloseHandle( hTempFile );
{
const char* password = NULL;
const char* user_password = NULL;
const bool decrypt = false;
const bool encrypt = true;

USES_CONVERSION;
QPDF pdf;
pdf.processFile(T2A(temp_path), password);
QPDFWriter w(pdf, T2A(temp_path2));
if (decrypt)
{
w.setPreserveEncryption(false);
}
if (encrypt)
{
w.setR3EncryptionParameters(
user_password, W2A(wzKey),
false,
false,
qpdf_r3p_none,
qpdf_r3m_none
);
}
w.write();

HANDLE hOutFile = CreateFile( temp_path2, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hOutFile == INVALID_HANDLE_VALUE )
{
goto LExit;
}

DWORD cbReaded = 0, cbWritten;
while ( ReadFile( hOutFile, rgbBuffer, sizeof( rgbBuffer ), &cbReaded, NULL ) || cbReaded )
{
hr = pistmT->Write(rgbBuffer, cbReaded, &cbWritten);
if (FAILED(hr))
goto LExit;
if ( cbReaded != cbWritten )
{
hr = STG_E_CANTSAVE;
goto LExit;
}
}
}

hr = pistmT->Commit(STGC_DEFAULT);

LExit:
DeleteFile( temp_path );
DeleteFile( temp_path2 );

*pdwStatus = SUCCEEDED(hr) ? MSOIPI_STATUS_PROTECT_SUCCESS : MSOIPI_STATUS_CANT_PROTECT;
if (bstr != NULL)
SysFreeString(bstr);
if (pistmT != NULL)
pistmT->Release();
if (pistgOutput != NULL)
pistgOutput->Release();

return hr;
}

HRESULT CPdfProtector::HrUnprotect(ILockBytes *pilbInput, ILockBytes *pilbOutput, I_IrmPolicyInfo *piid, DWORD *pdwStatus)
{
HRESULT hr = S_OK;
IStorage *pistgInput = NULL;
IStream *pistmT = NULL;
BYTE rgbBuffer[STACK_RW_BUF_SIZE];
ULARGE_INTEGER ulOffset = { 0 };

if (pilbInput == NULL || pilbOutput == NULL || piid == NULL || pdwStatus == NULL)
{
return E_INVALIDARG;
}

*pdwStatus = MSOIPI_STATUS_UNKNOWN;

hr = StgIsStorageILockBytes(pilbInput);
if (FAILED(hr) || hr == S_FALSE)
{
*pdwStatus = MSOIPI_STATUS_ALREADY_UNPROTECTED;
goto LExit;
}

hr = StgOpenStorageOnILockBytes(pilbInput, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, NULL, NULL, &pistgInput);
if (FAILED(hr))
goto LExit;

hr = HrEnsureStm(pistgInput, wzContent, false, &pistmT);
if (FAILED(hr))
goto LExit;
ulOffset.QuadPart = 0;

while (true)
{
ULONG cbRead = cElements(rgbBuffer);
ULONG cbWritten = 0;
hr = pistmT->Read(rgbBuffer, cbRead, &cbRead);
if (FAILED(hr))
goto LExit;
if (cbRead == 0)
goto LFinished;
for (ULONG i = 0; i < cbRead; i++) rgbBuffer[i] ^= 1; hr = pilbOutput->WriteAt(ulOffset, rgbBuffer, cbRead, &cbWritten);
if (FAILED(hr))
goto LExit;
if (cbRead != cbWritten)
{
hr = STG_E_CANTSAVE;
goto LExit;
}
ulOffset.QuadPart += cbRead;
}
LFinished:
pistmT->Release();
pistmT = NULL;

LExit:
if (pistmT != NULL)
pistmT->Release();
if (pistgInput != NULL)
pistgInput->Release();
return hr;
}
[/cpp]

and lastly, the PdfIrmProtector.idl file:

[cpp]
// PdfIrmProtector.idl : IDL source for PdfIrmProtector
//

// This file will be processed by the MIDL tool to
// produce the type library (PdfIrmProtector.tlb) and marshalling code.

import “oaidl.idl”;
import “ocidl.idl”;

[
uuid(598F03E8-948A-425e-B7B2-2D613CEDFFEF)
]
interface I_IrmCrypt: IUnknown
{
HRESULT HrGetBlockSize(
/*[OUT]*/ DWORD *pdwBlockSize) ;

HRESULT HrEncrypt(
/*[IN]*/ ULONG ulOffset,
/*[IN/OUT]*/ BYTE *pbData,
/*[IN]*/ DWORD cbData,
/*[OUT]*/ DWORD *pcbData) ;

HRESULT HrDecrypt(
/*[IN]*/ ULONG ulOffset,
/*[IN/OUT]*/ BYTE *pbData,
/*[IN]*/ DWORD cbData,
/*[OUT]*/ DWORD *pcbData) ;

HRESULT HrEncode(
/*[IN]*/ WCHAR *wszAlgID,
/*[IN]*/ UINT uDataLen,
/*[IN]*/ BYTE *pbDecodedData,
/*[IN/OUT]*/ UINT *puEncodedStringLen,
/*[OUT]*/ WCHAR *wszEncodedString) ;

HRESULT HrDecode(
/*[IN]*/ WCHAR *wszAlgID,
/*[IN]*/ WCHAR *wszEncodedString,
/*[IN/OUT]*/ UINT *puDecodedDataLen,
/*[OUT]*/ BYTE *pbDecodedData) ;
};

[
uuid(175EF0A4-8EB8-49ac-9049-F40EC69EC0A7)
]
interface I_IrmPolicyInfoRMS: IUnknown
{
HRESULT HrGetICrypt(
/*[OUT]*/ I_IrmCrypt **piic) ;

HRESULT HrGetSignedIL(
/*[OUT]*/ BSTR *pbstrIL) ;
HRESULT HrGetServerId(
/*[OUT]*/ BSTR *pbstrServerId) ;
HRESULT HrGetEULs(
/*[OUT]*/ BSTR *rgbstrEUL,
/*[OUT]*/ BSTR *rgbstrId,
/*[OUT]*/ UINT *pcbEULs) ;

HRESULT HrSetSignedIL(
/*[IN]*/ BSTR bstrIL) ;
HRESULT HrSetServerEUL(
/*[IN]*/ BSTR bstrEUL) ;

HRESULT HrGetRightsTemplate(
/*[OUT]*/ BSTR* pbstrRightsTemplate) ;

HRESULT HrGetListGuid(
/*[OUT]*/ BSTR* pbstrListGuid) ;
};

[
uuid(2CDC48E9-DB49-47E6-8487-A2EA1FCE292F)
]
interface I_IrmPolicyInfo: IUnknown
{
HRESULT HrGetListGuid(
/*[OUT]*/ BSTR* pbstrListGuid) ;

HRESULT HrSetListGuid(
/*[IN]*/ BSTR bstrListGuid) ;

HRESULT HrGetRightsMask(
/*[OUT]*/ DWORD* pdwRightsMask) ;

HRESULT HrGetRequestingUser(
/*[OUT]*/ BSTR* pbstrRequestingUser,
/*[OUT]*/ BOOL* pfRequestingUserIsSystem) ;

HRESULT HrGetURL(
/*[OUT]*/ BSTR* pbstrURL) ;

HRESULT HrGetPolicyTitle(
/*[OUT]*/ BSTR* pbstrPolicyTitle) ;

HRESULT HrGetPolicyDescription(
/*[OUT]*/ BSTR* pbstrPolicyDescription) ;

HRESULT HrGetOfflineDays(
/*[OUT]*/ DWORD* pdwOfflineDays) ;
};

[
uuid(fcfbc0ac-672b-452d-80e5-40652503d96e)
]
interface I_IrmProtector: IUnknown
{
HRESULT HrInit(
/*[OUT]*/ BSTR *pbstrProduct,
/*[OUT]*/ DWORD *pdwVersion,
/*[OUT]*/ BSTR *pbstrExtentions,
/*[OUT]*/ BOOL *pfUseRMS) ;

HRESULT HrIsProtected(
/*[IN]*/ ILockBytes *pilbInput,
/*[OUT]*/ DWORD *pdwResult) ;

HRESULT HrSetLangId(
/*[IN]*/ LANGID langid) ;

HRESULT HrProtectRMS(
/*[IN]*/ ILockBytes *pilbInput,
/*[IN]*/ ILockBytes *pilbOutput,
/*[IN]*/ I_IrmPolicyInfoRMS *piid,
/*[OUT]*/ DWORD *pdwStatus) ;

HRESULT HrUnprotectRMS(
/*[IN]*/ ILockBytes *pilbInput,
/*[IN]*/ ILockBytes *pilbOutput,
/*[IN]*/ I_IrmPolicyInfoRMS *piid,
/*[OUT]*/ DWORD *pdwStatus) ;

HRESULT HrProtect(
/*[IN]*/ ILockBytes *pilbInput,
/*[IN]*/ ILockBytes *pilbOutput,
/*[IN]*/ I_IrmPolicyInfo *piid,
/*[OUT]*/ DWORD *pdwStatus) ;

HRESULT HrUnprotect (/*[IN]*/ ILockBytes *pilbInput,
/*[IN]*/ ILockBytes *pilbOutput,
/*[IN]*/ I_IrmPolicyInfo *piid,
/*[OUT]*/ DWORD *pdwStatus) ;
};
[
object,
uuid(9F6F6D2C-434C-49D1-ACD5-C8B1C70A38DD),
dual,
nonextensible,
helpstring(“IPdfProtector Interface”),
pointer_default(unique)
]
interface IPdfProtector : IDispatch{
};
[
uuid(50FB39F2-4C18-460a-9A45-FD79980DFD8D),
version(1.0),
helpstring(“PdfIrmProtector 1.0 Type Library”)
]
library PdfProtectorLib
{
importlib(“stdole2.tlb”);
[
uuid(D2CE39CC-DF1D-48f2-86CC-7640B307E868),
helpstring(“PdfProtector Class”)
]
coclass PdfProtector
{
[default] interface I_IrmProtector;
};
};

[/cpp]

Share

Implementing List Governance With Performance Consideration In SharePoint 2010 – Part 2

Managed Metadata – With Managed metadata you will have a new set of features that add information to the architecture of the SharePoint Server. The managed metadata will offer a shared service known as the managed metadata service. This can be used for storing term sets and it can also be used to deploy the SharePoint environment. Elements of this feature include terms that can support both deep and flat hierarchies, managing metadata column type, and term sets that are open or restricted.

The use of managed metadata columns and terms that are set for organizing content allow you to use the features of content querying. Both metadata and the Content Query Web Part navigation help a user to find content. With managed metadata there is also the regular search queries available. This allows for keywords to be added to classified documents. It also allows for managed metadata to be used in the search panel.

Limits and Throttles – Through SharePoint Server 2010 there are various limits that can be configured for farm performance to be maintained. The Web application level is configured with limits and throttles. They were added to offer more operations for individual users or processes. However, they don’t affect the overall farm performance. The list view threshold is a limit that stops queries from affecting a given number of list items.

Compound Index – One of the important elements of large lists is the use of indexes. With SharePoint Server you will be able to create a compound index. These are useful for queries that will be performed on two columns versus just one. When you only have one, it may not be selective enough. A compound index allows for utilization of various views but they can still be accessed with metadata navigation. A throttle condition will occur when they metadata attempts to retry and then indexing is based on the various filters that apply.

Developer Dashboard – With the developer dashboard display there is a diagnostic detail for each page that loads. The default can be left on if you like. The developer will allow you to get information about load times, errors, and database queries. The metadata navigation is visible in the developer dashboard.

This means that large lists and throttle conditions are for the list of indexes. They are used to retry and for partial results that can appear in the operation tree. This is on the left side. The SQL Server queries are found on the right side. The developer dashboard allows for debugging the custom Web Parts and queries.

Content Iterator – The content Iterator is developed for API and it simplifies the writing code for large lists. This is important when there is a new list view limit. The content iterator offers a way for retrieving content and performing operations on small sets. This is different than performing operations on the entire set as before. The result is that you don’t have to worry about exceeding the threshold for a give list view.

Remote BLOB Storage – The SharePoint default results in files stored as Binary Large Objects (BLOB). This is in the SQL Server database. There is a large amount of content found in the database. BLOB storage also allows for more to be stored outside of the SQL Server. This allows for less cost to be involved with storing the options. At the same time this reduces the content database size. Remote BLOB storage is a library API set for the add on pack with the SQL Server 2008. There can be a 3rd party remote BLOB storage provider required for the remote BLOB storage API.

Share