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 Jan 7, 2024
1 parent 44a13ff commit f06b413
Show file tree
Hide file tree
Showing 17 changed files with 719 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ extern "C" {
enum BUNDLE_EXTENSION_MESSAGE
{
BUNDLE_EXTENSION_MESSAGE_SEARCH,
BUNDLE_EXTENSION_MESSAGE_CONTAINER_OPEN,
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 +29,82 @@ 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_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
51 changes: 51 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,57 @@ class CBextBaseBundleExtension : public IBundleExtension
return E_NOTIMPL;
}

virtual STDMETHODIMP ContainerOpen(
__in LPCWSTR /*wzContainerId*/,
__in LPCWSTR /*wzFilePath*/,
__out LPVOID* /*pContext*/
)
{
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
74 changes: 73 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,60 @@ 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 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 +87,32 @@ 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_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
30 changes: 30 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,36 @@ DECLARE_INTERFACE_IID_(IBundleExtension, IUnknown, "93123C9D-796B-4FCD-A507-6EDE
__in LPCWSTR wzVariable
) = 0;

STDMETHOD(ContainerOpen)(
__in LPCWSTR wzContainerId,
__in LPCWSTR wzFilePath,
__out LPVOID *ppContext
) = 0;

STDMETHOD(ContainerNextStream)(
__in LPVOID pContext,
__inout_z LPWSTR* psczStreamName
) = 0;

STDMETHOD(ContainerStreamToFile)(
__in LPVOID pContext,
__in_z LPCWSTR wzFileName
) = 0;

STDMETHOD(ContainerStreamToBuffer)(
__in LPVOID pContext,
__out BYTE** ppbBuffer,
__out SIZE_T* pcbBuffer
) = 0;

STDMETHOD(ContainerSkipStream)(
__in LPVOID pContext
) = 0;

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
6 changes: 6 additions & 0 deletions src/api/wix/WixToolset.Data/ErrorMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2266,6 +2266,11 @@ 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 enum Ids
{
UnexpectedException = 1,
Expand Down Expand Up @@ -2657,6 +2662,7 @@ public enum Ids
MsiTransactionInvalidPackage2 = 412,
ExpectedAttributeOrElementWithOtherAttribute = 413,
ExpectedAttributeOrElementWithoutOtherAttribute = 414,
MissingContainerExtension = 415,
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public static partial class SymbolDefinitions
new IntermediateFieldDefinition(nameof(WixBundleContainerSymbolFields.Hash), IntermediateFieldType.String),
new IntermediateFieldDefinition(nameof(WixBundleContainerSymbolFields.AttachedContainerIndex), IntermediateFieldType.Number),
new IntermediateFieldDefinition(nameof(WixBundleContainerSymbolFields.WorkingPath), IntermediateFieldType.String),
new IntermediateFieldDefinition(nameof(WixBundleContainerSymbolFields.BundleExtensionRef), IntermediateFieldType.String),
},
typeof(WixBundleContainerSymbol));
}
Expand All @@ -35,6 +36,7 @@ public enum WixBundleContainerSymbolFields
Hash,
AttachedContainerIndex,
WorkingPath,
BundleExtensionRef,
}

/// <summary>
Expand Down Expand Up @@ -99,5 +101,11 @@ public string WorkingPath
get => (string)this.Fields[(int)WixBundleContainerSymbolFields.WorkingPath];
set => this.Set((int)WixBundleContainerSymbolFields.WorkingPath, value);
}

public string BundleExtensionRef
{
get => (string)this.Fields[(int)WixBundleContainerSymbolFields.BundleExtensionRef];
set => this.Set((int)WixBundleContainerSymbolFields.BundleExtensionRef, value);
}
}
}
Loading

0 comments on commit f06b413

Please sign in to comment.