From 7057d0418207456c48c58fa2e9683602c782bcdf Mon Sep 17 00:00:00 2001 From: Mark Lechtermann Date: Mon, 18 Jul 2022 18:25:46 +0200 Subject: [PATCH] Support for 32Bit assemblies (#65) * Support for 32Bit assemblies Fixes #60 * Check Is64BitProcess property for win32 output * Add binaries to releases --- .github/workflows/release.yaml | 20 +++++- scripts/demo32Bit.bat | 70 +++++++++++++++++++++ src/dscom.client/Program.cs | 7 ++- src/dscom.client/dscom.client.csproj | 3 +- src/dscom.common/ICreateTypeInfo2.cs | 10 +-- src/dscom.common/ICreateTypeLib2.cs | 2 +- src/dscom.demo/assembly1/assembly1.csproj | 3 +- src/dscom.demo/assembly2/assembly2.csproj | 3 +- src/dscom.demo/assembly3/assembly3.csproj | 3 +- src/dscom.test/dscom.test.csproj | 1 + src/dscom/TypeLibConverter.cs | 9 ++- src/dscom/TypeLibConverterSettings.cs | 5 ++ src/dscom/WriterContext.cs | 5 ++ src/dscom/dscom.csproj | 3 +- src/dscom/writer/IUnknownInterfaceWriter.cs | 3 +- src/dscom/writer/InterfaceWriter.cs | 21 ++----- 16 files changed, 134 insertions(+), 34 deletions(-) create mode 100644 scripts/demo32Bit.bat diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 75e2ee31..6750d650 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -46,4 +46,22 @@ jobs: - name: Nuget push tool run: dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET }} --source https://api.nuget.org/v3/index.json - working-directory: src/dscom.client/bin/Release \ No newline at end of file + working-directory: src/dscom.client/bin/Release + + - name: Publish 32Bit binary + run: dotnet publish .\src\dscom.client\dscom.client.csproj --no-self-contained -c Release -r win-x86 -f net6.0 /p:PublishSingleFile=true; copy src\dscom.client\bin\Release\net6.0\win-x86\publish\dscom.exe src\dscom.client\bin\Release\net6.0\win-x86\publish\dscom32.exe + + - name: Release 32Bit binary + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + files: src\dscom.client\bin\Release\net6.0\win-x86\publish\dscom32.exe + + - name: Publish 64Bit binary + run: dotnet publish .\src\dscom.client\dscom.client.csproj --no-self-contained -c Release -r win-x64 -f net6.0 /p:PublishSingleFile=true + + - name: Release 64Bit binary + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + files: src\dscom.client\bin\Release\net6.0\win-x64\publish\dscom.exe \ No newline at end of file diff --git a/scripts/demo32Bit.bat b/scripts/demo32Bit.bat new file mode 100644 index 00000000..b5ae7774 --- /dev/null +++ b/scripts/demo32Bit.bat @@ -0,0 +1,70 @@ +@echo off + +SET workspace=%~dp0..\ +@REM set filterregex=--filterregex \.file\= --filterregex \.attributes\.guid\= --filterregex numberOfImplementedInterfaces --filterregex implementedInterfaces +set filterregex= + +SET net60dll=%workspace%src\dscom.demo\assembly1\bin\Release\net6.0\dSPACE.Runtime.InteropServices.DemoAssembly1.dll +SET net48dll=%workspace%src\dscom.demo\assembly1\bin\Release\net48\dSPACE.Runtime.InteropServices.DemoAssembly1.dll + +del %workspace%src\dscom.demo\assembly1\bin\Release\net48\*.tlb +del %workspace%src\dscom.demo\assembly1\bin\Release\net6.0\*.tlb +del %workspace%src\dscom.demo\assembly1\bin\Release\net6.0\*.yaml +del %workspace%src\dscom.demo\assembly1\bin\Release\net48\*.yaml + +dotnet build -c Release "%workspace%dscom.sln" +IF ERRORLEVEL 1 goto error + +@REM dscom +echo ############## dscom.exe tlbexport +dotnet run --project %workspace%src\dscom.client\dscom.client.csproj -r win-x86 -f net6.0 --no-self-contained tlbexport /win32 /silent "%net60dll%" "/out:%net60dll%.tlb" + +IF ERRORLEVEL 1 goto error + +echo ############## dscom.exe tlbdump +dotnet run --project %workspace%src\dscom.client\dscom.client.csproj -r win-x86 -f net6.0 --no-self-contained tlbdump %filterregex% "/tlbrefpath:%net60dll%.tlb/.." "%net60dll%.tlb" "/out:%net60dll%.yaml" +IF ERRORLEVEL 1 goto error + +WHERE tlbexp +IF %ERRORLEVEL% NEQ 0 ( + ECHO. + ECHO ###################################################### + ECHO. + ECHO tlbexp.exe not found + ECHO Please add the path to tlbexp.exe to your PATH variable. + ECHO. + ECHO ###################################################### + ECHO. + goto error +) + +@REM tlbexp +echo ############## tlbexp.exe +tlbexp /win32 /silent "%net48dll%" "/out:%net48dll%.tlb" +IF ERRORLEVEL 1 goto error + +echo ############## dscom.exe tlbdump +dotnet run --project %workspace%src\dscom.client\dscom.client.csproj -r win-x86 -f net6.0 --no-self-contained tlbdump %filterregex% "/tlbrefpath:%net48dll%.tlb/.." "%net48dll%.tlb" "/out:%net48dll%.yaml" +IF ERRORLEVEL 1 goto error + +WHERE code +IF %ERRORLEVEL% NEQ 0 ( + ECHO. + ECHO ###################################################### + ECHO. + ECHO You don't have Visual Studio Code installed, too bad. + ECHO https://code.visualstudio.com/download + ECHO. + ECHO Please compare the following files: + ECHO %net48dll%.yaml + ECHO %net60dll%.yaml + ECHO. + ECHO ###################################################### + ECHO. + goto error +) + +code -d "%net48dll%.yaml" "%net60dll%.yaml" + +:error + pause \ No newline at end of file diff --git a/src/dscom.client/Program.cs b/src/dscom.client/Program.cs index 0a85d4e9..fae074d8 100644 --- a/src/dscom.client/Program.cs +++ b/src/dscom.client/Program.cs @@ -37,6 +37,7 @@ public static int Main(string[] args) new Option(new string [] {"--names", "/names"}, description: "A file in which each line specifies the capitalization of a name in the type library.", getDefaultValue: () => Array.Empty()) { Arity = ArgumentArity.ZeroOrMore}, new Option(new string [] {"--overridetlbid", "/overridetlbid"}, description: "Overwrites the library id"), new Option(new string [] {"--createmissingdependenttlbs", "/createmissingdependenttlbs"}, description: "Generate missing type libraries for referenced assemblies. (default true)"), + new Option(new string [] {"--win32", "/win32"}, description: "Create a 32-bit type library"), }; var tlbdumpCommand = new Command("tlbdump", "Dump a type library") @@ -69,7 +70,7 @@ public static int Main(string[] args) tlbunregisterCommand }; - rootCommand.Description = "dSPACE COM tools"; + rootCommand.Description = $"dSPACE COM tools ({(Environment.Is64BitProcess ? "64Bit" : "32Bit")})"; ConfigureTLBExportHandler(tlbexportCommand); ConfigureTLBDumpHandler(tlbdumpCommand); @@ -199,13 +200,13 @@ private static void ConfigureTLBExportHandler(Command tlbexportCommand) { throw; } -#else +#else catch (Exception e) { Console.Error.WriteLine($"Failed to export type library. {e.Message} {e.InnerException?.Message}"); return 1; } -#endif +#endif }); } diff --git a/src/dscom.client/dscom.client.csproj b/src/dscom.client/dscom.client.csproj index e4b30b57..6aba7d2a 100644 --- a/src/dscom.client/dscom.client.csproj +++ b/src/dscom.client/dscom.client.csproj @@ -4,7 +4,8 @@ dscom Exe net6.0 - x64 + AnyCPU + AnyCPU;x86 10.0 enable enable diff --git a/src/dscom.common/ICreateTypeInfo2.cs b/src/dscom.common/ICreateTypeInfo2.cs index 2d0702f9..0a6672db 100644 --- a/src/dscom.common/ICreateTypeInfo2.cs +++ b/src/dscom.common/ICreateTypeInfo2.cs @@ -93,19 +93,19 @@ internal interface ICreateTypeInfo2 : ICreateTypeInfo HRESULT DeleteImplType(uint index); [PreserveSig] - HRESULT SetCustData(in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] object pVarVal); + HRESULT SetCustData(in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] ref object pVarVal); [PreserveSig] - HRESULT SetFuncCustData(uint index, in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] object pVarVal); + HRESULT SetFuncCustData(uint index, in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] ref object pVarVal); [PreserveSig] - HRESULT SetParamCustData(uint indexFunc, uint indexParam, in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] object pVarVal); + HRESULT SetParamCustData(uint indexFunc, uint indexParam, in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] ref object pVarVal); [PreserveSig] - HRESULT SetVarCustData(uint index, in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] object pVarVal); + HRESULT SetVarCustData(uint index, in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] ref object pVarVal); [PreserveSig] - HRESULT SetImplTypeCustData(uint index, in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] object pVarVal); + HRESULT SetImplTypeCustData(uint index, in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] ref object pVarVal); [PreserveSig] HRESULT SetHelpStringContext(uint dwHelpStringContext); diff --git a/src/dscom.common/ICreateTypeLib2.cs b/src/dscom.common/ICreateTypeLib2.cs index 0f2cc6de..7194cace 100644 --- a/src/dscom.common/ICreateTypeLib2.cs +++ b/src/dscom.common/ICreateTypeLib2.cs @@ -42,7 +42,7 @@ internal interface ICreateTypeLib2 : ICreateTypeLib HRESULT DeleteTypeInfo([MarshalAs(UnmanagedType.LPWStr)] string? szName); [PreserveSig] - HRESULT SetCustData(in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] object? pVarVal); + HRESULT SetCustData(in Guid guid, [In, MarshalAs(UnmanagedType.Struct)] ref object? pVarVal); [PreserveSig] HRESULT SetHelpStringContext(uint dwHelpStringContext); diff --git a/src/dscom.demo/assembly1/assembly1.csproj b/src/dscom.demo/assembly1/assembly1.csproj index 5b21baf3..aa6df12d 100644 --- a/src/dscom.demo/assembly1/assembly1.csproj +++ b/src/dscom.demo/assembly1/assembly1.csproj @@ -2,7 +2,7 @@ net6.0;net48 - x64 + AnyCPU 10.0 enable enable @@ -12,6 +12,7 @@ Recommended true CA1416;CA1401;CA1707;CA1720;CA1711;CA2201;CA1200;CA5351;CS0618;CA1305; + AnyCPU;x86 diff --git a/src/dscom.demo/assembly2/assembly2.csproj b/src/dscom.demo/assembly2/assembly2.csproj index 2c0c3401..6e8123a5 100644 --- a/src/dscom.demo/assembly2/assembly2.csproj +++ b/src/dscom.demo/assembly2/assembly2.csproj @@ -2,7 +2,7 @@ net6.0;net48 - x64 + AnyCPU 10.0 enable enable @@ -11,6 +11,7 @@ true Recommended true + AnyCPU;x86 \ No newline at end of file diff --git a/src/dscom.demo/assembly3/assembly3.csproj b/src/dscom.demo/assembly3/assembly3.csproj index 92327e02..805400a3 100644 --- a/src/dscom.demo/assembly3/assembly3.csproj +++ b/src/dscom.demo/assembly3/assembly3.csproj @@ -2,7 +2,7 @@ net6.0;net48 - x64 + AnyCPU 10.0 enable enable @@ -11,6 +11,7 @@ true Recommended true + AnyCPU;x86 \ No newline at end of file diff --git a/src/dscom.test/dscom.test.csproj b/src/dscom.test/dscom.test.csproj index 03ebd19f..07f26dac 100644 --- a/src/dscom.test/dscom.test.csproj +++ b/src/dscom.test/dscom.test.csproj @@ -12,6 +12,7 @@ Recommended true CA1416;CA1401;CA1707;CA1720;CA1711;CA2201;CA1200;CA5351;CS0618;CA1305; + AnyCPU;x86 diff --git a/src/dscom/TypeLibConverter.cs b/src/dscom/TypeLibConverter.cs index 4b32ac23..5c9d1158 100644 --- a/src/dscom/TypeLibConverter.cs +++ b/src/dscom/TypeLibConverter.cs @@ -38,7 +38,12 @@ public class TypeLibConverter /// An object that implements the interface. public object? ConvertAssemblyToTypeLib(Assembly assembly, string tlbFilePath, ITypeLibExporterNotifySink? notifySink) { - var options = new TypeLibConverterSettings() { Out = tlbFilePath }; + var options = new TypeLibConverterSettings + { + Out = tlbFilePath, + Win32 = !Environment.Is64BitProcess + }; + return ConvertAssemblyToTypeLib(assembly, options, notifySink); } @@ -51,7 +56,7 @@ public class TypeLibConverter { CheckPlatform(); - OleAut32.CreateTypeLib2(SYSKIND.SYS_WIN64, settings.Out!, out var typelib).ThrowIfFailed("Failed to create type library."); + OleAut32.CreateTypeLib2(settings.Win32 ? SYSKIND.SYS_WIN32 : SYSKIND.SYS_WIN64, settings.Out!, out var typelib).ThrowIfFailed("Failed to create type library."); using var writer = new LibraryWriter(assembly, new WriterContext(settings, typelib, notifySink)); writer.Create(); diff --git a/src/dscom/TypeLibConverterSettings.cs b/src/dscom/TypeLibConverterSettings.cs index ddd87452..f33ffe59 100644 --- a/src/dscom/TypeLibConverterSettings.cs +++ b/src/dscom/TypeLibConverterSettings.cs @@ -48,4 +48,9 @@ public class TypeLibConverterSettings /// Gets or sets the type library GUID. /// public Guid OverrideTlbId { get; set; } = Guid.Empty; + + /// + /// Gets or sets a value indicating whether the TLB is 32Bit. + /// + public bool Win32 { get; set; } = !Environment.Is64BitProcess; } diff --git a/src/dscom/WriterContext.cs b/src/dscom/WriterContext.cs index 3aab0958..612c680b 100644 --- a/src/dscom/WriterContext.cs +++ b/src/dscom/WriterContext.cs @@ -49,6 +49,11 @@ public WriterContext(TypeLibConverterSettings options, ICreateTypeLib2 targetTyp public NameResolver NameResolver { get; private set; } + /// + /// Gets size of a pointer or handle in this process, measured in bytes. The value of this property is 4 in a 32-bit process, and 8 in a 64-bit process. + /// + internal int IntPtrSize => Options.Win32 ? 4 : 8; + public void LogTypeExported(string message) { if (NotifySink != null) diff --git a/src/dscom/dscom.csproj b/src/dscom/dscom.csproj index 9e1c6cc9..3a6c310d 100644 --- a/src/dscom/dscom.csproj +++ b/src/dscom/dscom.csproj @@ -3,7 +3,8 @@ dSPACE.Runtime.InteropServices net6.0;net48 - x64 + AnyCPU + AnyCPU;x86 10.0 enable enable diff --git a/src/dscom/writer/IUnknownInterfaceWriter.cs b/src/dscom/writer/IUnknownInterfaceWriter.cs index 1b6593ed..6358311c 100644 --- a/src/dscom/writer/IUnknownInterfaceWriter.cs +++ b/src/dscom/writer/IUnknownInterfaceWriter.cs @@ -23,7 +23,8 @@ public IUnknownInterfaceWriter(Type sourceType, LibraryWriter libraryWriter, Wri TypeFlags = TYPEFLAGS.TYPEFLAG_FOLEAUTOMATION; TypeKind = TYPEKIND.TKIND_INTERFACE; FuncKind = FUNCKIND.FUNC_PUREVIRTUAL; - VTableOffsetUserMethodStart = 24; + + VTableOffsetUserMethodStart = 3 * Context.IntPtrSize; ComInterfaceType = ComInterfaceType.InterfaceIsIUnknown; UseHResultAsReturnValue = true; } diff --git a/src/dscom/writer/InterfaceWriter.cs b/src/dscom/writer/InterfaceWriter.cs index db7a8a98..3995c3d9 100644 --- a/src/dscom/writer/InterfaceWriter.cs +++ b/src/dscom/writer/InterfaceWriter.cs @@ -21,11 +21,12 @@ internal abstract class InterfaceWriter : TypeWriter { public InterfaceWriter(Type sourceType, LibraryWriter libraryWriter, WriterContext context) : base(sourceType, libraryWriter, context) { + VTableOffsetUserMethodStart = 7 * context.IntPtrSize; } public DispatchIdCreator? DispatchIdCreator { get; protected set; } - public int VTableOffsetUserMethodStart { get; set; } = 56; + public int VTableOffsetUserMethodStart { get; set; } public ComInterfaceType ComInterfaceType { get; set; } @@ -70,20 +71,8 @@ public override void Create() // Handle special IDs like 0 or -4, and try to fix duplicate DispIds if possible. DispatchIdCreator.NormalizeIds(); - // This index is necessary to generate the correct offset of the VTable. - // Every method must be considered, even those that cannot be generated. - // var index = 0; - - // // The index of the function inside the type library - // var functionIndex = 0; - foreach (var item in MethodWriter) - { - // item.FunctionIndex = functionIndex; - // item.VTableOffset = VTableOffsetUserMethodStart + (index * 8); - item.Create(); - // functionIndex += item.IsValid ? 1 : 0; - // index++; - } + // Create all writer. + MethodWriter.ForEach(writer => writer.Create()); TypeInfo.LayOut().ThrowIfFailed($"Failed to layout type {SourceType}."); } @@ -129,7 +118,7 @@ private void CreateMethodWriters() foreach (var methodWriter in MethodWriter) { methodWriter.FunctionIndex = functionIndex; - methodWriter.VTableOffset = VTableOffsetUserMethodStart + (index * 8); + methodWriter.VTableOffset = VTableOffsetUserMethodStart + (index * Context.IntPtrSize); DispatchIdCreator!.RegisterMember(methodWriter); functionIndex += methodWriter.IsValid ? 1 : 0; index++;