Skip to content

Commit

Permalink
Extensions can create and extract containers using bundle extensions.
Browse files Browse the repository at this point in the history
  • Loading branch information
nirbar committed Feb 27, 2024
1 parent 6067839 commit 2408483
Show file tree
Hide file tree
Showing 28 changed files with 1,179 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ extern "C" {
enum BUNDLE_EXTENSION_MESSAGE
{
BUNDLE_EXTENSION_MESSAGE_SEARCH,
BUNDLE_EXTENSION_MESSAGE_CONTAINER_OPEN,
BUNDLE_EXTENSION_MESSAGE_CONTAINER_OPEN_ATTACHED,
BUNDLE_EXTENSION_MESSAGE_CONTAINER_NEXT_STREAM,
BUNDLE_EXTENSION_MESSAGE_CONTAINER_STREAM_TO_FILE,
BUNDLE_EXTENSION_MESSAGE_CONTAINER_STREAM_TO_BUFFER,
BUNDLE_EXTENSION_MESSAGE_CONTAINER_SKIP_STREAM,
BUNDLE_EXTENSION_MESSAGE_CONTAINER_CLOSE,
};

typedef struct _BUNDLE_EXTENSION_SEARCH_ARGS
Expand All @@ -23,6 +30,97 @@ typedef struct _BUNDLE_EXTENSION_SEARCH_RESULTS
DWORD cbSize;
} BUNDLE_EXTENSION_SEARCH_RESULTS;


// Container ops arguments
typedef struct _BUNDLE_EXTENSION_CONTAINER_OPEN_ARGS
{
DWORD cbSize;
LPCWSTR wzContainerId;
LPCWSTR wzFilePath;
} BUNDLE_EXTENSION_CONTAINER_OPEN_ARGS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_OPEN_RESULTS
{
DWORD cbSize;
LPVOID pContext;
} BUNDLE_EXTENSION_CONTAINER_OPEN_RESULTS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_OPEN_ATTACHED_ARGS
{
DWORD cbSize;
LPCWSTR wzContainerId;
HANDLE hBundle;
DWORD64 qwContainerStartPos;
DWORD64 qwContainerSize;
} BUNDLE_EXTENSION_CONTAINER_OPEN_ATTACHED_ARGS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_OPEN_ATTACHED_RESULTS
{
DWORD cbSize;
LPVOID pContext;
} BUNDLE_EXTENSION_CONTAINER_OPEN_ATTACHED_RESULTS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_NEXT_STREAM_ARGS
{
DWORD cbSize;
LPVOID pContext;
} BUNDLE_EXTENSION_CONTAINER_NEXT_STREAM_ARGS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_NEXT_STREAM_RESULTS
{
DWORD cbSize;
// String allocated using SysAllocString on input, expected to be allocated using same method on return
BSTR *psczStreamName;
} BUNDLE_EXTENSION_CONTAINER_NEXT_STREAM_RESULTS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_STREAM_TO_FILE_ARGS
{
DWORD cbSize;
LPVOID pContext;
LPCWSTR wzFileName;
} BUNDLE_EXTENSION_CONTAINER_STREAM_TO_FILE_ARGS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_STREAM_TO_FILE_RESULTS
{
DWORD cbSize;
} BUNDLE_EXTENSION_CONTAINER_STREAM_TO_FILE_RESULTS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_STREAM_TO_BUFFER_ARGS
{
DWORD cbSize;
LPVOID pContext;
} BUNDLE_EXTENSION_CONTAINER_STREAM_TO_BUFFER_ARGS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_STREAM_TO_BUFFER_RESULTS
{
DWORD cbSize;
// Buffer must be allocated with CoTaskMemAlloc()
LPBYTE *ppbBuffer;
SIZE_T *pcbBuffer;
} BUNDLE_EXTENSION_CONTAINER_STREAM_TO_BUFFER_RESULTS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_SKIP_STREAM_ARGS
{
DWORD cbSize;
LPVOID pContext;
} BUNDLE_EXTENSION_CONTAINER_SKIP_STREAM_ARGS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_SKIP_STREAM_RESULTS
{
DWORD cbSize;
} BUNDLE_EXTENSION_CONTAINER_SKIP_STREAM_RESULTS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_CLOSE_ARGS
{
DWORD cbSize;
LPVOID pContext;
} BUNDLE_EXTENSION_CONTAINER_CLOSE_ARGS;

