Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/build.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
name: Build

on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

jobs:
build:
# windows-2022 ships Visual Studio 2022 (with the C++ ATL and MFC
# components the native build needs) and CMake preinstalled.
runs-on: windows-2022

steps:
- name: Check out repository (with submodules)
uses: actions/checkout@v7
with:
submodules: recursive

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Show build tool versions
shell: pwsh
run: |
cmake --version
java -version

# -DbuildNative=true forces a real rebuild instead of packaging the
# committed bin/ DLLs (JitPack's only option, since it can't run
# MSVC). package-only, run first, just to catch Release-only compile
# regressions before the Debug build below becomes the installed jar.
- name: Build native (Release)
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# TestObject (needed by tests) only compiles into Debug builds.
# install, not package, so "Run tests" below can resolve com4j from
# the local repo without rebuilding or needing -am.
- name: Build native (Debug)
shell: pwsh
run: mvn -B -pl "!test" install -DbuildNative=true -Dmode=Debug

# Registers com4j.dll as TestObject's COM server. Plain regsvr32
# works unelevated: GitHub's Windows runners run as Administrator
# with UAC disabled (actions/runner-images discussion #6557).
- name: Register COM test object
shell: pwsh
run: |
$dll = Resolve-Path "bin\x64\Debug\com4j.dll"
$p = Start-Process -FilePath "$env:SystemRoot\System32\regsvr32.exe" -ArgumentList "/s", "$dll" -Wait -PassThru -NoNewWindow
if ($p.ExitCode -ne 0) {
throw "regsvr32 failed with exit code $($p.ExitCode)"
}

- name: Run tests
shell: pwsh
run: mvn -B test -pl test
55 changes: 55 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
name: Release

on:
release:
types: [published]

permissions:
contents: write

jobs:
build-and-upload:
runs-on: windows-2022

steps:
- name: Check out repository (with submodules) at the release tag
uses: actions/checkout@v7
with:
submodules: recursive
ref: ${{ github.event.release.tag_name }}

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

# Sets the version to the release tag
- name: Set version to release tag
shell: pwsh
run: mvn -B versions:set "-DnewVersion=${{ github.event.release.tag_name }}" -DgenerateBackupPoms=false

# Rebuilds native/com4j.dll (Release, x86+x64) from source rather than
# trusting whatever's committed, so the uploaded jar always reflects
# the exact code at this tag.
- name: Build native (Release) and package
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# Uploads all modules' built artifacts as release assets
- name: Upload build artifacts to the release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
function Latest($pattern) {
(Get-ChildItem $pattern | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
}
$files = @(
Latest "runtime/target/com4j-*.jar"
Latest "tlbimp/target/tlbimp-*.jar"
Latest "maven-com4j-plugin/target/maven-com4j-plugin-*.jar"
Latest "distribution/target/com4j-dist-*-all.zip"
)
gh release upload "${{ github.event.release.tag_name }}" $files --repo ${{ github.repository }} --clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,3 +10,8 @@
*.tli
vc90.idb
vc90.pdb
native/cmake-build*/

# bin/ holds the prebuilt com4j.dll (x86 and x64, Release and Debug) that the
# Java build packages by default and that JitPack relies on, since it can't
# build native/ itself - these are intentionally committed, do not ignore.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
[submodule "jnitl"]
path = jnitl
url = git://github.com/kohsuke/jnitl.git
url = https://github.com/kohsuke/jnitl.git
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions jitpack.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
jdk:
- openjdk17

# Skip building from source (this project needs a Windows/MSVC toolchain
# JitPack's Linux build servers don't have) and instead install the
# prebuilt artifacts already uploaded to the matching GitHub release by
# .github/workflows/release.yml.
install:
- OWNER=${GROUP#com.github.}
- REPO=${ARTIFACT}
- MODULE_GROUP=${GROUP}.${REPO}
- BASE_URL=https://github.com/${OWNER}/${REPO}/releases/download/${VERSION}

- curl -L -f -o com4j.jar ${BASE_URL}/com4j-${VERSION}.jar
- mvn install:install-file -Dfile=com4j.jar -DgroupId=${MODULE_GROUP} -DartifactId=com4j -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o tlbimp.jar ${BASE_URL}/tlbimp-${VERSION}.jar
- mvn install:install-file -Dfile=tlbimp.jar -DgroupId=${MODULE_GROUP} -DartifactId=tlbimp -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o maven-com4j-plugin.jar ${BASE_URL}/maven-com4j-plugin-${VERSION}.jar
- mvn install:install-file -Dfile=maven-com4j-plugin.jar -DgroupId=${MODULE_GROUP} -DartifactId=maven-com4j-plugin -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true
174 changes: 174 additions & 0 deletions native/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
cmake_minimum_required(VERSION 3.20)

cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

project(com4j_native LANGUAGES C CXX ASM_MASM)

if(NOT MSVC)
message(FATAL_ERROR "This project only builds with MSVC on Windows.")
endif()

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(COM4J_ARCH_DEFINE X86_WIN64)
set(COM4J_PLATFORM_DEFINE WIN64)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win64.asm64)
set(MIDL_ENV win64)
else()
set(COM4J_ARCH_DEFINE X86_WIN32)
set(COM4J_PLATFORM_DEFINE WIN32)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win32.asm)
set(MIDL_ENV win32)
endif()

set_source_files_properties(${LIBFFI_ASM} PROPERTIES LANGUAGE ASM_MASM)

# ---------------------------------------------------------------------------
# JNI
# ---------------------------------------------------------------------------
if(DEFINED JAVA_HOME)
set(ENV{JAVA_HOME} ${JAVA_HOME})
endif()
find_package(JNI REQUIRED)

# ---------------------------------------------------------------------------
# jnitl (git submodule, ../jnitl) - built as a small static lib.
# native/stdafx.h pulls in jnitl.h, which does:
# #pragma comment(lib, "jnitl.lib") (Release, static CRT)
# #pragma comment(lib, "jnitld.lib") (Debug, static CRT)
# so name the output to match and make sure it's on the link path.
# ---------------------------------------------------------------------------
set(JNITL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jnitl)

add_library(jnitl STATIC
${JNITL_DIR}/source/jnitl.cpp
${JNITL_DIR}/source/accessor.cpp
)
target_include_directories(jnitl PUBLIC ${JNITL_DIR}/include)
target_include_directories(jnitl PRIVATE ${JNI_INCLUDE_DIRS})
set_target_properties(jnitl PROPERTIES
OUTPUT_NAME "jnitl"
DEBUG_POSTFIX "d"
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/jnitl-lib
)
target_compile_definitions(jnitl PRIVATE WIN32 ${COM4J_PLATFORM_DEFINE} UNICODE _UNICODE)
# original vcproj built with TreatWChar_tAsBuiltInType="false" (/Zc:wchar_t-),
# which is why jni.h's `jchar` (unsigned short) and `wchar_t*`/BSTR interconvert
# implicitly all over this codebase.
target_compile_options(jnitl PRIVATE /Zc:wchar_t-)

# ---------------------------------------------------------------------------
# MIDL: com4j.idl -> com4j.tlb (+ generated .h/.c, unused but let midl emit
# its normal output). typelib.cpp does `#import "com4j.tlb" no_namespace`
# and com4j.rc embeds it as a TYPELIB resource, so both need the tlb's
# directory on their include search path.
# ---------------------------------------------------------------------------
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MIDL_SDK_ARCH x64)
else()
set(MIDL_SDK_ARCH x86)
endif()
file(GLOB MIDL_SDK_HINTS "C:/Program Files (x86)/Windows Kits/10/bin/10.0.*/${MIDL_SDK_ARCH}")
list(SORT MIDL_SDK_HINTS ORDER DESCENDING)
find_program(MIDL_EXECUTABLE midl.exe HINTS ${MIDL_SDK_HINTS} REQUIRED)

set(COM4J_TLB ${CMAKE_CURRENT_BINARY_DIR}/com4j.tlb)
set(COM4J_MIDL_H ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl.h)
set(COM4J_MIDL_C ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl_i.c)

add_custom_command(
OUTPUT ${COM4J_TLB}
COMMAND ${MIDL_EXECUTABLE}
/nologo
/env ${MIDL_ENV}
/tlb ${COM4J_TLB}
/h ${COM4J_MIDL_H}
/iid ${COM4J_MIDL_C}
/out ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running MIDL on com4j.idl"
VERBATIM
)
add_custom_target(com4j_idl DEPENDS ${COM4J_TLB})

# ---------------------------------------------------------------------------
# com4j.dll
# ---------------------------------------------------------------------------
set(COM4J_SOURCES
com4j.cpp
com4j_Win32Lock.cpp
error.cpp
eventReceiver.cpp
invoke.cpp
java_id.cpp
registry.cpp
safearray.cpp
stdafx.cpp
TestObject.cpp
toJava.cpp
typelib.cpp
variant.cpp
)

set(LIBFFI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libffi)
set(LIBFFI_SOURCES
${LIBFFI_DIR}/src/debug.c
${LIBFFI_DIR}/src/x86/ffi.c
${LIBFFI_DIR}/src/prep_cif.c
${LIBFFI_DIR}/src/types.c
${LIBFFI_ASM}
)

add_library(com4j SHARED
${COM4J_SOURCES}
${LIBFFI_SOURCES}
com4j.rc
)

add_dependencies(com4j com4j_idl)

target_include_directories(com4j PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${JNITL_DIR}/include
${LIBFFI_DIR}/include
${JNI_INCLUDE_DIRS}
)

target_compile_definitions(com4j PRIVATE
${COM4J_PLATFORM_DEFINE}
_WINDOWS
_USRDLL
COM4J_EXPORTS
${COM4J_ARCH_DEFINE}
UNICODE
_UNICODE
$<$<CONFIG:Debug>:_DEBUG>
$<$<NOT:$<CONFIG:Debug>>:NDEBUG>
)
target_compile_options(com4j PRIVATE $<$<COMPILE_LANGUAGE:CXX,C>:/Zc:wchar_t->)

# jnitl.h does `#pragma comment(lib, "jnitl.lib"/"jnitld.lib")` - that pragma-driven
# search needs the jnitl target's actual (per-config) output dir on the /LIBPATH,
# in addition to linking it directly as a CMake target dependency.
target_link_directories(com4j PRIVATE $<TARGET_FILE_DIR:jnitl>)
target_link_libraries(com4j PRIVATE jnitl ole32 oleaut32 uuid)

set(COM4J_LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/com4j.def")
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
# libffi's hand-written win32.asm predates SAFESEH exception-handler records;
# the modern linker refuses to produce a SAFESEH image without this.
set(COM4J_LINK_FLAGS "${COM4J_LINK_FLAGS} /SAFESEH:NO")
endif()
set_target_properties(com4j PROPERTIES
LINK_FLAGS "${COM4J_LINK_FLAGS}"
)

# make sure the rc compile step can find com4j.tlb (embedded via `1 TYPELIB "com4j.tlb"`)
set_source_files_properties(com4j.rc PROPERTIES
COMPILE_OPTIONS "/I${CMAKE_CURRENT_BINARY_DIR}"
)

# TestObject.cpp compiles to nothing outside _DEBUG - fine to always include.
13 changes: 10 additions & 3 deletions native/TestObject.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,8 +31,15 @@ STDMETHODIMP CTestObject::raw_TestVariant(VARIANT v1, VARIANT* v2, VARIANT* v3)

STDMETHODIMP CTestObject::raw_outByteBuf(BSTR bstrEncodedData, long* plSize, unsigned char** ppbData)
{
*plSize = 30;
*ppbData = (BYTE*)"Hello, World!";
static const char text[] = "Hello, World!";
const long len = sizeof(text)-1; // exclude the terminating '\0'

*ppbData = (BYTE*)CoTaskMemAlloc(len);
if(*ppbData==NULL)
return E_OUTOFMEMORY;

memcpy(*ppbData, text, len);
*plSize = len;

return S_OK;
}
Expand All@@ -45,4 +52,4 @@ STDMETHODIMP CTestObject::raw_testUI8Conv(VARIANT* in, VARIANT* out)
return ::VariantCopy(out,in);
}

#endif
#endif
29 changes: 0 additions & 29 deletions native/build.xml

This file was deleted.

Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/build.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
name: Build

on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

