Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty function table after export #136

Closed
gimi87 opened this issue Feb 3, 2020 · 9 comments
Closed

Empty function table after export #136

gimi87 opened this issue Feb 3, 2020 · 9 comments
Labels

Comments

@gimi87
Copy link

gimi87 commented Feb 3, 2020

Hello :)

I guess I have a simple problem with the DllExport.
I have netstandard2.1 project and I'm running the DllExport 1.7.0 version and I'd like to export functions.

This is my csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
  </PropertyGroup>
  <PropertyGroup>
    <DllExportIdent>0D1AB47E-E286-45E0-BE60-CA858F8A978D</DllExportIdent>
    <DllExportMetaLibName>DllExport.dll</DllExportMetaLibName>
    <DllExportNamespace>ClassLibrary1</DllExportNamespace>
    <DllExportDDNSCecil>false</DllExportDDNSCecil>
    <DllExportSkipOnAnyCpu>false</DllExportSkipOnAnyCpu>
    <DllExportPlatform>Auto</DllExportPlatform>
    <DllExportOrdinalsBase>1</DllExportOrdinalsBase>
    <DllExportGenExpLib>true</DllExportGenExpLib>
    <DllExportOurILAsm>true</DllExportOurILAsm>
    <DllExportSysObjRebase>true</DllExportSysObjRebase>
    <DllExportLeaveIntermediateFiles>false</DllExportLeaveIntermediateFiles>
    <DllExportTimeout>30000</DllExportTimeout>
    <DllExportPeCheck>2</DllExportPeCheck>
    <DllExportPatches>1</DllExportPatches>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="DllExport" Version="1.7.0" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="DllExport, PublicKeyToken=8337224c9ad9e356">
      <HintPath>$(SolutionDir)packages\DllExport.1.7.0\gcache\$(DllExportMetaXBase)\$(DllExportNamespace)\$(DllExportMetaLibName)</HintPath>
      <Private>False</Private>
      <SpecificVersion>False</SpecificVersion>
    </Reference>
  </ItemGroup>
  <ImportGroup Label=".NET DllExport">
    <Import Project="$(SolutionDir)packages\DllExport.1.7.0\tools\net.r_eg.DllExport.targets" Condition="Exists($([MSBuild]::Escape('$(SolutionDir)packages\DllExport.1.7.0\tools\net.r_eg.DllExport.targets')))" Label="8337224c9ad9e356" />
  </ImportGroup>
  <Target Name="DllExportRestorePkg" BeforeTargets="PrepareForBuild">
    <Error Condition="!Exists('$(SolutionDir)DllExport.bat')" Text="DllExport.bat is not found. Path: '$(SolutionDir)' - https://github.com/3F/DllExport" />
    <Exec Condition="('$(DllExportModImported)' != 'true' Or !Exists('$(SolutionDir)packages\DllExport.1.7.0\tools\net.r_eg.DllExport.targets')) And Exists('$(SolutionDir)DllExport.bat')" Command=".\DllExport.bat  -action Restore" WorkingDirectory="$(SolutionDir)" />
  </Target>
  <Target Name="DllExportRPkgDynamicImport" BeforeTargets="PostBuildEvent" DependsOnTargets="GetFrameworkPaths" Condition="'$(DllExportModImported)' != 'true' And '$(DllExportRPkgDyn)' != 'false'">
    <MSBuild BuildInParallel="true" UseResultsCache="true" Projects="$(MSBuildProjectFullPath)" Properties="DllExportRPkgDyn=true" Targets="Build" />
  </Target>
</Project>

sample class:

using System;
using System.Runtime.InteropServices;