typedef struct _BUNDLE_EXTENSION_CONTAINER_CLOSE_RESULTS
{
DWORD cbSize;
} BUNDLE_EXTENSION_CONTAINER_CLOSE_RESULTS;

extern "C" typedef HRESULT(WINAPI *PFN_BUNDLE_EXTENSION_PROC)(
__in BUNDLE_EXTENSION_MESSAGE message,
__in const LPVOID pvArgs,
Expand Down
62 changes: 62 additions & 0 deletions src/api/burn/bextutil/inc/BextBaseBundleExtension.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,68 @@ class CBextBaseBundleExtension : public IBundleExtension
return E_NOTIMPL;
}

virtual STDMETHODIMP ContainerOpen(
__in LPCWSTR /*wzContainerId*/,
__in LPCWSTR /*wzFilePath*/,
__out LPVOID* /*pContext*/
)
{
return E_NOTIMPL;
}

virtual STDMETHODIMP ContainerOpenAttached(
__in LPCWSTR /*wzContainerId*/,
__in HANDLE /*hBundle*/,
__in DWORD64 /*qwContainerStartPos*/,
__in DWORD64 /*qwContainerSize*/,
__out LPVOID* /*ppContext*/
)
{
return E_NOTIMPL;
}

// Implementor should keep the stream name in the contex, to release it when done
virtual STDMETHODIMP ContainerNextStream(
__in LPVOID /*pContext*/,
__inout_z LPWSTR* /*psczStreamName*/
)
{
return E_NOTIMPL;
}

virtual STDMETHODIMP ContainerStreamToFile(
__in LPVOID /*pContext*/,
__in_z LPCWSTR /*wzFileName*/
)
{
return E_NOTIMPL;
}

// Not really needed because it is only used to read the manifest by the engine, and that is always a cab.
virtual STDMETHODIMP ContainerStreamToBuffer(
__in LPVOID /*pContext*/,
__out BYTE** /*ppbBuffer*/,
__out SIZE_T* /*pcbBuffer*/
)
{
return E_NOTIMPL;
}

virtual STDMETHODIMP ContainerSkipStream(
__in LPVOID /*pContext*/
)
{
return E_NOTIMPL;
}

// Don't forget to release everything in the context
virtual STDMETHODIMP ContainerClose(
__in LPVOID /*pContext*/
)
{
return E_NOTIMPL;
}

virtual STDMETHODIMP BundleExtensionProc(
__in BUNDLE_EXTENSION_MESSAGE /*message*/,
__in const LPVOID /*pvArgs*/,
Expand Down
86 changes: 85 additions & 1 deletion src/api/burn/bextutil/inc/BextBaseBundleExtensionProc.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,69 @@ static HRESULT BextBaseBEProcSearch(
return pBE->Search(pArgs->wzId, pArgs->wzVariable);
}

static HRESULT BextBaseBEProcContainerOpen(
__in IBundleExtension* pBE,
__in BUNDLE_EXTENSION_CONTAINER_OPEN_ARGS* pArgs,
__inout BUNDLE_EXTENSION_CONTAINER_OPEN_RESULTS* pResults
)
{
return pBE->ContainerOpen(pArgs->wzContainerId, pArgs->wzFilePath, &pResults->pContext);
}

static HRESULT BextBaseBEProcContainerOpenAttached(
__in IBundleExtension* pBE,
__in BUNDLE_EXTENSION_CONTAINER_OPEN_ATTACHED_ARGS* pArgs,
__inout BUNDLE_EXTENSION_CONTAINER_OPEN_ATTACHED_RESULTS* pResults
)
{
return pBE->ContainerOpenAttached(pArgs->wzContainerId, pArgs->hBundle, pArgs->qwContainerStartPos, pArgs->qwContainerSize, &pResults->pContext);
}

static HRESULT BextBaseBEProcContainerNextStream(
__in IBundleExtension* pBE,
__in BUNDLE_EXTENSION_CONTAINER_NEXT_STREAM_ARGS* pArgs,
__inout BUNDLE_EXTENSION_CONTAINER_NEXT_STREAM_RESULTS* pResults
)
{
return pBE->ContainerNextStream(pArgs->pContext, pResults->psczStreamName);
}

static HRESULT BextBaseBEProcContainerStreamToFile(
__in IBundleExtension* pBE,
__in BUNDLE_EXTENSION_CONTAINER_STREAM_TO_FILE_ARGS* pArgs,
__inout BUNDLE_EXTENSION_CONTAINER_STREAM_TO_FILE_RESULTS* /*pResults*/
)
{
return pBE->ContainerStreamToFile(pArgs->pContext, pArgs->wzFileName);
}

static HRESULT BextBaseBEProcContainerStreamToBuffer(
__in IBundleExtension* pBE,
__in BUNDLE_EXTENSION_CONTAINER_STREAM_TO_BUFFER_ARGS* pArgs,
__inout BUNDLE_EXTENSION_CONTAINER_STREAM_TO_BUFFER_RESULTS* pResults
)
{
return pBE->ContainerStreamToBuffer(pArgs->pContext, pResults->ppbBuffer, pResults->pcbBuffer);
}

static HRESULT BextBaseBEProcContainerSkipStream(
__in IBundleExtension* pBE,
__in BUNDLE_EXTENSION_CONTAINER_SKIP_STREAM_ARGS* pArgs,
__inout BUNDLE_EXTENSION_CONTAINER_SKIP_STREAM_RESULTS* /*pResults*/
)
{
return pBE->ContainerSkipStream(pArgs->pContext);
}

static HRESULT BextBaseBEProcContainerClose(
__in IBundleExtension* pBE,
__in BUNDLE_EXTENSION_CONTAINER_CLOSE_ARGS* pArgs,
__inout BUNDLE_EXTENSION_CONTAINER_CLOSE_RESULTS* /*pResults*/
)
{
return pBE->ContainerClose(pArgs->pContext);
}

/*******************************************************************
BextBaseBundleExtensionProc - requires pvContext to be of type IBundleExtension.
Provides a default mapping between the message based
Expand All @@ -33,14 +96,35 @@ static HRESULT WINAPI BextBaseBundleExtensionProc(
{
IBundleExtension* pBE = reinterpret_cast<IBundleExtension*>(pvContext);
HRESULT hr = pBE->BundleExtensionProc(message, pvArgs, pvResults, pvContext);

if (E_NOTIMPL == hr)
{
switch (message)
{
case BUNDLE_EXTENSION_MESSAGE_SEARCH:
hr = BextBaseBEProcSearch(pBE, reinterpret_cast<BUNDLE_EXTENSION_SEARCH_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_SEARCH_RESULTS*>(pvResults));
break;
case BUNDLE_EXTENSION_MESSAGE_CONTAINER_OPEN:
hr = BextBaseBEProcContainerOpen(pBE, reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_OPEN_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_OPEN_RESULTS*>(pvResults));
break;
case BUNDLE_EXTENSION_MESSAGE_CONTAINER_OPEN_ATTACHED:
hr = BextBaseBEProcContainerOpenAttached(pBE, reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_OPEN_ATTACHED_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_OPEN_ATTACHED_RESULTS*>(pvResults));
break;
case BUNDLE_EXTENSION_MESSAGE_CONTAINER_NEXT_STREAM:
hr = BextBaseBEProcContainerNextStream(pBE, reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_NEXT_STREAM_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_NEXT_STREAM_RESULTS*>(pvResults));
break;
case BUNDLE_EXTENSION_MESSAGE_CONTAINER_STREAM_TO_FILE:
hr = BextBaseBEProcContainerStreamToFile(pBE, reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_STREAM_TO_FILE_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_STREAM_TO_FILE_RESULTS*>(pvResults));
break;
case BUNDLE_EXTENSION_MESSAGE_CONTAINER_STREAM_TO_BUFFER:
hr = BextBaseBEProcContainerStreamToBuffer(pBE, reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_STREAM_TO_BUFFER_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_STREAM_TO_BUFFER_RESULTS*>(pvResults));
break;
case BUNDLE_EXTENSION_MESSAGE_CONTAINER_SKIP_STREAM:
hr = BextBaseBEProcContainerSkipStream(pBE, reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_SKIP_STREAM_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_SKIP_STREAM_RESULTS*>(pvResults));
break;
case BUNDLE_EXTENSION_MESSAGE_CONTAINER_CLOSE:
hr = BextBaseBEProcContainerClose(pBE, reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_CLOSE_ARGS*>(pvArgs), reinterpret_cast<BUNDLE_EXTENSION_CONTAINER_CLOSE_RESULTS*>(pvResults));
break;
}
}

Expand Down
60 changes: 60 additions & 0 deletions src/api/burn/bextutil/inc/IBundleExtension.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,66 @@ DECLARE_INTERFACE_IID_(IBundleExtension, IUnknown, "93123C9D-796B-4FCD-A507-6EDE
__in LPCWSTR wzVariable
) = 0;

/* ContainerOpen
Open a container file
*/
STDMETHOD(ContainerOpen)(
__in LPCWSTR wzContainerId,
__in LPCWSTR wzFilePath,
__out LPVOID *ppContext
) = 0;

/* ContainerOpenAttached
Open an attached container
If not implemented, return E_NOTIMPL. In that case, burn will extract the container to a temporary file and call ContainerOpen(). Note that, this may come with substantial performance penalty
*/
STDMETHOD(ContainerOpenAttached)(
__in LPCWSTR wzContainerId,
__in HANDLE hBundle,
__in DWORD64 qwContainerStartPos,
__in DWORD64 qwContainerSize,
__out LPVOID *ppContext
) = 0;

/* ContainerNextStream
Return the file name of the subsequent stream
*/
STDMETHOD(ContainerNextStream)(
__in LPVOID pContext,
__inout_z LPWSTR* psczStreamName
) = 0;

/* ContainerStreamToFile
Extract the current stream to a file. May be implemented a-synchronically. All extractions must be completed before the call to ContainerClose returns.
*/
STDMETHOD(ContainerStreamToFile)(
__in LPVOID pContext,
__in_z LPCWSTR wzFileName
) = 0;

/* ContainerStreamToBuffer
Extract the current stream to a buffer. May not be implemented a-synchronically
*/
STDMETHOD(ContainerStreamToBuffer)(
__in LPVOID pContext,
__out BYTE** ppbBuffer,
__out SIZE_T* pcbBuffer
) = 0;

/* ContainerSkipStream
Notifies that the current stream is not needed
*/
STDMETHOD(ContainerSkipStream)(
__in LPVOID pContext
) = 0;

/* ContainerClose
Complete all pending file extractions and release the container.
*/
STDMETHOD(ContainerClose)(
__in LPVOID pContext
) = 0;

// BundleExtensionProc - The PFN_BUNDLE_EXTENSION_PROC can call this method to give the BundleExtension raw access to the callback from the engine.
// This might be used to help the BundleExtension support more than one version of the engine.
STDMETHOD(BundleExtensionProc)(
Expand Down
18 changes: 18 additions & 0 deletions src/api/wix/WixToolset.Data/ErrorMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2276,6 +2276,21 @@ private static Message Message(SourceLineNumber sourceLineNumber, Ids id, Resour
return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args);
}

public static Message MissingContainerExtension(SourceLineNumber sourceLineNumber, string containerId, string bundleExtensionRef)
{
return Message(sourceLineNumber, Ids.MissingContainerExtension, "Container '{0}' has BundleExtensionRef set to '{1}', which could not be resolved to a container extension.", containerId, bundleExtensionRef);
}

public static Message ContainerExtractFailed(SourceLineNumber sourceLineNumber, string containerId, string bundleExtensionRef, string errorMessage)
{
return Message(sourceLineNumber, Ids.ContainerExtractFailed, "Container '{0}' with BundleExtensionRef set to '{1}' failed to extract the container. {2}", containerId, bundleExtensionRef, errorMessage);
}

public static Message InvalidBurnManifestContainers(SourceLineNumber sourceLineNumber, int containersCount, int missingIndex)
{
return Message(sourceLineNumber, Ids.InvalidBurnManifestContainers, "The burn manifest file contains {0} containers, yet container with index {1} was not found.", containersCount, missingIndex);
}

public enum Ids
{
UnexpectedException = 1,
Expand Down Expand Up @@ -2667,6 +2682,9 @@ public enum Ids
MsiTransactionInvalidPackage2 = 412,
ExpectedAttributeOrElementWithOtherAttribute = 413,
ExpectedAttributeOrElementWithoutOtherAttribute = 414,
MissingContainerExtension = 415,
ContainerExtractFailed = 416,
InvalidBurnManifestContainers = 417,
}
}
}
Loading

0 comments on commit 2408483

Please sign in to comment.