jobs:
build:
# windows-2022 ships Visual Studio 2022 (with the C++ ATL and MFC
# components the native build needs) and CMake preinstalled.
runs-on: windows-2022

steps:
- name: Check out repository (with submodules)
uses: actions/checkout@v7
with:
submodules: recursive

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Show build tool versions
shell: pwsh
run: |
cmake --version
java -version

# -DbuildNative=true forces a real rebuild instead of packaging the
# committed bin/ DLLs (JitPack's only option, since it can't run
# MSVC). package-only, run first, just to catch Release-only compile
# regressions before the Debug build below becomes the installed jar.
- name: Build native (Release)
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# TestObject (needed by tests) only compiles into Debug builds.
# install, not package, so "Run tests" below can resolve com4j from
# the local repo without rebuilding or needing -am.
- name: Build native (Debug)
shell: pwsh
run: mvn -B -pl "!test" install -DbuildNative=true -Dmode=Debug

# Registers com4j.dll as TestObject's COM server. Plain regsvr32
# works unelevated: GitHub's Windows runners run as Administrator
# with UAC disabled (actions/runner-images discussion #6557).
- name: Register COM test object
shell: pwsh
run: |
$dll = Resolve-Path "bin\x64\Debug\com4j.dll"
$p = Start-Process -FilePath "$env:SystemRoot\System32\regsvr32.exe" -ArgumentList "/s", "$dll" -Wait -PassThru -NoNewWindow
if ($p.ExitCode -ne 0) {
throw "regsvr32 failed with exit code $($p.ExitCode)"
}

- name: Run tests
shell: pwsh
run: mvn -B test -pl test
55 changes: 55 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
name: Release

on:
release:
types: [published]

permissions:
contents: write

jobs:
build-and-upload:
runs-on: windows-2022

steps:
- name: Check out repository (with submodules) at the release tag
uses: actions/checkout@v7
with:
submodules: recursive
ref: ${{ github.event.release.tag_name }}

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

# Sets the version to the release tag
- name: Set version to release tag
shell: pwsh
run: mvn -B versions:set "-DnewVersion=${{ github.event.release.tag_name }}" -DgenerateBackupPoms=false

# Rebuilds native/com4j.dll (Release, x86+x64) from source rather than
# trusting whatever's committed, so the uploaded jar always reflects
# the exact code at this tag.
- name: Build native (Release) and package
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# Uploads all modules' built artifacts as release assets
- name: Upload build artifacts to the release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
function Latest($pattern) {
(Get-ChildItem $pattern | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
}
$files = @(
Latest "runtime/target/com4j-*.jar"
Latest "tlbimp/target/tlbimp-*.jar"
Latest "maven-com4j-plugin/target/maven-com4j-plugin-*.jar"
Latest "distribution/target/com4j-dist-*-all.zip"
)
gh release upload "${{ github.event.release.tag_name }}" $files --repo ${{ github.repository }} --clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,3 +10,8 @@
*.tli
vc90.idb
vc90.pdb
native/cmake-build*/

# bin/ holds the prebuilt com4j.dll (x86 and x64, Release and Debug) that the
# Java build packages by default and that JitPack relies on, since it can't
# build native/ itself - these are intentionally committed, do not ignore.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
[submodule "jnitl"]
path = jnitl
url = git://github.com/kohsuke/jnitl.git
url = https://github.com/kohsuke/jnitl.git
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions jitpack.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
jdk:
- openjdk17

# Skip building from source (this project needs a Windows/MSVC toolchain
# JitPack's Linux build servers don't have) and instead install the
# prebuilt artifacts already uploaded to the matching GitHub release by
# .github/workflows/release.yml.
install:
- OWNER=${GROUP#com.github.}
- REPO=${ARTIFACT}
- MODULE_GROUP=${GROUP}.${REPO}
- BASE_URL=https://github.com/${OWNER}/${REPO}/releases/download/${VERSION}

- curl -L -f -o com4j.jar ${BASE_URL}/com4j-${VERSION}.jar
- mvn install:install-file -Dfile=com4j.jar -DgroupId=${MODULE_GROUP} -DartifactId=com4j -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o tlbimp.jar ${BASE_URL}/tlbimp-${VERSION}.jar
- mvn install:install-file -Dfile=tlbimp.jar -DgroupId=${MODULE_GROUP} -DartifactId=tlbimp -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o maven-com4j-plugin.jar ${BASE_URL}/maven-com4j-plugin-${VERSION}.jar
- mvn install:install-file -Dfile=maven-com4j-plugin.jar -DgroupId=${MODULE_GROUP} -DartifactId=maven-com4j-plugin -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true
174 changes: 174 additions & 0 deletions native/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
cmake_minimum_required(VERSION 3.20)

cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

project(com4j_native LANGUAGES C CXX ASM_MASM)

if(NOT MSVC)
message(FATAL_ERROR "This project only builds with MSVC on Windows.")
endif()

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(COM4J_ARCH_DEFINE X86_WIN64)
set(COM4J_PLATFORM_DEFINE WIN64)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win64.asm64)
set(MIDL_ENV win64)
else()
set(COM4J_ARCH_DEFINE X86_WIN32)
set(COM4J_PLATFORM_DEFINE WIN32)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win32.asm)
set(MIDL_ENV win32)
endif()

set_source_files_properties(${LIBFFI_ASM} PROPERTIES LANGUAGE ASM_MASM)

# ---------------------------------------------------------------------------
# JNI
# ---------------------------------------------------------------------------
if(DEFINED JAVA_HOME)
set(ENV{JAVA_HOME} ${JAVA_HOME})
endif()
find_package(JNI REQUIRED)

# ---------------------------------------------------------------------------
# jnitl (git submodule, ../jnitl) - built as a small static lib.
# native/stdafx.h pulls in jnitl.h, which does:
# #pragma comment(lib, "jnitl.lib") (Release, static CRT)
# #pragma comment(lib, "jnitld.lib") (Debug, static CRT)
# so name the output to match and make sure it's on the link path.
# ---------------------------------------------------------------------------
set(JNITL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jnitl)

add_library(jnitl STATIC
${JNITL_DIR}/source/jnitl.cpp
${JNITL_DIR}/source/accessor.cpp
)
target_include_directories(jnitl PUBLIC ${JNITL_DIR}/include)
target_include_directories(jnitl PRIVATE ${JNI_INCLUDE_DIRS})
set_target_properties(jnitl PROPERTIES
OUTPUT_NAME "jnitl"
DEBUG_POSTFIX "d"
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/jnitl-lib
)
target_compile_definitions(jnitl PRIVATE WIN32 ${COM4J_PLATFORM_DEFINE} UNICODE _UNICODE)
# original vcproj built with TreatWChar_tAsBuiltInType="false" (/Zc:wchar_t-),
# which is why jni.h's `jchar` (unsigned short) and `wchar_t*`/BSTR interconvert
# implicitly all over this codebase.
target_compile_options(jnitl PRIVATE /Zc:wchar_t-)

# ---------------------------------------------------------------------------
# MIDL: com4j.idl -> com4j.tlb (+ generated .h/.c, unused but let midl emit
# its normal output). typelib.cpp does `#import "com4j.tlb" no_namespace`
# and com4j.rc embeds it as a TYPELIB resource, so both need the tlb's
# directory on their include search path.
# ---------------------------------------------------------------------------
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MIDL_SDK_ARCH x64)
else()
set(MIDL_SDK_ARCH x86)
endif()
file(GLOB MIDL_SDK_HINTS "C:/Program Files (x86)/Windows Kits/10/bin/10.0.*/${MIDL_SDK_ARCH}")
list(SORT MIDL_SDK_HINTS ORDER DESCENDING)
find_program(MIDL_EXECUTABLE midl.exe HINTS ${MIDL_SDK_HINTS} REQUIRED)

set(COM4J_TLB ${CMAKE_CURRENT_BINARY_DIR}/com4j.tlb)
set(COM4J_MIDL_H ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl.h)
set(COM4J_MIDL_C ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl_i.c)

add_custom_command(
OUTPUT ${COM4J_TLB}
COMMAND ${MIDL_EXECUTABLE}
/nologo
/env ${MIDL_ENV}
/tlb ${COM4J_TLB}
/h ${COM4J_MIDL_H}
/iid ${COM4J_MIDL_C}
/out ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running MIDL on com4j.idl"
VERBATIM
)
add_custom_target(com4j_idl DEPENDS ${COM4J_TLB})

# ---------------------------------------------------------------------------
# com4j.dll
# ---------------------------------------------------------------------------
set(COM4J_SOURCES
com4j.cpp
com4j_Win32Lock.cpp
error.cpp
eventReceiver.cpp
invoke.cpp
java_id.cpp
registry.cpp
safearray.cpp
stdafx.cpp
TestObject.cpp
toJava.cpp
typelib.cpp
variant.cpp
)

set(LIBFFI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libffi)
set(LIBFFI_SOURCES
${LIBFFI_DIR}/src/debug.c
${LIBFFI_DIR}/src/x86/ffi.c
${LIBFFI_DIR}/src/prep_cif.c
${LIBFFI_DIR}/src/types.c
${LIBFFI_ASM}
)

add_library(com4j SHARED
${COM4J_SOURCES}
${LIBFFI_SOURCES}
com4j.rc
)

add_dependencies(com4j com4j_idl)

target_include_directories(com4j PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${JNITL_DIR}/include
${LIBFFI_DIR}/include
${JNI_INCLUDE_DIRS}
)

target_compile_definitions(com4j PRIVATE
${COM4J_PLATFORM_DEFINE}
_WINDOWS
_USRDLL
COM4J_EXPORTS
${COM4J_ARCH_DEFINE}
UNICODE
_UNICODE
$<$<CONFIG:Debug>:_DEBUG>
$<$<NOT:$<CONFIG:Debug>>:NDEBUG>
)
target_compile_options(com4j PRIVATE $<$<COMPILE_LANGUAGE:CXX,C>:/Zc:wchar_t->)

# jnitl.h does `#pragma comment(lib, "jnitl.lib"/"jnitld.lib")` - that pragma-driven
# search needs the jnitl target's actual (per-config) output dir on the /LIBPATH,
# in addition to linking it directly as a CMake target dependency.
target_link_directories(com4j PRIVATE $<TARGET_FILE_DIR:jnitl>)
target_link_libraries(com4j PRIVATE jnitl ole32 oleaut32 uuid)

set(COM4J_LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/com4j.def")
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
# libffi's hand-written win32.asm predates SAFESEH exception-handler records;
# the modern linker refuses to produce a SAFESEH image without this.
set(COM4J_LINK_FLAGS "${COM4J_LINK_FLAGS} /SAFESEH:NO")
endif()
set_target_properties(com4j PROPERTIES
LINK_FLAGS "${COM4J_LINK_FLAGS}"
)

# make sure the rc compile step can find com4j.tlb (embedded via `1 TYPELIB "com4j.tlb"`)
set_source_files_properties(com4j.rc PROPERTIES
COMPILE_OPTIONS "/I${CMAKE_CURRENT_BINARY_DIR}"
)

# TestObject.cpp compiles to nothing outside _DEBUG - fine to always include.
13 changes: 10 additions & 3 deletions native/TestObject.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,8 +31,15 @@ STDMETHODIMP CTestObject::raw_TestVariant(VARIANT v1, VARIANT* v2, VARIANT* v3)

STDMETHODIMP CTestObject::raw_outByteBuf(BSTR bstrEncodedData, long* plSize, unsigned char** ppbData)
{
*plSize = 30;
*ppbData = (BYTE*)"Hello, World!";
static const char text[] = "Hello, World!";
const long len = sizeof(text)-1; // exclude the terminating '\0'

*ppbData = (BYTE*)CoTaskMemAlloc(len);
if(*ppbData==NULL)
return E_OUTOFMEMORY;

memcpy(*ppbData, text, len);
*plSize = len;

return S_OK;
}
Expand All@@ -45,4 +52,4 @@ STDMETHODIMP CTestObject::raw_testUI8Conv(VARIANT* in, VARIANT* out)
return ::VariantCopy(out,in);
}

#endif
#endif
29 changes: 0 additions & 29 deletions native/build.xml

This file was deleted.

Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/build.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
name: Build

on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