namespace ClassLibrary1
{
	public static class PassThruDeviceAPI
	{
		[DllExport] public static int PassThruOpen([In] IntPtr pName, [Out] IntPtr pDeviceID) => 0;
		[DllExport] public static int PassThruClose([In]uint deviceID) => 0;
		[DllExport] public static int PassThruConnect([In]uint deviceID, [In]int protocolID, [In]int flags, [In]uint baudrate, [Out]IntPtr pChannelID) => 0;
		[DllExport] public static int PassThruDisconnect([In]uint channelID) => 0;
		[DllExport] public static int PassThruReadMsgs([In]uint channelID, [Out]IntPtr pMsg, [In, Out]IntPtr pNumMsgs, [In]uint timeout) => 0;
		[DllExport] public static int PassThruWriteMsgs([In]uint channelID, [In]IntPtr pMsgs, [In, Out]IntPtr pNumMsgs, [In]uint timeout) => 0;
		[DllExport] public static int PassThruStartPeriodicMsg([In]uint channelID, [In]IntPtr pMsg, [Out]IntPtr pMsgID, [In]uint timeInterval) => 0;
		[DllExport] public static int PassThruStopPeriodicMsg([In]uint channelID, [In]uint msgID) => 0;
		[DllExport] public static int PassThruStartMsgFilter([In]uint channelID, [In]int filterType, [In]IntPtr pMaskMsg, [In]IntPtr pPatternMsg, [In]IntPtr pFlowControlMsg, [Out]IntPtr pFilterID) => 0;
		[DllExport] public static int PassThruStopMsgFilter([In]uint channelID, [In]uint filterID) => 0;
		[DllExport] public static int PassThruSetProgrammingVoltage([In]uint deviceID, [In]uint pinNumber, [In]uint voltage) => 0;
		[DllExport] public static int PassThruReadVersion([In]uint deviceID, [Out]IntPtr pFirmwareVersion, [Out]IntPtr pDllVersion, [Out]IntPtr pApiVersion) => 0;
		[DllExport] public static int PassThruGetLastError([Out]IntPtr pErrorDescription) => 0;
		[DllExport] public static int PassThruIoctl([In]uint channelID, [In]int ioctlID, [In]IntPtr pInput, [Out]IntPtr pOutput) => 0;
	}
}

build log:

Restoring NuGet packages...
To prevent NuGet from restoring packages during build, open the Visual Studio Options dialog, click on the NuGet Package Manager node and uncheck 'Allow NuGet to download missing packages during build.'
Restoring packages for D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\ClassLibrary1.csproj...
Committing restore...
Assets file has not changed. Skipping assets file writing. Path: D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\obj\project.assets.json
Restore completed in 3,15 ms for D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\ClassLibrary1.csproj.
NuGet package restore finished.
1>------ Rebuild All started: Project: ClassLibrary1, Configuration: Debug Any CPU ------
1>Build started 03.02.2020 16:09:14.
1>Target CoreClean:
1>  Deleting file "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\bin\Debug\netstandard2.1\ClassLibrary1.deps.json".
1>  Deleting file "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\bin\Debug\netstandard2.1\ClassLibrary1.dll".
1>  Deleting file "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\obj\Debug\netstandard2.1\ClassLibrary1.csprojAssemblyReference.cache".
1>  Deleting file "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\obj\Debug\netstandard2.1\ClassLibrary1.AssemblyInfoInputs.cache".
1>  Deleting file "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\obj\Debug\netstandard2.1\ClassLibrary1.AssemblyInfo.cs".
1>  Deleting file "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\obj\Debug\netstandard2.1\ClassLibrary1.dll".
1>  Deleting file "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\obj\Debug\netstandard2.1\ClassLibrary1.pdb".
1>Target GenerateTargetFrameworkMonikerAttribute:
1>  Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
1>Target CoreCompile:
1>  Using shared compilation with compiler from directory: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn
1>Target CopyFilesToOutputDirectory:
1>  Copying file from "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\obj\Debug\netstandard2.1\ClassLibrary1.dll" to "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\bin\Debug\netstandard2.1\ClassLibrary1.dll".
1>  ClassLibrary1 -> D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\bin\Debug\netstandard2.1\ClassLibrary1.dll
1>  Copying file from "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\obj\Debug\netstandard2.1\ClassLibrary1.pdb" to "D:\Documents\Visual Studio 2019\Projects\ClassLibrary1\bin\Debug\netstandard2.1\ClassLibrary1.pdb".
1>Target DllExportMod:
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruOpen'([in] native int 'pName', [out] native int 'pDeviceID') cil managed
1>  	exporting as PassThruOpen and index 1
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruClose'([in] uint32 'deviceID') cil managed
1>  	exporting as PassThruClose and index 2
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruConnect'([in] uint32 'deviceID', [in] int32 'protocolID', [in] int32 'flags', [in] uint32 'baudrate', [out] native int 'pChannelID') cil managed
1>  	exporting as PassThruConnect and index 3
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruDisconnect'([in] uint32 'channelID') cil managed
1>  	exporting as PassThruDisconnect and index 4
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruReadMsgs'([in] uint32 'channelID', [out] native int 'pMsg', [in][out] native int 'pNumMsgs', [in] uint32 'timeout') cil managed
1>  	exporting as PassThruReadMsgs and index 5
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruWriteMsgs'([in] uint32 'channelID', [in] native int 'pMsgs', [in][out] native int 'pNumMsgs', [in] uint32 'timeout') cil managed
1>  	exporting as PassThruWriteMsgs and index 6
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruStartPeriodicMsg'([in] uint32 'channelID', [in] native int 'pMsg', [out] native int 'pMsgID', [in] uint32 'timeInterval') cil managed
1>  	exporting as PassThruStartPeriodicMsg and index 7
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruStopPeriodicMsg'([in] uint32 'channelID', [in] uint32 'msgID') cil managed
1>  	exporting as PassThruStopPeriodicMsg and index 8
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruStartMsgFilter'([in] uint32 'channelID', [in] int32 'filterType', [in] native int 'pMaskMsg', [in] native int 'pPatternMsg', [in] native int 'pFlowControlMsg', [out] native int 'pFilterID') cil managed
1>  	exporting as PassThruStartMsgFilter and index 9
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruStopMsgFilter'([in] uint32 'channelID', [in] uint32 'filterID') cil managed
1>  	exporting as PassThruStopMsgFilter and index 10
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruSetProgrammingVoltage'([in] uint32 'deviceID', [in] uint32 'pinNumber', [in] uint32 'voltage') cil managed
1>  	exporting as PassThruSetProgrammingVoltage and index 11
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruReadVersion'([in] uint32 'deviceID', [out] native int 'pFirmwareVersion', [out] native int 'pDllVersion', [out] native int 'pApiVersion') cil managed
1>  	exporting as PassThruReadVersion and index 12
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruGetLastError'([out] native int 'pErrorDescription') cil managed
1>  	exporting as PassThruGetLastError and index 13
1>  Found method: ClassLibrary1.PassThruDeviceAPI..method public hidebysig static int32  'PassThruIoctl'([in] uint32 'channelID', [in] int32 'ioctlID', [in] native int 'pInput', [out] native int 'pOutput') cil managed
1>  	exporting as PassThruIoctl and index 14
1>  VsDevCmd: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat
1>  lib tool via VsDevCmd: 0
1>
1>Build succeeded.
1>    0 Warning(s)
1>    0 Error(s)
1>
1>Time Elapsed 00:00:04.38
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

After that I have a program called "DLL Export Viewer" to check that export is correct and file is generating proper function table and my list is empty:
empty
Similar library from 3rd party is looking like this:
not_empty

What I'm doing wrong? Can you help me to fill that table with your tool?

@gimi87 gimi87 added the question label Feb 3, 2020
@3F
Copy link
Owner

3F commented Feb 3, 2020

Can you show what says -pe-exp-list <module> command?

Also I hope you're using modified modules in related x86 + x64 folders instead of original in ~\bin.

@gimi87
Copy link
Author

gimi87 commented Feb 3, 2020

Log:

PS D:\Documents\Visual Studio 2019\Projects\ClassLibrary1> .\DllExport.bat -pe-exp-list bin\Debug\netstandard2.1\ClassLibrary1.dll
PS D:\Documents\Visual Studio 2019\Projects\ClassLibrary1> .\DllExport.bat -pe-exp-list bin\Debug\netstandard2.1\x86\ClassLibrary1.dll
PassThruClose
PassThruConnect
PassThruDisconnect
PassThruGetLastError
PassThruIoctl
PassThruOpen
PassThruReadMsgs
PassThruReadVersion
PassThruSetProgrammingVoltage
PassThruStartMsgFilter
PassThruStartPeriodicMsg
PassThruStopMsgFilter
PassThruStopPeriodicMsg
PassThruWriteMsgs
PS D:\Documents\Visual Studio 2019\Projects\ClassLibrary1> .\DllExport.bat -pe-exp-list bin\Debug\netstandard2.1\x64\ClassLibrary1.dll
PassThruClose
PassThruConnect
PassThruDisconnect
PassThruGetLastError
PassThruIoctl
PassThruOpen
PassThruReadMsgs
PassThruReadVersion
PassThruSetProgrammingVoltage
PassThruStartMsgFilter
PassThruStartPeriodicMsg
PassThruStopMsgFilter
PassThruStopPeriodicMsg
PassThruWriteMsgs
PS D:\Documents\Visual Studio 2019\Projects\ClassLibrary1>

I'm trying to use from the x86 folder, because 32-bit is required :)

@3F
Copy link
Owner

3F commented Feb 3, 2020

@gimi87, Thanks for the details about issue!

I don't know about "DLL Export Viewer" tool, but our -pe-exp-list indicates normal export as you can also see it from your log.

Can you help me to fill that table with your tool?

You need to contact with developers of the mentioned "DLL Export Viewer" tool if some records are not displayed from the following modules:

  • bin\Debug\netstandard2.1\x86\ClassLibrary1.dll
  • bin\Debug\netstandard2.1\x64\ClassLibrary1.dll

@3F 3F closed this as completed Feb 3, 2020
@gimi87
Copy link
Author

gimi87 commented Feb 3, 2020

I know that it is 3rd party tool.
I just wanted to show that something is not properly addressed, because when I open this exported library from the application which is trying to import and use those methods I have "Access violation (c0000005)". So I guess not everything is exported correctly.
Maybe I'll wait for some updates in the meantime.
But thanks anyway.

@3F
Copy link
Owner

3F commented Feb 3, 2020

which is trying to import and use those methods I have "Access violation (c0000005)"

@gimi87, You can also try solution from issue #132. Or try netfx. Let me know about result.

@RayKoopa
Copy link

RayKoopa commented Feb 23, 2020

I could not get a .NET Standard 2.1 assembly to be callable from native code without access violations. Simply switching to .NET Standard 2.0 made it work, but only after I also set the following project properties, which I took from the Example repository (which is also only targeting .NET Standard 2.0):

  • DllExportOurILAsm to true
  • DllExportSysObjRebase to true
  • DllExportPatches to 1

@RayKoopa
Copy link

@3F I may have missed that info elsewhere, but is .NET Standard 2.1 even meant to be supported at this time? As said in my above comment, I could not get it to work, it only throws access violations when trying to call the exported functions from native code.

I can accept a sample project if you like.

@3F
Copy link
Owner

3F commented Feb 23, 2020

@RayKoopa,

Please read #132 as I mentioned above.

For today I implemented rebasing only for system objects: #125 (comment)
Others can be considered later: #132 (comment)

For better support and most known behavior with 1.7.0, netstandard2.0 or netcoreapp2.2 is recommended.

Follow the news!

@RayKoopa
Copy link

RayKoopa commented Feb 24, 2020

Thanks for the information! netcoreapp2.2 seems pretty fine for me right now as all I was missing in netstandard2.0 are several Span methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants