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 854b675 commit 86aeea6
Show file tree
Hide file tree
Showing 18 changed files with 734 additions and 30 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
path: build/logs/

- name: Publish nuget packages to github
if: github.event.inputs.publish_nuget == 'true' && github.ref == 'refs/heads/develop-psw-wix'
if: ${{ github.event.inputs.publish_nuget == 'true' && github.ref == 'refs/heads/develop-psw-wix' }}
env:
GITHUB_TOKEN: ${{ secrets.MY_GITHUB_PAT }}
run: |
Expand Down
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
42 changes: 36 additions & 6 deletions src/api/burn/bextutil/inc/IBundleExtension.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,46 @@
DECLARE_INTERFACE_IID_(IBundleExtension, IUnknown, "93123C9D-796B-4FCD-A507-6EDEF9A925FD")
{
STDMETHOD(Search)(
__in LPCWSTR wzId,
__in LPCWSTR wzVariable
__in LPCWSTR wzId,
__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)(
__in BUNDLE_EXTENSION_MESSAGE message,
__in const LPVOID pvArgs,
__inout LPVOID pvResults,
__in_opt LPVOID pvContext
__in BUNDLE_EXTENSION_MESSAGE message,
__in const LPVOID pvArgs,
__inout LPVOID pvResults,
__in_opt LPVOID pvContext
) = 0;
};
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 @@ -2288,6 +2288,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 @@ -2682,6 +2687,7 @@ public enum Ids
ExpectedAttributeOrElementWithOtherAttribute = 413,
ExpectedAttributeOrElementWithoutOtherAttribute = 414,
MsiTransactionX86AndX64Packages = 415,
MissingContainerExtension = 416,
}
}
}
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 86aeea6

Please sign in to comment.