jobs:
build:
# windows-2022 ships Visual Studio 2022 (with the C++ ATL and MFC
# components the native build needs) and CMake preinstalled.
runs-on: windows-2022

steps:
- name: Check out repository (with submodules)
uses: actions/checkout@v7
with:
submodules: recursive

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Show build tool versions
shell: pwsh
run: |
cmake --version
java -version

# -DbuildNative=true forces a real rebuild instead of packaging the
# committed bin/ DLLs (JitPack's only option, since it can't run
# MSVC). package-only, run first, just to catch Release-only compile
# regressions before the Debug build below becomes the installed jar.
- name: Build native (Release)
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# TestObject (needed by tests) only compiles into Debug builds.
# install, not package, so "Run tests" below can resolve com4j from
# the local repo without rebuilding or needing -am.
- name: Build native (Debug)
shell: pwsh
run: mvn -B -pl "!test" install -DbuildNative=true -Dmode=Debug

# Registers com4j.dll as TestObject's COM server. Plain regsvr32
# works unelevated: GitHub's Windows runners run as Administrator
# with UAC disabled (actions/runner-images discussion #6557).
- name: Register COM test object
shell: pwsh
run: |
$dll = Resolve-Path "bin\x64\Debug\com4j.dll"
$p = Start-Process -FilePath "$env:SystemRoot\System32\regsvr32.exe" -ArgumentList "/s", "$dll" -Wait -PassThru -NoNewWindow
if ($p.ExitCode -ne 0) {
throw "regsvr32 failed with exit code $($p.ExitCode)"
}

- name: Run tests
shell: pwsh
run: mvn -B test -pl test
55 changes: 55 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
name: Release

on:
release:
types: [published]

permissions:
contents: write

jobs:
build-and-upload:
runs-on: windows-2022

steps:
- name: Check out repository (with submodules) at the release tag
uses: actions/checkout@v7
with:
submodules: recursive
ref: ${{ github.event.release.tag_name }}

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

# Sets the version to the release tag
- name: Set version to release tag
shell: pwsh
run: mvn -B versions:set "-DnewVersion=${{ github.event.release.tag_name }}" -DgenerateBackupPoms=false

# Rebuilds native/com4j.dll (Release, x86+x64) from source rather than
# trusting whatever's committed, so the uploaded jar always reflects
# the exact code at this tag.
- name: Build native (Release) and package
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# Uploads all modules' built artifacts as release assets
- name: Upload build artifacts to the release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
function Latest($pattern) {
(Get-ChildItem $pattern | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
}
$files = @(
Latest "runtime/target/com4j-*.jar"
Latest "tlbimp/target/tlbimp-*.jar"
Latest "maven-com4j-plugin/target/maven-com4j-plugin-*.jar"
Latest "distribution/target/com4j-dist-*-all.zip"
)
gh release upload "${{ github.event.release.tag_name }}" $files --repo ${{ github.repository }} --clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,3 +10,8 @@
*.tli
vc90.idb
vc90.pdb
native/cmake-build*/

# bin/ holds the prebuilt com4j.dll (x86 and x64, Release and Debug) that the
# Java build packages by default and that JitPack relies on, since it can't
# build native/ itself - these are intentionally committed, do not ignore.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
[submodule "jnitl"]
path = jnitl
url = git://github.com/kohsuke/jnitl.git
url = https://github.com/kohsuke/jnitl.git
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions jitpack.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
jdk:
- openjdk17

# Skip building from source (this project needs a Windows/MSVC toolchain
# JitPack's Linux build servers don't have) and instead install the
# prebuilt artifacts already uploaded to the matching GitHub release by
# .github/workflows/release.yml.
install:
- OWNER=${GROUP#com.github.}
- REPO=${ARTIFACT}
- MODULE_GROUP=${GROUP}.${REPO}
- BASE_URL=https://github.com/${OWNER}/${REPO}/releases/download/${VERSION}

- curl -L -f -o com4j.jar ${BASE_URL}/com4j-${VERSION}.jar
- mvn install:install-file -Dfile=com4j.jar -DgroupId=${MODULE_GROUP} -DartifactId=com4j -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o tlbimp.jar ${BASE_URL}/tlbimp-${VERSION}.jar
- mvn install:install-file -Dfile=tlbimp.jar -DgroupId=${MODULE_GROUP} -DartifactId=tlbimp -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o maven-com4j-plugin.jar ${BASE_URL}/maven-com4j-plugin-${VERSION}.jar
- mvn install:install-file -Dfile=maven-com4j-plugin.jar -DgroupId=${MODULE_GROUP} -DartifactId=maven-com4j-plugin -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true
174 changes: 174 additions & 0 deletions native/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
cmake_minimum_required(VERSION 3.20)

cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

project(com4j_native LANGUAGES C CXX ASM_MASM)

if(NOT MSVC)
message(FATAL_ERROR "This project only builds with MSVC on Windows.")
endif()

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(COM4J_ARCH_DEFINE X86_WIN64)
set(COM4J_PLATFORM_DEFINE WIN64)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win64.asm64)
set(MIDL_ENV win64)
else()
set(COM4J_ARCH_DEFINE X86_WIN32)
set(COM4J_PLATFORM_DEFINE WIN32)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win32.asm)
set(MIDL_ENV win32)
endif()

set_source_files_properties(${LIBFFI_ASM} PROPERTIES LANGUAGE ASM_MASM)

# ---------------------------------------------------------------------------
# JNI
# ---------------------------------------------------------------------------
if(DEFINED JAVA_HOME)
set(ENV{JAVA_HOME} ${JAVA_HOME})
endif()
find_package(JNI REQUIRED)

# ---------------------------------------------------------------------------
# jnitl (git submodule, ../jnitl) - built as a small static lib.
# native/stdafx.h pulls in jnitl.h, which does:
# #pragma comment(lib, "jnitl.lib") (Release, static CRT)
# #pragma comment(lib, "jnitld.lib") (Debug, static CRT)
# so name the output to match and make sure it's on the link path.
# ---------------------------------------------------------------------------
set(JNITL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jnitl)

add_library(jnitl STATIC
${JNITL_DIR}/source/jnitl.cpp
${JNITL_DIR}/source/accessor.cpp
)
target_include_directories(jnitl PUBLIC ${JNITL_DIR}/include)
target_include_directories(jnitl PRIVATE ${JNI_INCLUDE_DIRS})
set_target_properties(jnitl PROPERTIES
OUTPUT_NAME "jnitl"
DEBUG_POSTFIX "d"
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/jnitl-lib
)
target_compile_definitions(jnitl PRIVATE WIN32 ${COM4J_PLATFORM_DEFINE} UNICODE _UNICODE)
# original vcproj built with TreatWChar_tAsBuiltInType="false" (/Zc:wchar_t-),
# which is why jni.h's `jchar` (unsigned short) and `wchar_t*`/BSTR interconvert
# implicitly all over this codebase.
target_compile_options(jnitl PRIVATE /Zc:wchar_t-)

# ---------------------------------------------------------------------------
# MIDL: com4j.idl -> com4j.tlb (+ generated .h/.c, unused but let midl emit
# its normal output). typelib.cpp does `#import "com4j.tlb" no_namespace`
# and com4j.rc embeds it as a TYPELIB resource, so both need the tlb's
# directory on their include search path.
# ---------------------------------------------------------------------------
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MIDL_SDK_ARCH x64)
else()
set(MIDL_SDK_ARCH x86)
endif()
file(GLOB MIDL_SDK_HINTS "C:/Program Files (x86)/Windows Kits/10/bin/10.0.*/${MIDL_SDK_ARCH}")
list(SORT MIDL_SDK_HINTS ORDER DESCENDING)
find_program(MIDL_EXECUTABLE midl.exe HINTS ${MIDL_SDK_HINTS} REQUIRED)

set(COM4J_TLB ${CMAKE_CURRENT_BINARY_DIR}/com4j.tlb)
set(COM4J_MIDL_H ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl.h)
set(COM4J_MIDL_C ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl_i.c)

add_custom_command(
OUTPUT ${COM4J_TLB}
COMMAND ${MIDL_EXECUTABLE}
/nologo
/env ${MIDL_ENV}
/tlb ${COM4J_TLB}
/h ${COM4J_MIDL_H}
/iid ${COM4J_MIDL_C}
/out ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running MIDL on com4j.idl"
VERBATIM
)
add_custom_target(com4j_idl DEPENDS ${COM4J_TLB})

# ---------------------------------------------------------------------------
# com4j.dll
# ---------------------------------------------------------------------------
set(COM4J_SOURCES
com4j.cpp
com4j_Win32Lock.cpp
error.cpp
eventReceiver.cpp
invoke.cpp
java_id.cpp
registry.cpp
safearray.cpp
stdafx.cpp
TestObject.cpp
toJava.cpp
typelib.cpp
variant.cpp
)

set(LIBFFI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libffi)
set(LIBFFI_SOURCES
${LIBFFI_DIR}/src/debug.c
${LIBFFI_DIR}/src/x86/ffi.c
${LIBFFI_DIR}/src/prep_cif.c
${LIBFFI_DIR}/src/types.c
${LIBFFI_ASM}
)

add_library(com4j SHARED
${COM4J_SOURCES}
${LIBFFI_SOURCES}
com4j.rc
)

add_dependencies(com4j com4j_idl)

target_include_directories(com4j PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${JNITL_DIR}/include
${LIBFFI_DIR}/include
${JNI_INCLUDE_DIRS}
)

target_compile_definitions(com4j PRIVATE
${COM4J_PLATFORM_DEFINE}
_WINDOWS
_USRDLL
COM4J_EXPORTS
${COM4J_ARCH_DEFINE}
UNICODE
_UNICODE
$<$<CONFIG:Debug>:_DEBUG>
$<$<NOT:$<CONFIG:Debug>>:NDEBUG>
)
target_compile_options(com4j PRIVATE $<$<COMPILE_LANGUAGE:CXX,C>:/Zc:wchar_t->)

# jnitl.h does `#pragma comment(lib, "jnitl.lib"/"jnitld.lib")` - that pragma-driven
# search needs the jnitl target's actual (per-config) output dir on the /LIBPATH,
# in addition to linking it directly as a CMake target dependency.
target_link_directories(com4j PRIVATE $<TARGET_FILE_DIR:jnitl>)
target_link_libraries(com4j PRIVATE jnitl ole32 oleaut32 uuid)

set(COM4J_LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/com4j.def")
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
# libffi's hand-written win32.asm predates SAFESEH exception-handler records;
# the modern linker refuses to produce a SAFESEH image without this.
set(COM4J_LINK_FLAGS "${COM4J_LINK_FLAGS} /SAFESEH:NO")
endif()
set_target_properties(com4j PROPERTIES
LINK_FLAGS "${COM4J_LINK_FLAGS}"
)

# make sure the rc compile step can find com4j.tlb (embedded via `1 TYPELIB "com4j.tlb"`)
set_source_files_properties(com4j.rc PROPERTIES
COMPILE_OPTIONS "/I${CMAKE_CURRENT_BINARY_DIR}"
)

# TestObject.cpp compiles to nothing outside _DEBUG - fine to always include.
13 changes: 10 additions & 3 deletions native/TestObject.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,8 +31,15 @@ STDMETHODIMP CTestObject::raw_TestVariant(VARIANT v1, VARIANT* v2, VARIANT* v3)

STDMETHODIMP CTestObject::raw_outByteBuf(BSTR bstrEncodedData, long* plSize, unsigned char** ppbData)
{
*plSize = 30;
*ppbData = (BYTE*)"Hello, World!";
static const char text[] = "Hello, World!";
const long len = sizeof(text)-1; // exclude the terminating '\0'

*ppbData = (BYTE*)CoTaskMemAlloc(len);
if(*ppbData==NULL)
return E_OUTOFMEMORY;

memcpy(*ppbData, text, len);
*plSize = len;

return S_OK;
}
Expand All@@ -45,4 +52,4 @@ STDMETHODIMP CTestObject::raw_testUI8Conv(VARIANT* in, VARIANT* out)
return ::VariantCopy(out,in);
}

#endif
#endif
29 changes: 0 additions & 29 deletions native/build.xml

This file was deleted.

Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/build.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
name: Build

on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

jobs:
build:
# windows-2022 ships Visual Studio 2022 (with the C++ ATL and MFC
# components the native build needs) and CMake preinstalled.
runs-on: windows-2022

steps:
- name: Check out repository (with submodules)
uses: actions/checkout@v7
with:
submodules: recursive

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Show build tool versions
shell: pwsh
run: |
cmake --version
java -version

# -DbuildNative=true forces a real rebuild instead of packaging the
# committed bin/ DLLs (JitPack's only option, since it can't run
# MSVC). package-only, run first, just to catch Release-only compile
# regressions before the Debug build below becomes the installed jar.
- name: Build native (Release)
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# TestObject (needed by tests) only compiles into Debug builds.
# install, not package, so "Run tests" below can resolve com4j from
# the local repo without rebuilding or needing -am.
- name: Build native (Debug)
shell: pwsh
run: mvn -B -pl "!test" install -DbuildNative=true -Dmode=Debug

# Registers com4j.dll as TestObject's COM server. Plain regsvr32
# works unelevated: GitHub's Windows runners run as Administrator
# with UAC disabled (actions/runner-images discussion #6557).
- name: Register COM test object
shell: pwsh
run: |
$dll = Resolve-Path "bin\x64\Debug\com4j.dll"
$p = Start-Process -FilePath "$env:SystemRoot\System32\regsvr32.exe" -ArgumentList "/s", "$dll" -Wait -PassThru -NoNewWindow
if ($p.ExitCode -ne 0) {
throw "regsvr32 failed with exit code $($p.ExitCode)"
}

- name: Run tests
shell: pwsh
run: mvn -B test -pl test
55 changes: 55 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
name: Release

on:
release:
types: [published]

permissions:
contents: write

jobs:
build-and-upload:
runs-on: windows-2022

steps:
- name: Check out repository (with submodules) at the release tag
uses: actions/checkout@v7
with:
submodules: recursive
ref: ${{ github.event.release.tag_name }}

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

# Sets the version to the release tag
- name: Set version to release tag
shell: pwsh
run: mvn -B versions:set "-DnewVersion=${{ github.event.release.tag_name }}" -DgenerateBackupPoms=false

# Rebuilds native/com4j.dll (Release, x86+x64) from source rather than
# trusting whatever's committed, so the uploaded jar always reflects
# the exact code at this tag.
- name: Build native (Release) and package
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# Uploads all modules' built artifacts as release assets
- name: Upload build artifacts to the release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
function Latest($pattern) {
(Get-ChildItem $pattern | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
}
$files = @(
Latest "runtime/target/com4j-*.jar"
Latest "tlbimp/target/tlbimp-*.jar"
Latest "maven-com4j-plugin/target/maven-com4j-plugin-*.jar"
Latest "distribution/target/com4j-dist-*-all.zip"
)
gh release upload "${{ github.event.release.tag_name }}" $files --repo ${{ github.repository }} --clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,3 +10,8 @@
*.tli
vc90.idb
vc90.pdb
native/cmake-build*/

# bin/ holds the prebuilt com4j.dll (x86 and x64, Release and Debug) that the
# Java build packages by default and that JitPack relies on, since it can't
# build native/ itself - these are intentionally committed, do not ignore.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
[submodule "jnitl"]
path = jnitl
url = git://github.com/kohsuke/jnitl.git
url = https://github.com/kohsuke/jnitl.git
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions jitpack.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
jdk:
- openjdk17

# Skip building from source (this project needs a Windows/MSVC toolchain
# JitPack's Linux build servers don't have) and instead install the
# prebuilt artifacts already uploaded to the matching GitHub release by
# .github/workflows/release.yml.
install:
- OWNER=${GROUP#com.github.}
- REPO=${ARTIFACT}
- MODULE_GROUP=${GROUP}.${REPO}
- BASE_URL=https://github.com/${OWNER}/${REPO}/releases/download/${VERSION}

- curl -L -f -o com4j.jar ${BASE_URL}/com4j-${VERSION}.jar
- mvn install:install-file -Dfile=com4j.jar -DgroupId=${MODULE_GROUP} -DartifactId=com4j -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o tlbimp.jar ${BASE_URL}/tlbimp-${VERSION}.jar
- mvn install:install-file -Dfile=tlbimp.jar -DgroupId=${MODULE_GROUP} -DartifactId=tlbimp -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o maven-com4j-plugin.jar ${BASE_URL}/maven-com4j-plugin-${VERSION}.jar
- mvn install:install-file -Dfile=maven-com4j-plugin.jar -DgroupId=${MODULE_GROUP} -DartifactId=maven-com4j-plugin -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true
174 changes: 174 additions & 0 deletions native/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
cmake_minimum_required(VERSION 3.20)

cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

project(com4j_native LANGUAGES C CXX ASM_MASM)

if(NOT MSVC)
message(FATAL_ERROR "This project only builds with MSVC on Windows.")
endif()

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(COM4J_ARCH_DEFINE X86_WIN64)
set(COM4J_PLATFORM_DEFINE WIN64)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win64.asm64)
set(MIDL_ENV win64)
else()
set(COM4J_ARCH_DEFINE X86_WIN32)
set(COM4J_PLATFORM_DEFINE WIN32)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win32.asm)
set(MIDL_ENV win32)
endif()

set_source_files_properties(${LIBFFI_ASM} PROPERTIES LANGUAGE ASM_MASM)

# ---------------------------------------------------------------------------
# JNI
# ---------------------------------------------------------------------------
if(DEFINED JAVA_HOME)
set(ENV{JAVA_HOME} ${JAVA_HOME})
endif()
find_package(JNI REQUIRED)

# ---------------------------------------------------------------------------
# jnitl (git submodule, ../jnitl) - built as a small static lib.
# native/stdafx.h pulls in jnitl.h, which does:
# #pragma comment(lib, "jnitl.lib") (Release, static CRT)
# #pragma comment(lib, "jnitld.lib") (Debug, static CRT)
# so name the output to match and make sure it's on the link path.
# ---------------------------------------------------------------------------
set(JNITL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jnitl)

add_library(jnitl STATIC
${JNITL_DIR}/source/jnitl.cpp
${JNITL_DIR}/source/accessor.cpp
)
target_include_directories(jnitl PUBLIC ${JNITL_DIR}/include)
target_include_directories(jnitl PRIVATE ${JNI_INCLUDE_DIRS})
set_target_properties(jnitl PROPERTIES
OUTPUT_NAME "jnitl"
DEBUG_POSTFIX "d"
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/jnitl-lib
)
target_compile_definitions(jnitl PRIVATE WIN32 ${COM4J_PLATFORM_DEFINE} UNICODE _UNICODE)
# original vcproj built with TreatWChar_tAsBuiltInType="false" (/Zc:wchar_t-),
# which is why jni.h's `jchar` (unsigned short) and `wchar_t*`/BSTR interconvert
# implicitly all over this codebase.
target_compile_options(jnitl PRIVATE /Zc:wchar_t-)

# ---------------------------------------------------------------------------
# MIDL: com4j.idl -> com4j.tlb (+ generated .h/.c, unused but let midl emit
# its normal output). typelib.cpp does `#import "com4j.tlb" no_namespace`
# and com4j.rc embeds it as a TYPELIB resource, so both need the tlb's
# directory on their include search path.
# ---------------------------------------------------------------------------
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MIDL_SDK_ARCH x64)
else()
set(MIDL_SDK_ARCH x86)
endif()
file(GLOB MIDL_SDK_HINTS "C:/Program Files (x86)/Windows Kits/10/bin/10.0.*/${MIDL_SDK_ARCH}")
list(SORT MIDL_SDK_HINTS ORDER DESCENDING)
find_program(MIDL_EXECUTABLE midl.exe HINTS ${MIDL_SDK_HINTS} REQUIRED)

set(COM4J_TLB ${CMAKE_CURRENT_BINARY_DIR}/com4j.tlb)
set(COM4J_MIDL_H ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl.h)
set(COM4J_MIDL_C ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl_i.c)

add_custom_command(
OUTPUT ${COM4J_TLB}
COMMAND ${MIDL_EXECUTABLE}
/nologo
/env ${MIDL_ENV}
/tlb ${COM4J_TLB}
/h ${COM4J_MIDL_H}
/iid ${COM4J_MIDL_C}
/out ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running MIDL on com4j.idl"
VERBATIM
)
add_custom_target(com4j_idl DEPENDS ${COM4J_TLB})

# ---------------------------------------------------------------------------
# com4j.dll
# ---------------------------------------------------------------------------
set(COM4J_SOURCES
com4j.cpp
com4j_Win32Lock.cpp
error.cpp
eventReceiver.cpp
invoke.cpp
java_id.cpp
registry.cpp
safearray.cpp
stdafx.cpp
TestObject.cpp
toJava.cpp
typelib.cpp
variant.cpp
)

set(LIBFFI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libffi)
set(LIBFFI_SOURCES
${LIBFFI_DIR}/src/debug.c
${LIBFFI_DIR}/src/x86/ffi.c
${LIBFFI_DIR}/src/prep_cif.c
${LIBFFI_DIR}/src/types.c
${LIBFFI_ASM}
)

add_library(com4j SHARED
${COM4J_SOURCES}
${LIBFFI_SOURCES}
com4j.rc
)

add_dependencies(com4j com4j_idl)

target_include_directories(com4j PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${JNITL_DIR}/include
${LIBFFI_DIR}/include
${JNI_INCLUDE_DIRS}
)

target_compile_definitions(com4j PRIVATE
${COM4J_PLATFORM_DEFINE}
_WINDOWS
_USRDLL
COM4J_EXPORTS
${COM4J_ARCH_DEFINE}
UNICODE
_UNICODE
$<$<CONFIG:Debug>:_DEBUG>
$<$<NOT:$<CONFIG:Debug>>:NDEBUG>
)
target_compile_options(com4j PRIVATE $<$<COMPILE_LANGUAGE:CXX,C>:/Zc:wchar_t->)

# jnitl.h does `#pragma comment(lib, "jnitl.lib"/"jnitld.lib")` - that pragma-driven
# search needs the jnitl target's actual (per-config) output dir on the /LIBPATH,
# in addition to linking it directly as a CMake target dependency.
target_link_directories(com4j PRIVATE $<TARGET_FILE_DIR:jnitl>)
target_link_libraries(com4j PRIVATE jnitl ole32 oleaut32 uuid)

set(COM4J_LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/com4j.def")
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
# libffi's hand-written win32.asm predates SAFESEH exception-handler records;
# the modern linker refuses to produce a SAFESEH image without this.
set(COM4J_LINK_FLAGS "${COM4J_LINK_FLAGS} /SAFESEH:NO")
endif()
set_target_properties(com4j PROPERTIES
LINK_FLAGS "${COM4J_LINK_FLAGS}"
)

# make sure the rc compile step can find com4j.tlb (embedded via `1 TYPELIB "com4j.tlb"`)
set_source_files_properties(com4j.rc PROPERTIES
COMPILE_OPTIONS "/I${CMAKE_CURRENT_BINARY_DIR}"
)

# TestObject.cpp compiles to nothing outside _DEBUG - fine to always include.
13 changes: 10 additions & 3 deletions native/TestObject.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,8 +31,15 @@ STDMETHODIMP CTestObject::raw_TestVariant(VARIANT v1, VARIANT* v2, VARIANT* v3)

STDMETHODIMP CTestObject::raw_outByteBuf(BSTR bstrEncodedData, long* plSize, unsigned char** ppbData)
{
*plSize = 30;
*ppbData = (BYTE*)"Hello, World!";
static const char text[] = "Hello, World!";
const long len = sizeof(text)-1; // exclude the terminating '\0'

*ppbData = (BYTE*)CoTaskMemAlloc(len);
if(*ppbData==NULL)
return E_OUTOFMEMORY;

memcpy(*ppbData, text, len);
*plSize = len;

return S_OK;
}
Expand All@@ -45,4 +52,4 @@ STDMETHODIMP CTestObject::raw_testUI8Conv(VARIANT* in, VARIANT* out)
return ::VariantCopy(out,in);
}

#endif
#endif
29 changes: 0 additions & 29 deletions native/build.xml

This file was deleted.

Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/build.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
name: Build

on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

jobs:
build:
# windows-2022 ships Visual Studio 2022 (with the C++ ATL and MFC
# components the native build needs) and CMake preinstalled.
runs-on: windows-2022

steps:
- name: Check out repository (with submodules)
uses: actions/checkout@v7
with:
submodules: recursive

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Show build tool versions
shell: pwsh
run: |
cmake --version
java -version

# -DbuildNative=true forces a real rebuild instead of packaging the
# committed bin/ DLLs (JitPack's only option, since it can't run
# MSVC). package-only, run first, just to catch Release-only compile
# regressions before the Debug build below becomes the installed jar.
- name: Build native (Release)
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# TestObject (needed by tests) only compiles into Debug builds.
# install, not package, so "Run tests" below can resolve com4j from
# the local repo without rebuilding or needing -am.
- name: Build native (Debug)
shell: pwsh
run: mvn -B -pl "!test" install -DbuildNative=true -Dmode=Debug

# Registers com4j.dll as TestObject's COM server. Plain regsvr32
# works unelevated: GitHub's Windows runners run as Administrator
# with UAC disabled (actions/runner-images discussion #6557).
- name: Register COM test object
shell: pwsh
run: |
$dll = Resolve-Path "bin\x64\Debug\com4j.dll"
$p = Start-Process -FilePath "$env:SystemRoot\System32\regsvr32.exe" -ArgumentList "/s", "$dll" -Wait -PassThru -NoNewWindow
if ($p.ExitCode -ne 0) {
throw "regsvr32 failed with exit code $($p.ExitCode)"
}

- name: Run tests
shell: pwsh
run: mvn -B test -pl test
55 changes: 55 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
name: Release

on:
release:
types: [published]

permissions:
contents: write

jobs:
build-and-upload:
runs-on: windows-2022

steps:
- name: Check out repository (with submodules) at the release tag
uses: actions/checkout@v7
with:
submodules: recursive
ref: ${{ github.event.release.tag_name }}

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

# Sets the version to the release tag
- name: Set version to release tag
shell: pwsh
run: mvn -B versions:set "-DnewVersion=${{ github.event.release.tag_name }}" -DgenerateBackupPoms=false

# Rebuilds native/com4j.dll (Release, x86+x64) from source rather than
# trusting whatever's committed, so the uploaded jar always reflects
# the exact code at this tag.
- name: Build native (Release) and package
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# Uploads all modules' built artifacts as release assets
- name: Upload build artifacts to the release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
function Latest($pattern) {
(Get-ChildItem $pattern | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
}
$files = @(
Latest "runtime/target/com4j-*.jar"
Latest "tlbimp/target/tlbimp-*.jar"
Latest "maven-com4j-plugin/target/maven-com4j-plugin-*.jar"
Latest "distribution/target/com4j-dist-*-all.zip"
)
gh release upload "${{ github.event.release.tag_name }}" $files --repo ${{ github.repository }} --clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,3 +10,8 @@
*.tli
vc90.idb
vc90.pdb
native/cmake-build*/

# bin/ holds the prebuilt com4j.dll (x86 and x64, Release and Debug) that the
# Java build packages by default and that JitPack relies on, since it can't
# build native/ itself - these are intentionally committed, do not ignore.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
[submodule "jnitl"]
path = jnitl
url = git://github.com/kohsuke/jnitl.git
url = https://github.com/kohsuke/jnitl.git
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions jitpack.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
jdk:
- openjdk17

# Skip building from source (this project needs a Windows/MSVC toolchain
# JitPack's Linux build servers don't have) and instead install the
# prebuilt artifacts already uploaded to the matching GitHub release by
# .github/workflows/release.yml.
install:
- OWNER=${GROUP#com.github.}
- REPO=${ARTIFACT}
- MODULE_GROUP=${GROUP}.${REPO}
- BASE_URL=https://github.com/${OWNER}/${REPO}/releases/download/${VERSION}

- curl -L -f -o com4j.jar ${BASE_URL}/com4j-${VERSION}.jar
- mvn install:install-file -Dfile=com4j.jar -DgroupId=${MODULE_GROUP} -DartifactId=com4j -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o tlbimp.jar ${BASE_URL}/tlbimp-${VERSION}.jar
- mvn install:install-file -Dfile=tlbimp.jar -DgroupId=${MODULE_GROUP} -DartifactId=tlbimp -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o maven-com4j-plugin.jar ${BASE_URL}/maven-com4j-plugin-${VERSION}.jar
- mvn install:install-file -Dfile=maven-com4j-plugin.jar -DgroupId=${MODULE_GROUP} -DartifactId=maven-com4j-plugin -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true
174 changes: 174 additions & 0 deletions native/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
cmake_minimum_required(VERSION 3.20)

cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

project(com4j_native LANGUAGES C CXX ASM_MASM)

if(NOT MSVC)
message(FATAL_ERROR "This project only builds with MSVC on Windows.")
endif()

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(COM4J_ARCH_DEFINE X86_WIN64)
set(COM4J_PLATFORM_DEFINE WIN64)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win64.asm64)
set(MIDL_ENV win64)
else()
set(COM4J_ARCH_DEFINE X86_WIN32)
set(COM4J_PLATFORM_DEFINE WIN32)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win32.asm)
set(MIDL_ENV win32)
endif()

set_source_files_properties(${LIBFFI_ASM} PROPERTIES LANGUAGE ASM_MASM)

# ---------------------------------------------------------------------------
# JNI
# ---------------------------------------------------------------------------
if(DEFINED JAVA_HOME)
set(ENV{JAVA_HOME} ${JAVA_HOME})
endif()
find_package(JNI REQUIRED)

# ---------------------------------------------------------------------------
# jnitl (git submodule, ../jnitl) - built as a small static lib.
# native/stdafx.h pulls in jnitl.h, which does:
# #pragma comment(lib, "jnitl.lib") (Release, static CRT)
# #pragma comment(lib, "jnitld.lib") (Debug, static CRT)
# so name the output to match and make sure it's on the link path.
# ---------------------------------------------------------------------------
set(JNITL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jnitl)

add_library(jnitl STATIC
${JNITL_DIR}/source/jnitl.cpp
${JNITL_DIR}/source/accessor.cpp
)
target_include_directories(jnitl PUBLIC ${JNITL_DIR}/include)
target_include_directories(jnitl PRIVATE ${JNI_INCLUDE_DIRS})
set_target_properties(jnitl PROPERTIES
OUTPUT_NAME "jnitl"
DEBUG_POSTFIX "d"
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/jnitl-lib
)
target_compile_definitions(jnitl PRIVATE WIN32 ${COM4J_PLATFORM_DEFINE} UNICODE _UNICODE)
# original vcproj built with TreatWChar_tAsBuiltInType="false" (/Zc:wchar_t-),
# which is why jni.h's `jchar` (unsigned short) and `wchar_t*`/BSTR interconvert
# implicitly all over this codebase.
target_compile_options(jnitl PRIVATE /Zc:wchar_t-)

# ---------------------------------------------------------------------------
# MIDL: com4j.idl -> com4j.tlb (+ generated .h/.c, unused but let midl emit
# its normal output). typelib.cpp does `#import "com4j.tlb" no_namespace`
# and com4j.rc embeds it as a TYPELIB resource, so both need the tlb's
# directory on their include search path.
# ---------------------------------------------------------------------------
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MIDL_SDK_ARCH x64)
else()
set(MIDL_SDK_ARCH x86)
endif()
file(GLOB MIDL_SDK_HINTS "C:/Program Files (x86)/Windows Kits/10/bin/10.0.*/${MIDL_SDK_ARCH}")
list(SORT MIDL_SDK_HINTS ORDER DESCENDING)
find_program(MIDL_EXECUTABLE midl.exe HINTS ${MIDL_SDK_HINTS} REQUIRED)

set(COM4J_TLB ${CMAKE_CURRENT_BINARY_DIR}/com4j.tlb)
set(COM4J_MIDL_H ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl.h)
set(COM4J_MIDL_C ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl_i.c)

add_custom_command(
OUTPUT ${COM4J_TLB}
COMMAND ${MIDL_EXECUTABLE}
/nologo
/env ${MIDL_ENV}
/tlb ${COM4J_TLB}
/h ${COM4J_MIDL_H}
/iid ${COM4J_MIDL_C}
/out ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running MIDL on com4j.idl"
VERBATIM
)
add_custom_target(com4j_idl DEPENDS ${COM4J_TLB})

# ---------------------------------------------------------------------------
# com4j.dll
# ---------------------------------------------------------------------------
set(COM4J_SOURCES
com4j.cpp
com4j_Win32Lock.cpp
error.cpp
eventReceiver.cpp
invoke.cpp
java_id.cpp
registry.cpp
safearray.cpp
stdafx.cpp
TestObject.cpp
toJava.cpp
typelib.cpp
variant.cpp
)

set(LIBFFI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libffi)
set(LIBFFI_SOURCES
${LIBFFI_DIR}/src/debug.c
${LIBFFI_DIR}/src/x86/ffi.c
${LIBFFI_DIR}/src/prep_cif.c
${LIBFFI_DIR}/src/types.c
${LIBFFI_ASM}
)

add_library(com4j SHARED
${COM4J_SOURCES}
${LIBFFI_SOURCES}
com4j.rc
)

add_dependencies(com4j com4j_idl)

target_include_directories(com4j PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${JNITL_DIR}/include
${LIBFFI_DIR}/include
${JNI_INCLUDE_DIRS}
)

target_compile_definitions(com4j PRIVATE
${COM4J_PLATFORM_DEFINE}
_WINDOWS
_USRDLL
COM4J_EXPORTS
${COM4J_ARCH_DEFINE}
UNICODE
_UNICODE
$<$<CONFIG:Debug>:_DEBUG>
$<$<NOT:$<CONFIG:Debug>>:NDEBUG>
)
target_compile_options(com4j PRIVATE $<$<COMPILE_LANGUAGE:CXX,C>:/Zc:wchar_t->)

# jnitl.h does `#pragma comment(lib, "jnitl.lib"/"jnitld.lib")` - that pragma-driven
# search needs the jnitl target's actual (per-config) output dir on the /LIBPATH,
# in addition to linking it directly as a CMake target dependency.
target_link_directories(com4j PRIVATE $<TARGET_FILE_DIR:jnitl>)
target_link_libraries(com4j PRIVATE jnitl ole32 oleaut32 uuid)

set(COM4J_LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/com4j.def")
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
# libffi's hand-written win32.asm predates SAFESEH exception-handler records;
# the modern linker refuses to produce a SAFESEH image without this.
set(COM4J_LINK_FLAGS "${COM4J_LINK_FLAGS} /SAFESEH:NO")
endif()
set_target_properties(com4j PROPERTIES
LINK_FLAGS "${COM4J_LINK_FLAGS}"
)

# make sure the rc compile step can find com4j.tlb (embedded via `1 TYPELIB "com4j.tlb"`)
set_source_files_properties(com4j.rc PROPERTIES
COMPILE_OPTIONS "/I${CMAKE_CURRENT_BINARY_DIR}"
)

# TestObject.cpp compiles to nothing outside _DEBUG - fine to always include.
13 changes: 10 additions & 3 deletions native/TestObject.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,8 +31,15 @@ STDMETHODIMP CTestObject::raw_TestVariant(VARIANT v1, VARIANT* v2, VARIANT* v3)

STDMETHODIMP CTestObject::raw_outByteBuf(BSTR bstrEncodedData, long* plSize, unsigned char** ppbData)
{
*plSize = 30;
*ppbData = (BYTE*)"Hello, World!";
static const char text[] = "Hello, World!";
const long len = sizeof(text)-1; // exclude the terminating '\0'

*ppbData = (BYTE*)CoTaskMemAlloc(len);
if(*ppbData==NULL)
return E_OUTOFMEMORY;

memcpy(*ppbData, text, len);
*plSize = len;

return S_OK;
}
Expand All@@ -45,4 +52,4 @@ STDMETHODIMP CTestObject::raw_testUI8Conv(VARIANT* in, VARIANT* out)
return ::VariantCopy(out,in);
}

#endif
#endif
29 changes: 0 additions & 29 deletions native/build.xml

This file was deleted.

Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/build.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
name: Build

on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

jobs:
build:
# windows-2022 ships Visual Studio 2022 (with the C++ ATL and MFC
# components the native build needs) and CMake preinstalled.
runs-on: windows-2022

steps:
- name: Check out repository (with submodules)
uses: actions/checkout@v7
with:
submodules: recursive

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Show build tool versions
shell: pwsh
run: |
cmake --version
java -version

# -DbuildNative=true forces a real rebuild instead of packaging the
# committed bin/ DLLs (JitPack's only option, since it can't run
# MSVC). package-only, run first, just to catch Release-only compile
# regressions before the Debug build below becomes the installed jar.
- name: Build native (Release)
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# TestObject (needed by tests) only compiles into Debug builds.
# install, not package, so "Run tests" below can resolve com4j from
# the local repo without rebuilding or needing -am.
- name: Build native (Debug)
shell: pwsh
run: mvn -B -pl "!test" install -DbuildNative=true -Dmode=Debug

# Registers com4j.dll as TestObject's COM server. Plain regsvr32
# works unelevated: GitHub's Windows runners run as Administrator
# with UAC disabled (actions/runner-images discussion #6557).
- name: Register COM test object
shell: pwsh
run: |
$dll = Resolve-Path "bin\x64\Debug\com4j.dll"
$p = Start-Process -FilePath "$env:SystemRoot\System32\regsvr32.exe" -ArgumentList "/s", "$dll" -Wait -PassThru -NoNewWindow
if ($p.ExitCode -ne 0) {
throw "regsvr32 failed with exit code $($p.ExitCode)"
}

- name: Run tests
shell: pwsh
run: mvn -B test -pl test
55 changes: 55 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
name: Release

on:
release:
types: [published]

permissions:
contents: write

jobs:
build-and-upload:
runs-on: windows-2022

steps:
- name: Check out repository (with submodules) at the release tag
uses: actions/checkout@v7
with:
submodules: recursive
ref: ${{ github.event.release.tag_name }}

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

# Sets the version to the release tag
- name: Set version to release tag
shell: pwsh
run: mvn -B versions:set "-DnewVersion=${{ github.event.release.tag_name }}" -DgenerateBackupPoms=false

# Rebuilds native/com4j.dll (Release, x86+x64) from source rather than
# trusting whatever's committed, so the uploaded jar always reflects
# the exact code at this tag.
- name: Build native (Release) and package
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# Uploads all modules' built artifacts as release assets
- name: Upload build artifacts to the release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
function Latest($pattern) {
(Get-ChildItem $pattern | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
}
$files = @(
Latest "runtime/target/com4j-*.jar"
Latest "tlbimp/target/tlbimp-*.jar"
Latest "maven-com4j-plugin/target/maven-com4j-plugin-*.jar"
Latest "distribution/target/com4j-dist-*-all.zip"
)
gh release upload "${{ github.event.release.tag_name }}" $files --repo ${{ github.repository }} --clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,3 +10,8 @@
*.tli
vc90.idb
vc90.pdb
native/cmake-build*/

# bin/ holds the prebuilt com4j.dll (x86 and x64, Release and Debug) that the
# Java build packages by default and that JitPack relies on, since it can't
# build native/ itself - these are intentionally committed, do not ignore.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
[submodule "jnitl"]
path = jnitl
url = git://github.com/kohsuke/jnitl.git
url = https://github.com/kohsuke/jnitl.git
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions jitpack.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
jdk:
- openjdk17

# Skip building from source (this project needs a Windows/MSVC toolchain
# JitPack's Linux build servers don't have) and instead install the
# prebuilt artifacts already uploaded to the matching GitHub release by
# .github/workflows/release.yml.
install:
- OWNER=${GROUP#com.github.}
- REPO=${ARTIFACT}
- MODULE_GROUP=${GROUP}.${REPO}
- BASE_URL=https://github.com/${OWNER}/${REPO}/releases/download/${VERSION}

- curl -L -f -o com4j.jar ${BASE_URL}/com4j-${VERSION}.jar
- mvn install:install-file -Dfile=com4j.jar -DgroupId=${MODULE_GROUP} -DartifactId=com4j -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o tlbimp.jar ${BASE_URL}/tlbimp-${VERSION}.jar
- mvn install:install-file -Dfile=tlbimp.jar -DgroupId=${MODULE_GROUP} -DartifactId=tlbimp -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o maven-com4j-plugin.jar ${BASE_URL}/maven-com4j-plugin-${VERSION}.jar
- mvn install:install-file -Dfile=maven-com4j-plugin.jar -DgroupId=${MODULE_GROUP} -DartifactId=maven-com4j-plugin -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true
174 changes: 174 additions & 0 deletions native/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
cmake_minimum_required(VERSION 3.20)

cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

project(com4j_native LANGUAGES C CXX ASM_MASM)

if(NOT MSVC)
message(FATAL_ERROR "This project only builds with MSVC on Windows.")
endif()

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(COM4J_ARCH_DEFINE X86_WIN64)
set(COM4J_PLATFORM_DEFINE WIN64)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win64.asm64)
set(MIDL_ENV win64)
else()
set(COM4J_ARCH_DEFINE X86_WIN32)
set(COM4J_PLATFORM_DEFINE WIN32)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win32.asm)
set(MIDL_ENV win32)
endif()

set_source_files_properties(${LIBFFI_ASM} PROPERTIES LANGUAGE ASM_MASM)

# ---------------------------------------------------------------------------
# JNI
# ---------------------------------------------------------------------------
if(DEFINED JAVA_HOME)
set(ENV{JAVA_HOME} ${JAVA_HOME})
endif()
find_package(JNI REQUIRED)

# ---------------------------------------------------------------------------
# jnitl (git submodule, ../jnitl) - built as a small static lib.
# native/stdafx.h pulls in jnitl.h, which does:
# #pragma comment(lib, "jnitl.lib") (Release, static CRT)
# #pragma comment(lib, "jnitld.lib") (Debug, static CRT)
# so name the output to match and make sure it's on the link path.
# ---------------------------------------------------------------------------
set(JNITL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jnitl)

add_library(jnitl STATIC
${JNITL_DIR}/source/jnitl.cpp
${JNITL_DIR}/source/accessor.cpp
)
target_include_directories(jnitl PUBLIC ${JNITL_DIR}/include)
target_include_directories(jnitl PRIVATE ${JNI_INCLUDE_DIRS})
set_target_properties(jnitl PROPERTIES
OUTPUT_NAME "jnitl"
DEBUG_POSTFIX "d"
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/jnitl-lib
)
target_compile_definitions(jnitl PRIVATE WIN32 ${COM4J_PLATFORM_DEFINE} UNICODE _UNICODE)
# original vcproj built with TreatWChar_tAsBuiltInType="false" (/Zc:wchar_t-),
# which is why jni.h's `jchar` (unsigned short) and `wchar_t*`/BSTR interconvert
# implicitly all over this codebase.
target_compile_options(jnitl PRIVATE /Zc:wchar_t-)

# ---------------------------------------------------------------------------
# MIDL: com4j.idl -> com4j.tlb (+ generated .h/.c, unused but let midl emit
# its normal output). typelib.cpp does `#import "com4j.tlb" no_namespace`
# and com4j.rc embeds it as a TYPELIB resource, so both need the tlb's
# directory on their include search path.
# ---------------------------------------------------------------------------
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MIDL_SDK_ARCH x64)
else()
set(MIDL_SDK_ARCH x86)
endif()
file(GLOB MIDL_SDK_HINTS "C:/Program Files (x86)/Windows Kits/10/bin/10.0.*/${MIDL_SDK_ARCH}")
list(SORT MIDL_SDK_HINTS ORDER DESCENDING)
find_program(MIDL_EXECUTABLE midl.exe HINTS ${MIDL_SDK_HINTS} REQUIRED)

set(COM4J_TLB ${CMAKE_CURRENT_BINARY_DIR}/com4j.tlb)
set(COM4J_MIDL_H ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl.h)
set(COM4J_MIDL_C ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl_i.c)

add_custom_command(
OUTPUT ${COM4J_TLB}
COMMAND ${MIDL_EXECUTABLE}
/nologo
/env ${MIDL_ENV}
/tlb ${COM4J_TLB}
/h ${COM4J_MIDL_H}
/iid ${COM4J_MIDL_C}
/out ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running MIDL on com4j.idl"
VERBATIM
)
add_custom_target(com4j_idl DEPENDS ${COM4J_TLB})

# ---------------------------------------------------------------------------
# com4j.dll
# ---------------------------------------------------------------------------
set(COM4J_SOURCES
com4j.cpp
com4j_Win32Lock.cpp
error.cpp
eventReceiver.cpp
invoke.cpp
java_id.cpp
registry.cpp
safearray.cpp
stdafx.cpp
TestObject.cpp
toJava.cpp
typelib.cpp
variant.cpp
)

set(LIBFFI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libffi)
set(LIBFFI_SOURCES
${LIBFFI_DIR}/src/debug.c
${LIBFFI_DIR}/src/x86/ffi.c
${LIBFFI_DIR}/src/prep_cif.c
${LIBFFI_DIR}/src/types.c
${LIBFFI_ASM}
)

add_library(com4j SHARED
${COM4J_SOURCES}
${LIBFFI_SOURCES}
com4j.rc
)

add_dependencies(com4j com4j_idl)

target_include_directories(com4j PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${JNITL_DIR}/include
${LIBFFI_DIR}/include
${JNI_INCLUDE_DIRS}
)

target_compile_definitions(com4j PRIVATE
${COM4J_PLATFORM_DEFINE}
_WINDOWS
_USRDLL
COM4J_EXPORTS
${COM4J_ARCH_DEFINE}
UNICODE
_UNICODE
$<$<CONFIG:Debug>:_DEBUG>
$<$<NOT:$<CONFIG:Debug>>:NDEBUG>
)
target_compile_options(com4j PRIVATE $<$<COMPILE_LANGUAGE:CXX,C>:/Zc:wchar_t->)

# jnitl.h does `#pragma comment(lib, "jnitl.lib"/"jnitld.lib")` - that pragma-driven
# search needs the jnitl target's actual (per-config) output dir on the /LIBPATH,
# in addition to linking it directly as a CMake target dependency.
target_link_directories(com4j PRIVATE $<TARGET_FILE_DIR:jnitl>)
target_link_libraries(com4j PRIVATE jnitl ole32 oleaut32 uuid)

set(COM4J_LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/com4j.def")
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
# libffi's hand-written win32.asm predates SAFESEH exception-handler records;
# the modern linker refuses to produce a SAFESEH image without this.
set(COM4J_LINK_FLAGS "${COM4J_LINK_FLAGS} /SAFESEH:NO")
endif()
set_target_properties(com4j PROPERTIES
LINK_FLAGS "${COM4J_LINK_FLAGS}"
)

# make sure the rc compile step can find com4j.tlb (embedded via `1 TYPELIB "com4j.tlb"`)
set_source_files_properties(com4j.rc PROPERTIES
COMPILE_OPTIONS "/I${CMAKE_CURRENT_BINARY_DIR}"
)

# TestObject.cpp compiles to nothing outside _DEBUG - fine to always include.
13 changes: 10 additions & 3 deletions native/TestObject.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,8 +31,15 @@ STDMETHODIMP CTestObject::raw_TestVariant(VARIANT v1, VARIANT* v2, VARIANT* v3)

STDMETHODIMP CTestObject::raw_outByteBuf(BSTR bstrEncodedData, long* plSize, unsigned char** ppbData)
{
*plSize = 30;
*ppbData = (BYTE*)"Hello, World!";
static const char text[] = "Hello, World!";
const long len = sizeof(text)-1; // exclude the terminating '\0'

*ppbData = (BYTE*)CoTaskMemAlloc(len);
if(*ppbData==NULL)
return E_OUTOFMEMORY;

memcpy(*ppbData, text, len);
*plSize = len;

return S_OK;
}
Expand All@@ -45,4 +52,4 @@ STDMETHODIMP CTestObject::raw_testUI8Conv(VARIANT* in, VARIANT* out)
return ::VariantCopy(out,in);
}

#endif
#endif
29 changes: 0 additions & 29 deletions native/build.xml

This file was deleted.

Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/build.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
name: Build

on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

jobs:
build:
# windows-2022 ships Visual Studio 2022 (with the C++ ATL and MFC
# components the native build needs) and CMake preinstalled.
runs-on: windows-2022

steps:
- name: Check out repository (with submodules)
uses: actions/checkout@v7
with:
submodules: recursive

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Show build tool versions
shell: pwsh
run: |
cmake --version
java -version

# -DbuildNative=true forces a real rebuild instead of packaging the
# committed bin/ DLLs (JitPack's only option, since it can't run
# MSVC). package-only, run first, just to catch Release-only compile
# regressions before the Debug build below becomes the installed jar.
- name: Build native (Release)
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# TestObject (needed by tests) only compiles into Debug builds.
# install, not package, so "Run tests" below can resolve com4j from
# the local repo without rebuilding or needing -am.
- name: Build native (Debug)
shell: pwsh
run: mvn -B -pl "!test" install -DbuildNative=true -Dmode=Debug

# Registers com4j.dll as TestObject's COM server. Plain regsvr32
# works unelevated: GitHub's Windows runners run as Administrator
# with UAC disabled (actions/runner-images discussion #6557).
- name: Register COM test object
shell: pwsh
run: |
$dll = Resolve-Path "bin\x64\Debug\com4j.dll"
$p = Start-Process -FilePath "$env:SystemRoot\System32\regsvr32.exe" -ArgumentList "/s", "$dll" -Wait -PassThru -NoNewWindow
if ($p.ExitCode -ne 0) {
throw "regsvr32 failed with exit code $($p.ExitCode)"
}

- name: Run tests
shell: pwsh
run: mvn -B test -pl test
55 changes: 55 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
name: Release

on:
release:
types: [published]

permissions:
contents: write

jobs:
build-and-upload:
runs-on: windows-2022

steps:
- name: Check out repository (with submodules) at the release tag
uses: actions/checkout@v7
with:
submodules: recursive
ref: ${{ github.event.release.tag_name }}

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

# Sets the version to the release tag
- name: Set version to release tag
shell: pwsh
run: mvn -B versions:set "-DnewVersion=${{ github.event.release.tag_name }}" -DgenerateBackupPoms=false

# Rebuilds native/com4j.dll (Release, x86+x64) from source rather than
# trusting whatever's committed, so the uploaded jar always reflects
# the exact code at this tag.
- name: Build native (Release) and package
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# Uploads all modules' built artifacts as release assets
- name: Upload build artifacts to the release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
function Latest($pattern) {
(Get-ChildItem $pattern | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
}
$files = @(
Latest "runtime/target/com4j-*.jar"
Latest "tlbimp/target/tlbimp-*.jar"
Latest "maven-com4j-plugin/target/maven-com4j-plugin-*.jar"
Latest "distribution/target/com4j-dist-*-all.zip"
)
gh release upload "${{ github.event.release.tag_name }}" $files --repo ${{ github.repository }} --clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,3 +10,8 @@
*.tli
vc90.idb
vc90.pdb
native/cmake-build*/

# bin/ holds the prebuilt com4j.dll (x86 and x64, Release and Debug) that the
# Java build packages by default and that JitPack relies on, since it can't
# build native/ itself - these are intentionally committed, do not ignore.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
[submodule "jnitl"]
path = jnitl
url = git://github.com/kohsuke/jnitl.git
url = https://github.com/kohsuke/jnitl.git
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions jitpack.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
jdk:
- openjdk17

# Skip building from source (this project needs a Windows/MSVC toolchain
# JitPack's Linux build servers don't have) and instead install the
# prebuilt artifacts already uploaded to the matching GitHub release by
# .github/workflows/release.yml.
install:
- OWNER=${GROUP#com.github.}
- REPO=${ARTIFACT}
- MODULE_GROUP=${GROUP}.${REPO}
- BASE_URL=https://github.com/${OWNER}/${REPO}/releases/download/${VERSION}

- curl -L -f -o com4j.jar ${BASE_URL}/com4j-${VERSION}.jar
- mvn install:install-file -Dfile=com4j.jar -DgroupId=${MODULE_GROUP} -DartifactId=com4j -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o tlbimp.jar ${BASE_URL}/tlbimp-${VERSION}.jar
- mvn install:install-file -Dfile=tlbimp.jar -DgroupId=${MODULE_GROUP} -DartifactId=tlbimp -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o maven-com4j-plugin.jar ${BASE_URL}/maven-com4j-plugin-${VERSION}.jar
- mvn install:install-file -Dfile=maven-com4j-plugin.jar -DgroupId=${MODULE_GROUP} -DartifactId=maven-com4j-plugin -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true
174 changes: 174 additions & 0 deletions native/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
cmake_minimum_required(VERSION 3.20)

cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

project(com4j_native LANGUAGES C CXX ASM_MASM)

if(NOT MSVC)
message(FATAL_ERROR "This project only builds with MSVC on Windows.")
endif()

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(COM4J_ARCH_DEFINE X86_WIN64)
set(COM4J_PLATFORM_DEFINE WIN64)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win64.asm64)
set(MIDL_ENV win64)
else()
set(COM4J_ARCH_DEFINE X86_WIN32)
set(COM4J_PLATFORM_DEFINE WIN32)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win32.asm)
set(MIDL_ENV win32)
endif()

set_source_files_properties(${LIBFFI_ASM} PROPERTIES LANGUAGE ASM_MASM)

# ---------------------------------------------------------------------------
# JNI
# ---------------------------------------------------------------------------
if(DEFINED JAVA_HOME)
set(ENV{JAVA_HOME} ${JAVA_HOME})
endif()
find_package(JNI REQUIRED)

# ---------------------------------------------------------------------------
# jnitl (git submodule, ../jnitl) - built as a small static lib.
# native/stdafx.h pulls in jnitl.h, which does:
# #pragma comment(lib, "jnitl.lib") (Release, static CRT)
# #pragma comment(lib, "jnitld.lib") (Debug, static CRT)
# so name the output to match and make sure it's on the link path.
# ---------------------------------------------------------------------------
set(JNITL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jnitl)

add_library(jnitl STATIC
${JNITL_DIR}/source/jnitl.cpp
${JNITL_DIR}/source/accessor.cpp
)
target_include_directories(jnitl PUBLIC ${JNITL_DIR}/include)
target_include_directories(jnitl PRIVATE ${JNI_INCLUDE_DIRS})
set_target_properties(jnitl PROPERTIES
OUTPUT_NAME "jnitl"
DEBUG_POSTFIX "d"
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/jnitl-lib
)
target_compile_definitions(jnitl PRIVATE WIN32 ${COM4J_PLATFORM_DEFINE} UNICODE _UNICODE)
# original vcproj built with TreatWChar_tAsBuiltInType="false" (/Zc:wchar_t-),
# which is why jni.h's `jchar` (unsigned short) and `wchar_t*`/BSTR interconvert
# implicitly all over this codebase.
target_compile_options(jnitl PRIVATE /Zc:wchar_t-)

# ---------------------------------------------------------------------------
# MIDL: com4j.idl -> com4j.tlb (+ generated .h/.c, unused but let midl emit
# its normal output). typelib.cpp does `#import "com4j.tlb" no_namespace`
# and com4j.rc embeds it as a TYPELIB resource, so both need the tlb's
# directory on their include search path.
# ---------------------------------------------------------------------------
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MIDL_SDK_ARCH x64)
else()
set(MIDL_SDK_ARCH x86)
endif()
file(GLOB MIDL_SDK_HINTS "C:/Program Files (x86)/Windows Kits/10/bin/10.0.*/${MIDL_SDK_ARCH}")
list(SORT MIDL_SDK_HINTS ORDER DESCENDING)
find_program(MIDL_EXECUTABLE midl.exe HINTS ${MIDL_SDK_HINTS} REQUIRED)

set(COM4J_TLB ${CMAKE_CURRENT_BINARY_DIR}/com4j.tlb)
set(COM4J_MIDL_H ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl.h)
set(COM4J_MIDL_C ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl_i.c)

add_custom_command(
OUTPUT ${COM4J_TLB}
COMMAND ${MIDL_EXECUTABLE}
/nologo
/env ${MIDL_ENV}
/tlb ${COM4J_TLB}
/h ${COM4J_MIDL_H}
/iid ${COM4J_MIDL_C}
/out ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running MIDL on com4j.idl"
VERBATIM
)
add_custom_target(com4j_idl DEPENDS ${COM4J_TLB})

# ---------------------------------------------------------------------------
# com4j.dll
# ---------------------------------------------------------------------------
set(COM4J_SOURCES
com4j.cpp
com4j_Win32Lock.cpp
error.cpp
eventReceiver.cpp
invoke.cpp
java_id.cpp
registry.cpp
safearray.cpp
stdafx.cpp
TestObject.cpp
toJava.cpp
typelib.cpp
variant.cpp
)

set(LIBFFI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libffi)
set(LIBFFI_SOURCES
${LIBFFI_DIR}/src/debug.c
${LIBFFI_DIR}/src/x86/ffi.c
${LIBFFI_DIR}/src/prep_cif.c
${LIBFFI_DIR}/src/types.c
${LIBFFI_ASM}
)

add_library(com4j SHARED
${COM4J_SOURCES}
${LIBFFI_SOURCES}
com4j.rc
)

add_dependencies(com4j com4j_idl)

target_include_directories(com4j PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${JNITL_DIR}/include
${LIBFFI_DIR}/include
${JNI_INCLUDE_DIRS}
)

target_compile_definitions(com4j PRIVATE
${COM4J_PLATFORM_DEFINE}
_WINDOWS
_USRDLL
COM4J_EXPORTS
${COM4J_ARCH_DEFINE}
UNICODE
_UNICODE
$<$<CONFIG:Debug>:_DEBUG>
$<$<NOT:$<CONFIG:Debug>>:NDEBUG>
)
target_compile_options(com4j PRIVATE $<$<COMPILE_LANGUAGE:CXX,C>:/Zc:wchar_t->)

# jnitl.h does `#pragma comment(lib, "jnitl.lib"/"jnitld.lib")` - that pragma-driven
# search needs the jnitl target's actual (per-config) output dir on the /LIBPATH,
# in addition to linking it directly as a CMake target dependency.
target_link_directories(com4j PRIVATE $<TARGET_FILE_DIR:jnitl>)
target_link_libraries(com4j PRIVATE jnitl ole32 oleaut32 uuid)

set(COM4J_LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/com4j.def")
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
# libffi's hand-written win32.asm predates SAFESEH exception-handler records;
# the modern linker refuses to produce a SAFESEH image without this.
set(COM4J_LINK_FLAGS "${COM4J_LINK_FLAGS} /SAFESEH:NO")
endif()
set_target_properties(com4j PROPERTIES
LINK_FLAGS "${COM4J_LINK_FLAGS}"
)

# make sure the rc compile step can find com4j.tlb (embedded via `1 TYPELIB "com4j.tlb"`)
set_source_files_properties(com4j.rc PROPERTIES
COMPILE_OPTIONS "/I${CMAKE_CURRENT_BINARY_DIR}"
)

# TestObject.cpp compiles to nothing outside _DEBUG - fine to always include.
13 changes: 10 additions & 3 deletions native/TestObject.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,8 +31,15 @@ STDMETHODIMP CTestObject::raw_TestVariant(VARIANT v1, VARIANT* v2, VARIANT* v3)

STDMETHODIMP CTestObject::raw_outByteBuf(BSTR bstrEncodedData, long* plSize, unsigned char** ppbData)
{
*plSize = 30;
*ppbData = (BYTE*)"Hello, World!";
static const char text[] = "Hello, World!";
const long len = sizeof(text)-1; // exclude the terminating '\0'

*ppbData = (BYTE*)CoTaskMemAlloc(len);
if(*ppbData==NULL)
return E_OUTOFMEMORY;

memcpy(*ppbData, text, len);
*plSize = len;

return S_OK;
}
Expand All@@ -45,4 +52,4 @@ STDMETHODIMP CTestObject::raw_testUI8Conv(VARIANT* in, VARIANT* out)
return ::VariantCopy(out,in);
}

#endif
#endif
29 changes: 0 additions & 29 deletions native/build.xml

This file was deleted.

Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/build.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
name: Build

on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

jobs:
build:
# windows-2022 ships Visual Studio 2022 (with the C++ ATL and MFC
# components the native build needs) and CMake preinstalled.
runs-on: windows-2022

steps:
- name: Check out repository (with submodules)
uses: actions/checkout@v7
with:
submodules: recursive

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

- name: Show build tool versions
shell: pwsh
run: |
cmake --version
java -version

