### Install Development Dependencies and Run Checks Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Installs the project in editable mode with development dependencies and runs static analysis and tests. This command is equivalent to the CI setup. ```bash pip install -e ".[dev]" pyright src tests pytest -p no:randomly ``` -------------------------------- ### Install pyOpenVBA from Source Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Install the library from its source code for development purposes. This includes development dependencies. ```bash git clone https://github.com/WilliamSmithEdward/pyOpenVBA cd pyOpenVBA pip install -e ".[dev]" ``` -------------------------------- ### Install pyOpenVBA from PyPI Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Install the library using pip. Python 3.10 or newer is required. ```bash pip install pyOpenVBA ``` -------------------------------- ### Install pyOpenVBA using pip Source: https://github.com/williamsmithedward/pyopenvba/blob/main/demo/demo.md Install pyOpenVBA using pip. Choose either the standard installation or an editable install from a cloned repository. ```powershell pip install pyopenvba ``` ```powershell pip install -e . # from a clone of this repo ``` -------------------------------- ### Run pyOpenVBA CLI Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Access the command-line interface after installation, either as a module or a script. ```bash python -m pyopenvba --help pyopenvba --help ``` -------------------------------- ### VBA String Literal Examples Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Illustrates the byte representation of common string literals as observed on disk. These examples show the literal tag, byte count, and the UTF-16-LE encoded string. ```plaintext "hello" -> 0B 0A 00 00 00 68 00 65 00 6C 00 6C 00 6F 00 ``` ```plaintext "world" -> 0B 0A 00 00 00 77 00 6F 00 72 00 6C 00 64 00 ``` ```plaintext 55-char literal -> 0B 6E 00 00 00 <110 bytes UTF-16-LE> ``` -------------------------------- ### VBA7 P-Code Disassembly Examples Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Demonstrates the recovered p-code mnemonics for various VBA code samples. Note that identifier-table resolution is not yet implemented, so operands like name_id and var_id appear as placeholders. ```text Sample | Source | Decoded p-code |--------|------------------------------|------------------------------------------------------------------------------------- | 030 | `Sub A() : End Sub` | `FuncDefn func_0x0 ; EndSub` | 040 | `Sub A() : MsgBox "hello"` | `FuncDefn func_0x0 ; LitStr "hello" ; ArgsCall (op_type=0x10, argc=1) ; EndSub` | 044 | `Sub A() : Dim x As Integer` | `FuncDefn func_0x0 ; Dim ; VarDefn var_0x58 ; EndSub` ``` -------------------------------- ### Basic VBA Subroutine Source: https://github.com/williamsmithedward/pyopenvba/blob/main/tests/live_access_test/_oracle_plaintext/Module1.bas.txt This subroutine demonstrates a simple message box display. It's a fundamental example for VBA. ```VBA Option Compare Database Sub Test() MsgBox "This is a test" End Sub ``` -------------------------------- ### Public API for ExcelFile Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md Suggested public API surface for PyOpenVBA, including methods for opening, saving, reading module names, getting module content, and accessing the VBA project object. ```text # Open / save ExcelFile(path).open() / .save(dest=None, *, allow_protected=False, allow_invalidate_signature=False) # Read ExcelFile.module_names() -> list[str] ExcelFile.get_module(name) -> str ExcelFile.vba_project() -> VBAProject ``` -------------------------------- ### Procedure Open / End Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Encloses the body of a procedure (Sub or Function). The 'ProcOpen' variant likely starts the procedure, and 'ProcEnd' closes it. ```assembly 67 02 ``` ```assembly 67 02 00 00 00 00 ``` -------------------------------- ### Basic VBA Subroutine Source: https://github.com/williamsmithedward/pyopenvba/blob/main/tests/live_access_test/_oracle_plaintext/Class1.bas.txt This snippet shows a basic VBA subroutine named 'Test' that displays a message box. It's a simple example for beginners. ```VBA Option Compare Database Sub Test() MsgBox "This is a test" End Sub ' 1 This is a VBA comment line with line number ' 2 This is a VBA comment line with line number ' 3 This is a VBA comment line with line number ' 4 This is a VBA comment line with line number ' 5 This is a VBA comment line with line number ' 6 This is a VBA comment line with line number ' 7 This is a VBA comment line with line number ' 8 This is a VBA comment line with line number ' 9 This is a VBA comment line with line number ' 10 This is a VBA comment line with line number ' 11 This is a VBA comment line with line number ' 12 This is a VBA comment line with line number ' 13 This is a VBA comment line with line number ' 14 This is a VBA comment line with line number ' 15 This is a VBA comment line with line number ' 16 This is a VBA comment line with line number ' 17 This is a VBA comment line with line number ' 18 This is a VBA comment line with line number ' 19 This is a VBA comment line with line number ' 20 This is a VBA comment line with line number ' 21 This is a VBA comment line with line number ' 22 This is a VBA comment line with line number ' 23 This is a VBA comment line with line number ' 24 This is a VBA comment line with line number ' 25 This is a VBA comment line with line number ' 26 This is a VBA comment line with line number ' 27 This is a VBA comment line with line number ' 28 This is a VBA comment line with line number ' 29 This is a VBA comment line with line number ' 30 This is a VBA comment line with line number ' 31 This is a VBA comment line with line number ' 32 This is a VBA comment line with line number ' 33 This is a VBA comment line with line number ' 34 This is a VBA comment line with line number ' 35 This is a VBA comment line with line number ' 36 This is a VBA comment line with line number ' 37 This is a VBA comment line with line number ' 38 This is a VBA comment line with line number ' 39 This is a VBA comment line with line number ' 40 This is a VBA comment line with line number ' 41 This is a VBA comment line with line number ' 42 This is a VBA comment line with line number ' 43 This is a VBA comment line with line number ' 44 This is a VBA comment line with line number ' 45 This is a VBA comment line with line number ' 46 This is a VBA comment line with line number ' 47 This is a VBA comment line with line number ' 48 This is a VBA comment line with line number ' 49 This is a VBA comment line with line number ' 50 This is a VBA comment line with line number ' 51 This is a VBA comment line with line number ' 52 This is a VBA comment line with line number ' 53 This is a VBA comment line with line number ' 54 This is a VBA comment line with line number ' 55 This is a VBA comment line with line number ' 56 This is a VBA comment line with line number ' 57 This is a VBA comment line with line number ' 58 This is a VBA comment line with line number ' 59 This is a VBA comment line with line number ' 60 This is a VBA comment line with line number ' 61 This is a VBA comment line with line number ' 62 This is a VBA comment line with line number ' 63 This is a VBA comment line with line number ' 64 This is a VBA comment line with line number ' 65 This is a VBA comment line with line number ' 66 This is a VBA comment line with line number ' 67 This is a VBA comment line with line number ' 68 This is a VBA comment line with line number ' 69 This is a VBA comment line with line number ' 70 This is a VBA comment line with line number ' 71 This is a VBA comment line with line number ' 72 This is a VBA comment line with line number ' 73 This is a VBA comment line with line number ' 74 This is a VBA comment line with line number ' 75 This is a VBA comment line with line number ' 76 This is a VBA comment line with line number ' 77 This is a VBA comment line with line number ' 78 This is a VBA comment line with line number ' 79 This is a VBA comment line with line number ' 80 This is a VBA comment line with line number ' 81 This is a VBA comment line with line number ' 82 This is a VBA comment line with line number ' 83 This is a VBA comment line with line number ' 84 This is a VBA comment line with line number ' 85 This is a VBA comment line with line number ' 86 This is a VBA comment line with line number ' 87 This is a VBA comment line with line number ' 88 This is a VBA comment line with line number ' 89 This is a VBA comment line with line number ' 90 This is a VBA comment line with line number ' 91 This is a VBA comment line with line number ' 92 This is a VBA comment line with line number ' 93 This is a VBA comment line with line number ' 94 This is a VBA comment line with line number ' 95 This is a VBA comment line with line number ' 96 This is a VBA comment line with line number ``` -------------------------------- ### VBA ProcTrailer Frame Size Observations Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Provides examples of observed frame sizes within the ProcTrailer block, corresponding to different local variable declarations or argument counts. ```plaintext empty Sub (no locals) -> 00 00 ``` ```plaintext Dim x As Integer (one scalar) -> 08 00 ``` ```plaintext MsgBox 4-slot arg frame -> C0 00 ``` -------------------------------- ### Create New PowerPoint Presentation (.pptm) Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/changelog.md Allows for the creation of a brand-new .pptm file from scratch without launching PowerPoint. The new presentation includes an empty 'Module1'. ```python from pyopenvba import PowerPointFile PowerPointFile.create_new('path/to/new/presentation.pptm') ``` -------------------------------- ### WordFile and PowerPointFile Support Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/changelog.md Introduces full read/write support for Word macro-enabled files (.docm, .dotm, .doc) and PowerPoint macro-enabled files (.pptm, .potm, .ppt). These classes expose the same API as ExcelFile. ```python from pyopenvba import WordFile, PowerPointFile # Example usage for WordFile word_doc = WordFile('path/to/your/document.docm') module_names = word_doc.module_names() print(module_names) # Example usage for PowerPointFile ppt_pres = PowerPointFile('path/to/your/presentation.pptm') print(ppt_pres.vba_project()) ``` -------------------------------- ### Format Dispatch Logic Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md Determines the appropriate pipeline based on the file extension. Use the raw CFB pipeline for .xls files and the ZIP pipeline for .xlsm, .xlsb, and .xlam files. ```pseudo EXT = path.suffix.lower() if EXT in {'.xlsm', '.xlsb', '.xlam'}: use_zip_pipeline() elif EXT == '.xls': use_raw_cfb_pipeline() else: raise UnsupportedFormat(EXT) ``` -------------------------------- ### VBA Subroutine with Message Boxes Source: https://github.com/williamsmithedward/pyopenvba/blob/main/tests/live_access_test/_oracle_out/Module2.bas.txt This VBA subroutine displays three sequential message boxes. It is a basic example of procedural code execution in VBA. ```VBA Option Compare Database Sub Test() MsgBox "This is a test 1" MsgBox "This is a test 2" MsgBox "This is a test 3" End Sub ``` -------------------------------- ### Create New Word Document (.docm) Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/changelog.md Enables the creation of a brand-new .docm file from scratch without needing to launch Microsoft Word. The created file includes default 'ThisDocument' and 'Module1'. ```python from pyopenvba import WordFile WordFile.create_new('path/to/new/document.docm') ``` -------------------------------- ### Create New PowerPoint Presentation with VBA Module Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Illustrates creating a new macro-enabled PowerPoint presentation (.pptm) and embedding a VBA module with a 'MsgBox' subroutine. ```python from pyopenvba import PowerPointFile with PowerPointFile.create_new("new_prs.pptm") as prs: prs.set_module("Module1", 'Sub Hello()\r\n MsgBox "pptm"\r\nEnd Sub\r\n') prs.save() ``` -------------------------------- ### VBA Subroutine with MsgBox 'world' Source: https://github.com/williamsmithedward/pyopenvba/blob/main/scripts/_dump_rows.txt A VBA subroutine that displays a message box with the text 'world'. Similar to the 'hello' example, demonstrating basic message display. ```vba ´╗┐Sub A() MsgBox "world" End Sub ``` -------------------------------- ### Create New Excel Workbooks with VBA Modules Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Demonstrates creating new macro-enabled (.xlsm) and binary (.xlsb) Excel workbooks, embedding a VBA module with a simple 'MsgBox' subroutine in each. ```python from pyopenvba import ExcelFile with ExcelFile.create_new("new_book.xlsm") as wb: wb.set_module("Module1", 'Sub Hello()\r\n MsgBox "xlsm"\r\nEnd Sub\r\n') wb.save() with ExcelFile.create_new("new_book.xlsb") as wb: wb.set_module("Module1", 'Sub Hello()\r\n MsgBox "xlsb"\r\nEnd Sub\r\n') wb.save() ``` -------------------------------- ### Create New Macro-Enabled Files Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Use the `create_new()` method on ExcelFile, WordFile, or PowerPointFile classes to generate a new macro-enabled file from scratch. The file extension determines the format. ```python from pyopenvba import ExcelFile, WordFile, PowerPointFile ``` -------------------------------- ### VBA Subroutine with Message Boxes Source: https://github.com/williamsmithedward/pyopenvba/blob/main/tests/live_access_test/_oracle_plaintext/Module2.bas.txt This VBA code defines a subroutine that displays three different messages using the MsgBox function. It's a basic example for demonstrating output in VBA. ```VBA Option Compare Database Sub Test() MsgBox "PATCHED!!!!!!!!!" MsgBox "This is a test 2" MsgBox "This is a test 3" End Sub ``` -------------------------------- ### VBA7 P-Code Structure Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Illustrates the expected structure of a VBA7 p-code region, starting from a CAFE word and progressing through line records to the p-code itself. Records with an offset of 0xFFFFFFFF represent source-only lines. ```text CAFE word -> 2 reserved -> u16 numLines -> numLines * 12-byte line records (4 skip, u16 line_length, 2 skip, u32 line_offset) -> 10 reserved -> p-code region ``` -------------------------------- ### pyOpenVBA Layered Architecture Overview Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/architecture.md Visual representation of the pyOpenVBA module layering, detailing the responsibilities of each component from the top-level facades to the core Compound File Binary parser. ```text +--------------------------------------------------------+ | excel.py ExcelFile facade | | - ZIP / raw-CFB dispatch by extension | | - save() pipeline (safety gates, structural rewrites)| | - pull / push disk workflow | +--------------------------------------------------------+ | word.py WordFile facade | | - ZIP / raw-CFB dispatch by extension | | - identical save() pipeline as ExcelFile | | - pull / push disk workflow | +--------------------------------------------------------+ | powerpoint.py PowerPointFile facade | | - ZIP / raw-CFB dispatch by extension | | - identical save() pipeline as ExcelFile | | - pull / push disk workflow | +--------------------------------------------------------+ | access_read.py AccessReader facade (READ-ONLY) | | - ACE / Jet 4 page reader (.accdb, .mdb) | | - MS-OVBA blob discovery via signature scan | | - LVAL page-chain walker | | - read_vba_module(name) -> str (pure Python) | | - get_module / vba_modules / iter_vba_modules | | - pull_modules / export_modules / export_module | | - read_vba_module_with_attributes (full preamble) | | - read_project_info / identifiers | | - find_interned_strings / find_module_streams | | - iter_pcode_streams / read_module_pcode_stream | | - disassemble_module (via vba_pcode) | | - iter_msys_objects / find_msys_module | | (MSysObjects system catalog reader) | | - NO write APIs; see msaccess_lessons_learned.md | +--------------------------------------------------------+ | vba.py VBA project layer | | - MS-OVBA compression / decompression | | - dir / PROJECT / PROJECTwm / PROJECTlk parsers | | - VBAProject + VBAModule data model | | - cache invalidation, signature detection | +--------------------------------------------------------+ | vba_pcode.py VBA7 p-code disassembler (EXPERIMENTAL)| | - 264-entry VBA7 opcode table (factual data) | | - per-line p-code streaming parser | | - source-line correlation (to_annotated_listing) | | - dependency-free (no oletools, no pcodedmp) | +--------------------------------------------------------+ | cfb.py MS-CFB layer | | - Compound File Binary parser/writer | | - stream + storage CRUD (case-insensitive lookup) | +--------------------------------------------------------+ ``` -------------------------------- ### Create New Word Document with VBA Module Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Shows how to create a new macro-enabled Word document (.docm) and add a VBA module containing a 'MsgBox' subroutine. ```python from pyopenvba import WordFile with WordFile.create_new("new_doc.docm") as doc: doc.set_module("Module1", 'Sub Hello()\r\n MsgBox "docm"\r\nEnd Sub\r\n') doc.save() ``` -------------------------------- ### Access: List and Read VBA Modules (Read-Only) Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Illustrates how to list all available VBA modules in an Access database and read the source code of a specific module. This functionality is read-only. ```python from pyopenvba import AccessReader with AccessReader("database.accdb") as db: # 1. List all VBA modules in the database. modules = db.vba_modules() print(list(modules)) # ['Module1', 'Form_Form1'] # 2. Read a module's source as a string. source = db.get_module("Module1") print(source) ``` -------------------------------- ### MS-OVBA Compression Helpers Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md Helper functions for calculating chunk size, checking if a chunk is token-compressed, and creating chunk headers based on size and compression type. ```text chunk_size(h) = (h & 0x0FFF) + 3 chunk_is_token(h) = (h >> 15) & 1 make_header(size, is_token) = ((size - 3) & 0x0FFF) | 0x3000 | (is_token << 15) ``` -------------------------------- ### Run the pyOpenVBA demo script Source: https://github.com/williamsmithedward/pyopenvba/blob/main/demo/demo.md Execute the Python script to add a VBA module to an Excel workbook. This script is run from the directory containing the script and the target workbook. ```python python push_demo_module.py ``` -------------------------------- ### Copy Token Packing Helper Functions (Pseudo-code) Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md Provides pseudo-code for helper functions used in packing and unpacking copy tokens, crucial for LZ77-style compression within VBA projects. These functions calculate bit counts, masks, and maximum lengths based on the current decompression state. ```pseudo function copy_token_help(decompressed_current, decompressed_chunk_start): difference = decompressed_current - decompressed_chunk_start bit_count = max(ceil_log2(difference), 4) # 4..12 length_mask = 0xFFFF >> bit_count offset_mask = (~length_mask) & 0xFFFF max_length = length_mask + 3 return (length_mask, offset_mask, bit_count, max_length) ``` ```pseudo function unpack_copy_token(token, dc, dcs): (lm, om, bc, _) = copy_token_help(dc, dcs) length = (token & lm) + 3 offset = ((token & om) >> (16 - bc)) + 1 return (offset, length) ``` ```pseudo function pack_copy_token(offset, length, dc, dcs): (lm, om, bc, _) = copy_token_help(dc, dcs) return ((offset - 1) << (16 - bc)) | ((length - 3) & lm) ``` -------------------------------- ### Page-Aware Byte Diffing Tool Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md A script for performing page-aware byte diffing with page-type tagging, useful for comparing different versions of Access database files. ```python scripts/_diff_accdb.py ``` -------------------------------- ### Compression Chunking Logic (Pseudo-code) Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md Illustrates the decision-making process for handling the final chunk during VBA project compression. It outlines conditions for emitting raw chunks, literal-only token chunks, or full LZ token chunks based on chunk length and overhead. ```pseudo if chunk_len == 4096: emit_raw_chunk(chunk) # safe and exact elif chunk_len + ceil(chunk_len / 8) <= 4096: emit_literal_only_token_chunk() # always valid else: emit_full_lz_token_chunk() # must implement matching ``` -------------------------------- ### For Loop Initialization Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Initializes a For loop. This opcode marks the beginning of a For loop construct in the p-code. ```assembly 71 06 ``` -------------------------------- ### PyOpenVBA Test Layout Structure Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/architecture.md Details the organization of the test suite, including unit tests, integration tests, fuzzing, and live fixture testing for various Office file formats. ```text tests/ test_cfb.py CFB primitives + round-trip test_vba.py MS-OVBA codec + dir/PROJECT parsers test_excel.py ExcelFile facade, end-to-end test_word.py WordFile facade, end-to-end test_powerpoint.py PowerPointFile facade, end-to-end test_pull_push.py Disk workflow test_gates.py Per-roadmap-gate regression tests test_access.py AccessReader read path: page walk, LVAL chain walk, MS-OVBA blob decode, byte-for-byte oracle parity (EXPERIMENTAL) fuzz_corpus/ Persistent fuzz seeds (see test_gates.py Gate 23) live_excel_testing/ Real fixture workbooks (Excel) live_word_testing/ Real fixture documents (Word) live_powerpoint_testing/ Real fixture presentations (PowerPoint) live_access_test/ Real fixture databases (Access) + COM oracle ``` -------------------------------- ### Excel: List, Read, and Edit VBA Modules Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Demonstrates how to list all VBA modules in an Excel workbook, read a module's source code, and modify it. The changes can be saved back to the original file or a new one. ```python from pyopenvba import ExcelFile with ExcelFile("workbook.xlsm") as wb: # 1. List all VBA modules in the workbook. print(wb.module_names()) # ['ThisWorkbook', 'Sheet1', 'Module1'] # 2. Read a module's source as a string. source = wb.get_module("Module1") print(source) # 3. Edit a module and save the workbook. wb.set_module("Module1", 'Sub Hello()\r\n MsgBox "hi"\r\nEnd Sub\r\n') wb.save() # overwrites the original file # wb.save("edited.xlsm") # ...or save to a new file ``` -------------------------------- ### Write Module Stream (New Module) Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md Adds a new module stream to a VBA project. The initial source code is compressed and encoded. No prefix is needed, and MODULEOFFSET is set to 0 in the new MODULE record. ```pseudo seed_body = ovba_compress(encode(initial_source, code_page)) # No prefix needed; set MODULEOFFSET to 0 in the new MODULE record. cfb.add_stream_to_storage("VBA", new_name, seed_body) ``` -------------------------------- ### Class Module Creation Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/changelog.md Full support for creating class modules across all Office hosts. When adding a class module, callers must supply the full attribute header, including the universal VBA class CLSID, to avoid errors. ```python from pyopenvba import ExcelFile excel_file = ExcelFile('path/to/workbook.xlsm') # Example of adding a class module with a required header class_module_source = """ Attribute VB_Name = "MyClass" Attribute VB_Base = "0{FCFB3D2A-A0FA-1068-A738-08002B3371B5}" ' Universal VBA class CLSID Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = False Attribute VB_Exposed = True Public Sub DoSomething() MsgBox "Hello from MyClass!" End Sub """ excel_file.add_module(name='MyClass', body=class_module_source, kind='other') excel_file.save('path/to/modified/workbook.xlsm') ``` -------------------------------- ### Serialize PROJECTwm Stream Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md Serializes a list of MBCS and UTF-16LE name pairs for the PROJECTwm stream. Ensure the correct code page is used for MBCS encoding. ```pseudo function serialize_projectwm(pairs, code_page): out = bytearray() for (mbcs_name, unicode_name) in pairs: out.extend(encode(mbcs_name, code_page)) out.append(0x00) out.extend(encode_utf16le(unicode_name)) out.extend(b"\x00\x00") out.extend(b"\x00\x00") return bytes(out) ``` -------------------------------- ### ExcelFile Support for .xlsb Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/changelog.md Enhances ExcelFile.create_new() to support the .xlsb format in addition to .xlsm. The choice of template is determined by the file extension provided in the path. ```python from pyopenvba import ExcelFile # Create a new .xlsm file ExcelFile.create_new('path/to/new/workbook.xlsm') # Create a new .xlsb file ExcelFile.create_new('path/to/new/workbook.xlsb') ``` -------------------------------- ### Disk-based Pull/Push Helpers for PowerPoint Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/changelog.md Introduces disk-based helper functions for pulling and pushing VBA modules to and from PowerPoint presentations, analogous to the Excel and Word helpers. ```python from pyopenvba import pull_ppt, push_ppt # Pull modules from a PowerPoint presentation to a directory pull_ppt('path/to/your/presentation.pptm', 'path/to/destination/directory') # Push modules from a directory to a PowerPoint presentation push_ppt('path/to/source/directory', 'path/to/your/presentation.pptm') ``` -------------------------------- ### OOXML Outer-Container VBA Project Replacement Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md This pseudo-code demonstrates how to replace the `xl/vbaProject.bin` entry within an OOXML file while preserving all other entries' data, compression methods, and metadata. It iterates through the input ZIP archive and writes entries to an output buffer, substituting only the VBA project binary. ```pseudo with ZipFile(input_path) as zin, ZipFile(out_buf, "w") as zout: for info in zin.infolist(): if info.filename == "xl/vbaProject.bin": zinfo = ZipInfo(info.filename, info.date_time) zinfo.compress_type = info.compress_type zinfo.external_attr = info.external_attr zinfo.create_system = info.create_system zout.writestr(zinfo, new_vba_bin) else: data = zin.read(info.filename) zinfo = clone_zinfo(info) zout.writestr(zinfo, data) write_atomically(out_buf, out_path) ``` -------------------------------- ### Push Small Immediate Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Pushes a small, embedded immediate value onto the stack. This is a compact representation for small constants. ```assembly 77 06 ``` -------------------------------- ### Write Module Stream (In-place Source Replacement) Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md Replaces the source code of an existing module within a VBA project. It preserves the stream prefix, compresses the new raw source code, and writes the updated stream back. ```pseudo old = cfb.get_stream_in_storage("VBA", module.stream_name) prefix = old[:module.text_offset] # preserve verbatim new_raw = encode(new_text, code_page=project.code_page) new_body = ovba_compress(new_raw) cfb.write_stream_in_storage("VBA", module.stream_name, prefix + new_body) ``` -------------------------------- ### Procedure Trailer Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Appears exactly once per active row, likely containing metadata related to the procedure, such as its cookie or length. ```assembly 7B 02 ``` -------------------------------- ### Synthesize Minimal Attribute Header on Add Module Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/changelog.md When adding a module without a supplied header, add_module(name, body, kind=standard) now synthesizes a minimal 'Attribute VB_Name = ""' header. Caller-supplied headers are used as-is. ```python from pyopenvba import ExcelFile wb = ExcelFile('workbook.xlsm') # Add a module without providing a header; a minimal one will be synthesized. wb.add_module(name='NewStandardModule', body='Sub Test()\n MsgBox "This is a new standard module."\nEnd Sub') # Add a module with a custom header (e.g., for a class module) custom_header = "Attribute VB_Name = \"MyCustomClass\"\nAttribute VB_Base = \"0{FCFB3D2A-A0FA-1068-A738-08002B3371B5}\"\n" wb.add_module(name='MyCustomClass', body='Public Sub Greet()\n MsgBox "Hello from custom class."\nEnd Sub', kind='other', header=custom_header) wb.save('workbook_modules_added.xlsm') ``` -------------------------------- ### Disassemble Module Stream (Low-Level) Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md This is the low-level entry point for disassembling p-code if you already possess the raw byte data. It requires the byte stream and an optional flag for 64-bit encoding. ```python pyopenvba.vba_pcode.disassemble_module_stream(raw_bytes, *, is_64bit=True) ``` -------------------------------- ### VBA Subroutine with MsgBox 'hello' Source: https://github.com/williamsmithedward/pyopenvba/blob/main/scripts/_dump_rows.txt A VBA subroutine that displays a message box with the text 'hello'. Useful for simple output or debugging. ```vba ´╗┐Sub A() MsgBox "hello" End Sub ``` -------------------------------- ### PyOpenVBA Exception Hierarchy Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/architecture.md Illustrates the inheritance structure of exceptions used within PyOpenVBA. Parsers must raise from this hierarchy or ValueError. ```text PyOpenVBAError UnsupportedFormatError bad extension / host CFBError malformed CFB structure VBAProjectError malformed VBA project, or mutation refused ``` -------------------------------- ### Excel File Read Path Data Flow Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/architecture.md Illustrates the sequence of operations when reading an Excel file, from opening the file to parsing VBA project streams. ```text ExcelFile(path) -> _open() (excel.py) -> _open_zip() / _open_cfb_direct() -> extract xl/vbaProject.bin (excel.py) -> CFB.from_bytes(...) (cfb.py) -> parse_vba_project(cfb) (vba.py) -> decompress(dir_stream) (vba.py) -> _parse_dir_stream(...) (vba.py) -> parse_project_stream(...) (vba.py) -> [for each module] cfb.get_stream_in_storage("VBA", name) slice from MODULEOFFSET decompress(...) decode(..., code_page) ``` -------------------------------- ### For Loop Step / Next Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Represents the step and next iteration logic for a For loop. This opcode is executed within the loop. ```assembly 73 06 ``` -------------------------------- ### PowerPoint: Edit VBA Module and Save Source: https://github.com/williamsmithedward/pyopenvba/blob/main/README.md Demonstrates how to update a VBA module's source code in a PowerPoint presentation and save the modified file. ```python from pyopenvba import PowerPointFile with PowerPointFile("presentation.pptm") as prs: print(prs.module_names()) # ['Module1'] prs.set_module("Module1", 'Sub Hello()\r\n MsgBox "hi"\r\nEnd Sub\r\n') prs.save() ``` -------------------------------- ### Excel File Write Path (Save) Pipeline Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/architecture.md Details the step-by-step process for saving changes to an Excel file, emphasizing the atomic-like write operation and safety mechanisms. ```text 1. Detect mutation (any rename / add / delete / dirty module) 2. Safety gates (protected? signed?) 3. Apply renames (CFB stream rename) 4. Apply adds (CFB stream create with seeded body) 5. Apply deletes (CFB stream remove) 6. Replace dirty module bodies (compress + write back) 7. Rewrite dir / PROJECT / PROJECTwm (if structure changed) 8. Invalidate _VBA_PROJECT cache (zero PerformanceCache body) 9. Drop __SRP_* streams (force regeneration) 10. Drop signature streams (if mutating, with warning) 11. Serialize CFB (cfb.to_bytes()) 12. Write outer container (replace single ZIP entry, or raw CFB) ``` -------------------------------- ### Minimum Viable Read-Only Extractor Pseudocode Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/ms-ovba-implementation-guide_v2.md This pseudocode outlines the essential steps for extracting VBA modules from an Excel file, including opening the zip, reading the VBA project binary, parsing directory information, and decompressing module sources. ```pseudo function extract_modules(xlsm_path): zip = open_zip(xlsm_path) if "xl/vbaProject.bin" not in zip: raise VBAProjectError("no vbaProject.bin") blob = zip.read("xl/vbaProject.bin") cfb = CFB.from_bytes(blob) dir_raw = ovba_decompress(cfb.get_stream_in_storage("VBA", "dir")) project = parse_dir(dir_raw) out = [] for module in project.modules: stream = cfb.get_stream_in_storage("VBA", module.stream_name) compressed = stream[module.text_offset:] source_bytes = ovba_decompress(compressed) source_text = decode(source_bytes, code_page=project.code_page) out.append((module.name, source_text)) return out ``` -------------------------------- ### VBE-style Body-Only Source Edits for Modules Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/changelog.md Enhances ExcelFile.set_module() to accept either a full source replacement or a bare body. When a bare body is provided, the module's existing attribute header is automatically prepended, mimicking the Visual Basic Editor (VBE) user experience. ```python from pyopenvba import ExcelFile wb = ExcelFile('workbook.xlsm') # Example: Update only the executable code body of a module # The existing attribute header will be preserved. new_body = "\nSub MyUpdatedSub()\n MsgBox \"Updated code!\"\nEnd Sub\n" wb.set_module('Module1', new_body) wb.save('workbook_updated.xlsm') ``` -------------------------------- ### Call Block Open Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/access_pcode_re.md Marks the beginning of a block of calls, often used before a specific function call like MsgBox. ```assembly 67 02 4C 00 00 00 ``` -------------------------------- ### Disk-based Pull/Push Helpers for Word Source: https://github.com/williamsmithedward/pyopenvba/blob/main/docs/changelog.md Provides disk-based helper functions for pulling and pushing VBA modules to and from Word documents, mirroring the existing API for Excel. ```python from pyopenvba import pull_word, push_word # Pull modules from a Word document to a directory pull_word('path/to/your/document.docm', 'path/to/destination/directory') # Push modules from a directory to a Word document push_word('path/to/source/directory', 'path/to/your/document.docm') ``` -------------------------------- ### VBA Subroutine Assigning an Integer Source: https://github.com/williamsmithedward/pyopenvba/blob/main/scripts/_dump_rows.txt Illustrates declaring an integer variable 'x' and assigning it the value 7 in VBA. Shows basic variable assignment. ```vba ´╗┐Sub A() Dim x As Integer x = 7 End Sub ```