# -DbuildNative=true forces a real rebuild instead of packaging the
# committed bin/ DLLs (JitPack's only option, since it can't run
# MSVC). package-only, run first, just to catch Release-only compile
# regressions before the Debug build below becomes the installed jar.
- name: Build native (Release)
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# TestObject (needed by tests) only compiles into Debug builds.
# install, not package, so "Run tests" below can resolve com4j from
# the local repo without rebuilding or needing -am.
- name: Build native (Debug)
shell: pwsh
run: mvn -B -pl "!test" install -DbuildNative=true -Dmode=Debug

# Registers com4j.dll as TestObject's COM server. Plain regsvr32
# works unelevated: GitHub's Windows runners run as Administrator
# with UAC disabled (actions/runner-images discussion #6557).
- name: Register COM test object
shell: pwsh
run: |
$dll = Resolve-Path "bin\x64\Debug\com4j.dll"
$p = Start-Process -FilePath "$env:SystemRoot\System32\regsvr32.exe" -ArgumentList "/s", "$dll" -Wait -PassThru -NoNewWindow
if ($p.ExitCode -ne 0) {
throw "regsvr32 failed with exit code $($p.ExitCode)"
}

- name: Run tests
shell: pwsh
run: mvn -B test -pl test
55 changes: 55 additions & 0 deletions .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
name: Release

on:
release:
types: [published]

permissions:
contents: write

jobs:
build-and-upload:
runs-on: windows-2022

steps:
- name: Check out repository (with submodules) at the release tag
uses: actions/checkout@v7
with:
submodules: recursive
ref: ${{ github.event.release.tag_name }}

- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
cache: maven

# Sets the version to the release tag
- name: Set version to release tag
shell: pwsh
run: mvn -B versions:set "-DnewVersion=${{ github.event.release.tag_name }}" -DgenerateBackupPoms=false

# Rebuilds native/com4j.dll (Release, x86+x64) from source rather than
# trusting whatever's committed, so the uploaded jar always reflects
# the exact code at this tag.
- name: Build native (Release) and package
shell: pwsh
run: mvn -B -pl "!test" package -DbuildNative=true -Dmode=Release

# Uploads all modules' built artifacts as release assets
- name: Upload build artifacts to the release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
function Latest($pattern) {
(Get-ChildItem $pattern | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
}
$files = @(
Latest "runtime/target/com4j-*.jar"
Latest "tlbimp/target/tlbimp-*.jar"
Latest "maven-com4j-plugin/target/maven-com4j-plugin-*.jar"
Latest "distribution/target/com4j-dist-*-all.zip"
)
gh release upload "${{ github.event.release.tag_name }}" $files --repo ${{ github.repository }} --clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,3 +10,8 @@
*.tli
vc90.idb
vc90.pdb
native/cmake-build*/

# bin/ holds the prebuilt com4j.dll (x86 and x64, Release and Debug) that the
# Java build packages by default and that JitPack relies on, since it can't
# build native/ itself - these are intentionally committed, do not ignore.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
[submodule "jnitl"]
path = jnitl
url = git://github.com/kohsuke/jnitl.git
url = https://github.com/kohsuke/jnitl.git
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions jitpack.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
jdk:
- openjdk17

# Skip building from source (this project needs a Windows/MSVC toolchain
# JitPack's Linux build servers don't have) and instead install the
# prebuilt artifacts already uploaded to the matching GitHub release by
# .github/workflows/release.yml.
install:
- OWNER=${GROUP#com.github.}
- REPO=${ARTIFACT}
- MODULE_GROUP=${GROUP}.${REPO}
- BASE_URL=https://github.com/${OWNER}/${REPO}/releases/download/${VERSION}

- curl -L -f -o com4j.jar ${BASE_URL}/com4j-${VERSION}.jar
- mvn install:install-file -Dfile=com4j.jar -DgroupId=${MODULE_GROUP} -DartifactId=com4j -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o tlbimp.jar ${BASE_URL}/tlbimp-${VERSION}.jar
- mvn install:install-file -Dfile=tlbimp.jar -DgroupId=${MODULE_GROUP} -DartifactId=tlbimp -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true

- curl -L -f -o maven-com4j-plugin.jar ${BASE_URL}/maven-com4j-plugin-${VERSION}.jar
- mvn install:install-file -Dfile=maven-com4j-plugin.jar -DgroupId=${MODULE_GROUP} -DartifactId=maven-com4j-plugin -Dversion=${VERSION} -Dpackaging=jar -DgeneratePom=true
174 changes: 174 additions & 0 deletions native/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
cmake_minimum_required(VERSION 3.20)

cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

project(com4j_native LANGUAGES C CXX ASM_MASM)

if(NOT MSVC)
message(FATAL_ERROR "This project only builds with MSVC on Windows.")
endif()

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(COM4J_ARCH_DEFINE X86_WIN64)
set(COM4J_PLATFORM_DEFINE WIN64)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win64.asm64)
set(MIDL_ENV win64)
else()
set(COM4J_ARCH_DEFINE X86_WIN32)
set(COM4J_PLATFORM_DEFINE WIN32)
set(LIBFFI_ASM ${CMAKE_CURRENT_SOURCE_DIR}/../libffi/src/x86/win32.asm)
set(MIDL_ENV win32)
endif()

set_source_files_properties(${LIBFFI_ASM} PROPERTIES LANGUAGE ASM_MASM)

# ---------------------------------------------------------------------------
# JNI
# ---------------------------------------------------------------------------
if(DEFINED JAVA_HOME)
set(ENV{JAVA_HOME} ${JAVA_HOME})
endif()
find_package(JNI REQUIRED)

# ---------------------------------------------------------------------------
# jnitl (git submodule, ../jnitl) - built as a small static lib.
# native/stdafx.h pulls in jnitl.h, which does:
# #pragma comment(lib, "jnitl.lib") (Release, static CRT)
# #pragma comment(lib, "jnitld.lib") (Debug, static CRT)
# so name the output to match and make sure it's on the link path.
# ---------------------------------------------------------------------------
set(JNITL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jnitl)

add_library(jnitl STATIC
${JNITL_DIR}/source/jnitl.cpp
${JNITL_DIR}/source/accessor.cpp
)
target_include_directories(jnitl PUBLIC ${JNITL_DIR}/include)
target_include_directories(jnitl PRIVATE ${JNI_INCLUDE_DIRS})
set_target_properties(jnitl PROPERTIES
OUTPUT_NAME "jnitl"
DEBUG_POSTFIX "d"
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/jnitl-lib
)
target_compile_definitions(jnitl PRIVATE WIN32 ${COM4J_PLATFORM_DEFINE} UNICODE _UNICODE)
# original vcproj built with TreatWChar_tAsBuiltInType="false" (/Zc:wchar_t-),
# which is why jni.h's `jchar` (unsigned short) and `wchar_t*`/BSTR interconvert
# implicitly all over this codebase.
target_compile_options(jnitl PRIVATE /Zc:wchar_t-)

# ---------------------------------------------------------------------------
# MIDL: com4j.idl -> com4j.tlb (+ generated .h/.c, unused but let midl emit
# its normal output). typelib.cpp does `#import "com4j.tlb" no_namespace`
# and com4j.rc embeds it as a TYPELIB resource, so both need the tlb's
# directory on their include search path.
# ---------------------------------------------------------------------------
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MIDL_SDK_ARCH x64)
else()
set(MIDL_SDK_ARCH x86)
endif()
file(GLOB MIDL_SDK_HINTS "C:/Program Files (x86)/Windows Kits/10/bin/10.0.*/${MIDL_SDK_ARCH}")
list(SORT MIDL_SDK_HINTS ORDER DESCENDING)
find_program(MIDL_EXECUTABLE midl.exe HINTS ${MIDL_SDK_HINTS} REQUIRED)

set(COM4J_TLB ${CMAKE_CURRENT_BINARY_DIR}/com4j.tlb)
set(COM4J_MIDL_H ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl.h)
set(COM4J_MIDL_C ${CMAKE_CURRENT_BINARY_DIR}/com4j_midl_i.c)

add_custom_command(
OUTPUT ${COM4J_TLB}
COMMAND ${MIDL_EXECUTABLE}
/nologo
/env ${MIDL_ENV}
/tlb ${COM4J_TLB}
/h ${COM4J_MIDL_H}
/iid ${COM4J_MIDL_C}
/out ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/com4j.idl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running MIDL on com4j.idl"
VERBATIM
)
add_custom_target(com4j_idl DEPENDS ${COM4J_TLB})

# ---------------------------------------------------------------------------
# com4j.dll
# ---------------------------------------------------------------------------
set(COM4J_SOURCES
com4j.cpp
com4j_Win32Lock.cpp
error.cpp
eventReceiver.cpp
invoke.cpp
java_id.cpp
registry.cpp
safearray.cpp
stdafx.cpp
TestObject.cpp
toJava.cpp
typelib.cpp
variant.cpp
)

set(LIBFFI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libffi)
set(LIBFFI_SOURCES
${LIBFFI_DIR}/src/debug.c
${LIBFFI_DIR}/src/x86/ffi.c
${LIBFFI_DIR}/src/prep_cif.c
${LIBFFI_DIR}/src/types.c
${LIBFFI_ASM}
)

add_library(com4j SHARED
${COM4J_SOURCES}
${LIBFFI_SOURCES}
com4j.rc
)

add_dependencies(com4j com4j_idl)

target_include_directories(com4j PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${JNITL_DIR}/include
${LIBFFI_DIR}/include
${JNI_INCLUDE_DIRS}
)

target_compile_definitions(com4j PRIVATE
${COM4J_PLATFORM_DEFINE}
_WINDOWS
_USRDLL
COM4J_EXPORTS
${COM4J_ARCH_DEFINE}
UNICODE
_UNICODE
$<$<CONFIG:Debug>:_DEBUG>
$<$<NOT:$<CONFIG:Debug>>:NDEBUG>
)
target_compile_options(com4j PRIVATE $<$<COMPILE_LANGUAGE:CXX,C>:/Zc:wchar_t->)

# jnitl.h does `#pragma comment(lib, "jnitl.lib"/"jnitld.lib")` - that pragma-driven
# search needs the jnitl target's actual (per-config) output dir on the /LIBPATH,
# in addition to linking it directly as a CMake target dependency.
target_link_directories(com4j PRIVATE $<TARGET_FILE_DIR:jnitl>)
target_link_libraries(com4j PRIVATE jnitl ole32 oleaut32 uuid)

set(COM4J_LINK_FLAGS "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/com4j.def")
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
# libffi's hand-written win32.asm predates SAFESEH exception-handler records;
# the modern linker refuses to produce a SAFESEH image without this.
set(COM4J_LINK_FLAGS "${COM4J_LINK_FLAGS} /SAFESEH:NO")
endif()
set_target_properties(com4j PROPERTIES
LINK_FLAGS "${COM4J_LINK_FLAGS}"
)

# make sure the rc compile step can find com4j.tlb (embedded via `1 TYPELIB "com4j.tlb"`)
set_source_files_properties(com4j.rc PROPERTIES
COMPILE_OPTIONS "/I${CMAKE_CURRENT_BINARY_DIR}"
)

# TestObject.cpp compiles to nothing outside _DEBUG - fine to always include.
13 changes: 10 additions & 3 deletions native/TestObject.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,8 +31,15 @@ STDMETHODIMP CTestObject::raw_TestVariant(VARIANT v1, VARIANT* v2, VARIANT* v3)

STDMETHODIMP CTestObject::raw_outByteBuf(BSTR bstrEncodedData, long* plSize, unsigned char** ppbData)
{
*plSize = 30;
*ppbData = (BYTE*)"Hello, World!";
static const char text[] = "Hello, World!";
const long len = sizeof(text)-1; // exclude the terminating '\0'

*ppbData = (BYTE*)CoTaskMemAlloc(len);
if(*ppbData==NULL)
return E_OUTOFMEMORY;

memcpy(*ppbData, text, len);
*plSize = len;

return S_OK;
}
Expand All@@ -45,4 +52,4 @@ STDMETHODIMP CTestObject::raw_testUI8Conv(VARIANT* in, VARIANT* out)
return ::VariantCopy(out,in);
}

#endif
#endif
29 changes: 0 additions & 29 deletions native/build.xml

This file was deleted.

Loading