native dll

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von MaikN.

    Hallo,
    ich versuche grade eine externe, vermutlich native dll, in ein Programm zur Farbtonmessung einzubinden. Die "eXact.dll" wurde vom Messgerätehersteller bereitgestellt. Leider kommt immer ein Fehler den ich nicht weg bekomme. Ich habe alternative mal ein bisschen mit der "kernel32.dll" probiert, diese funktioniert.
    Hier erstmal mein Code.

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. Private Const DllPath As String = "kernel32.dll"
    4. Private Const DllPath_eXact As String = "C:\Users\xxx\source\repos\Xrite_DLL_Test\eXact.dll"
    5. ' Import der nativen DLL
    6. <DllImport(DllPath_eXact, CallingConvention:=CallingConvention.StdCall)>
    7. Private Shared Function _Connect() As Boolean
    8. End Function
    9. <DllImport(DllPath_eXact, CallingConvention:=CallingConvention.StdCall)>
    10. Private Shared Function _GetSerialNum() As String
    11. End Function
    12. <DllImport(DllPath_eXact, CallingConvention:=CallingConvention.Cdecl)>
    13. Private Shared Function SetOption(setting As String, Wert As String) As Integer
    14. End Function
    15. ' Importieren der Funktion "GetTickCount" aus der DLL
    16. <DllImport(DllPath, CallingConvention:=CallingConvention.StdCall)>
    17. Private Shared Function GetTickCount() As UInteger
    18. End Function
    19. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    20. 'läuft..............
    21. Dim tickCount As UInteger = GetTickCount()
    22. 'Dim result_string As String = _GetSerialNum()
    23. Dim result_bool As Boolean = _Connect()
    24. Dim username As String = Space(255)
    25. Dim result As Integer = GetUsername(username, 255)
    26. Stop
    27. 'Dim result As Integer = SetOption("Reading_Mode", "Pressure")
    28. ' Verarbeiten des Ergebnisses (z. B. Fehlerbehandlung)
    29. If result Then
    30. Console.WriteLine("Verbindung erfolgreich hergestellt.")
    31. Else
    32. Console.WriteLine("Verbindung fehlgeschlagen.")
    33. End If
    34. End Sub
    35. End Class


    Beim Aufruf von _connect kommt die Fehlermeldung

    An attempt was made to load a program with an incorrct format.

    Ich habe auch noch ein Beispielprogramm in C++ (2010) dabei, dies läuft aber leider bei mir nicht. Dies ist wohl die header Datei

    C-Quellcode

    1. #ifndef _SPECTRO_H_
    2. #define _SPECTRO_H_
    3. #include <Windows.h>
    4. typedef const char* _stdcall _GetInterfaceVersion(); // returns the interface version
    5. typedef bool _stdcall _Connect(); // connect to instrument
    6. typedef bool _stdcall _Disconnect(); // disconnect from instrument
    7. typedef bool _stdcall _IsConnected(); // returns connection status
    8. typedef int _stdcall _GetSpectralSetCount(); // number of spectral sets
    9. typedef int _stdcall _GetWavelengthCount(); // number of wavelengths
    10. typedef const char* _stdcall _GetSpectralSetName( int dataSet ); // string representation of spectral set
    11. typedef int _stdcall _GetWavelengthValue(int index); // returns the Wavelength in nm (ex. 400 for index=0)
    12. typedef const char* _stdcall _GetCalibrationStandard(); // string representation of calibration standard
    13. typedef bool _stdcall _Measure(); // commands instrument to take a measurement
    14. typedef float _stdcall _GetSpectralData(int angle, int wl); // returns current measurement value for the specified angle and wavelengh indexes
    15. typedef bool _stdcall _IsDataReady(); // returns measurement status (TRUE after measurment is taken)
    16. typedef const char* _stdcall _GetSerialNum(); // returns instrument Serial Number
    17. typedef int _stdcall _GetCalStatus(); // returns calibration status (0 = calibrated)
    18. typedef const char* _stdcall _GetCalSteps(); // returns a list of calibration steps
    19. typedef const char* _stdcall _GetCalMode(); // returns calibration trigger mode ("Software" or "Device")
    20. typedef bool _stdcall _CalibrateStep(const char* calstep); // performs the specified calibration step
    21. typedef int _stdcall _GetCalProgress(); // check progress of asynchronous calibration step
    22. typedef bool _stdcall _AbortCalibration(); // abort calibration
    23. typedef bool _stdcall _ClearSamples(); // clears all existing Samples in the instrument
    24. typedef int _stdcall _GetSampleCount(); // returns count of stored samples
    25. typedef bool _stdcall _SetCurrentSample( int sample ); // makes the specified sample active order to retrieve its data
    26. typedef float _stdcall _GetSampleData( int angle, int wl ); // returns value for the specified angle and wavlength of the active stored sample
    27. typedef const char* _stdcall _GetAvailableSettings(); // returns a list of available settings
    28. typedef const char* _stdcall _GetSettingOptions(const char* setting); // returns a list of options for the specified settings
    29. typedef const char* _stdcall _GetOption(const char* setting); // returns the current option for the specified settings
    30. typedef bool _stdcall _SetOption(const char* setting, const char* option); // sets the current option for the specified setting
    31. typedef int _stdcall _GetLastErrorCode(); // retrieves the last error code as an integer
    32. typedef const char* _stdcall _GetLastErrorString(); // retrieves the last error as a string (in language selected by SetLanguage function)
    33. typedef const char* _stdcall _Execute( const char* cmdString ); // executes a task or function specified by a string
    34. // an empty returned string ("") indicates an error.
    35. // call GetLastErrorCode() or GetLastErrorString() for more information
    36. typedef long _stdcall _ExecuteBinary( // General purpose function similar to "Execute", but allowing for
    37. const char* inputBuffer, // binary data to be sent and/or received: return value is number of bytes received.
    38. long inputLength, // The caller is responsible for all memory management.
    39. long timeout,
    40. char* outputBuffer,
    41. long outputBufferSize );
    42. /////////////////////////////////////////////////////////////////////
    43. // interface additions for Scanning support
    44. enum SCANSTATUS
    45. {
    46. SCANERROR = -1,
    47. IDLE = 0,
    48. READYTOSCAN = 1,
    49. SCANINPROGRESS = 2,
    50. SCANCOMPLETE = 3,
    51. PAPERINPROGRESS = 4,
    52. PAPERCOMPLETE = 5
    53. };
    54. typedef bool _stdcall _ScanIsSupported();
    55. typedef bool _stdcall _ScanConfig( int patchCount, float patchWidth );
    56. typedef bool _stdcall _ScanStart();
    57. typedef bool _stdcall _ScanAbort();
    58. typedef int _stdcall _ScanGetStatus();
    59. typedef int _stdcall _ScanGetCount();
    60. typedef const char* _stdcall _ScanGetData( int patchIndex, int dataSet );
    61. class Spectro
    62. {
    63. private:
    64. HMODULE m_hLib;
    65. void Init();
    66. public:
    67. _GetInterfaceVersion* GetInterfaceVersion;
    68. _Connect* Connect;
    69. _Disconnect* Disconnect;
    70. _IsConnected* IsConnected;
    71. _GetSpectralSetCount* GetSpectralSetCount;
    72. _GetWavelengthCount* GetWavelengthCount;
    73. _GetSpectralSetName* GetSpectralSetName;
    74. _GetWavelengthValue* GetWavelengthValue;
    75. _GetCalibrationStandard* GetCalibrationStandard;
    76. _Measure* Measure;
    77. _GetSpectralData* GetSpectralData;
    78. _IsDataReady* IsDataReady;
    79. _GetSerialNum* GetSerialNum;
    80. _GetCalStatus* GetCalStatus;
    81. _GetCalSteps* GetCalSteps;
    82. _GetCalMode* GetCalMode;
    83. _GetCalProgress* GetCalProgress;
    84. _AbortCalibration* AbortCalibration;
    85. _CalibrateStep* CalibrateStep;
    86. _ClearSamples* ClearSamples;
    87. _GetSampleCount* GetSampleCount;
    88. _SetCurrentSample* SetCurrentSample;
    89. _GetSampleData* GetSampleData;
    90. _GetAvailableSettings* GetAvailableSettings;
    91. _GetSettingOptions* GetSettingOptions;
    92. _GetOption* GetOption;
    93. _SetOption* SetOption;
    94. _GetLastErrorCode* GetLastErrorCode;
    95. _GetLastErrorString* GetLastErrorString;
    96. _Execute* Execute;
    97. _ExecuteBinary* ExecuteBinary;
    98. _ScanIsSupported* ScanIsSupported;
    99. _ScanConfig* ScanConfig;
    100. _ScanStart* ScanStart;
    101. _ScanAbort* ScanAbort;
    102. _ScanGetStatus* ScanGetStatus;
    103. _ScanGetCount* ScanGetCount;
    104. _ScanGetData* ScanGetData;
    105. Spectro()
    106. {
    107. Init();
    108. };
    109. ~Spectro()
    110. {
    111. FreeDLL();
    112. }
    113. bool IsLoaded()
    114. {
    115. return (m_hLib != NULL);
    116. };
    117. const char* InterfaceVersion()
    118. {
    119. if( GetInterfaceVersion == NULL )
    120. return "1.1";
    121. else
    122. return GetInterfaceVersion();
    123. }
    124. bool LoadDLL(LPCTSTR dll);
    125. void FreeDLL();
    126. };
    127. #endif // _SPECTRO_H_


    Kennt sich damit jemand aus und kann mir helfen die dll richtig anzusprechen?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „MaikN“ ()

    MaikN schrieb:

    An attempt was made to load a program with an incorrct format.


    Was ist das für eine DLL? Also x64, x86? Falls dein Project AnyCPU ist, stell dein Projekt auf die Architecture der DLL um, bzw. stell die bevorzugte VAriante für AnyCPU ein.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Ist das die einzige Header-Datei? Gibt es eine LIB Datei?

    Mach mal eine Entwicklerkonsole(Developer Command Prompt) aus dem Studio heraus auf und gebe das ein, passe Pfade aber an!

    Quellcode

    1. dumpbin /exports eXact.dll

    Dann kannst du sehen, ob und welche Symbole exportiert werden.

    Die Fehlermeldung "An attempt was made to load a program with an incorrect format", bzw. die Exception BadImageFormatException kommen vor wenn man eine x64 DLL in einem x86 Programm laden will, andersrum natürlich auch.

    Hast du dein Projekt mal auf x64 und mal mit x86 kompiliert und das versucht? Oder hast du AnyCPU verwendet. Bei AnyCPU kann man festlegen was man bevorzugt, das sollte dann eigendlich gehen. Ich kompiliere nur noch mit x64, ausser es muss auf einem alten Rechner laufen wo die CPU noch 32 Bit ist, deshalb kann ich dir nicht sagen ob es evtl. PRobleme mit AnyCPU gibt.

    Wenn dir nur AnyCPU vorgeschlagen wird, füge x64 und oder x86(win32) selbst hinzu.

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „DTF“ ()

    MaikN schrieb:

    ich habe beide Versionen.
    Meinst Du, Du hast sowohl eine x86- als auch eine x64-Variante der nativen DLL?
    Dann musst Du im PostBuild-Step dafür sorgen, dass die richtige DLL neben der richtigen Exe zu liegen kommt.
    Zippe mal Dein Projekt und die DLLs, aber ohne die obj-, bin- und vs-Verzeichnisse und häng das ZIP an einen Post.
    Erweiterte Antwort => Dateianhänge => Hochladen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Also diese exact.dll hab ich mir mal besorgt und auf einer Testmaschine ausprobiert. Sowohl die x86, wie auch die x64 Variante konnte ich mit AnyCPU nutzen. Siehe in den Anhängen, lief bis zum Haltepunkt das Programm. Mach einen rechtsklick im Projektmappenexplorer auf das Projekt(nicht die Projektmappe) und dann eigenschaften. Unter Build kannst du das einstellen. Dann musst du nur die richtige DLL dll laden. Wenn du einfach die DLL neben der exe hast, kannste den kompletten Pfad sparen(beim DLL Import).
    Bilder
    • Unbenannt.jpg

      81,44 kB, 673×642, 45 mal angesehen
    • Unbenannt1.jpg

      53,59 kB, 708×354, 48 mal angesehen
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Danke an DTF und RodFromGermany für eure Hinweise und Lösungsansätze. Jetzt bekomme ich eine Connection zum Messgerät hin. Sieht momentan so aus das ich einen Fehler in der dll Version und der Einstellung im Programm hatte. Arbeite jetzt mit der 64bit Version und x64 als Ziel CPU. Hoffe das der Rest jetzt besser läuft, sonst melde ich mich nochmal ;)
    Soweit funktioniert das schon sehr gut...
    Aber natürlich nicht alles. Diese Function geht reibungslos

    VB.NET-Quellcode

    1. <DllImport(DllPath_eXact, CallingConvention:=CallingConvention.StdCall)>
    2. Private Shared Function GetWavelengthValue(wl As Integer) As Integer
    3. End Function
    4. Public ReadOnly Property _GetWavelengthValue(wl As Integer) As Integer
    5. Get
    6. Return GetWavelengthValue(wl)
    7. End Get
    8. End Property


    Diese bricht immer ohne Meldung das Programm ab.

    VB.NET-Quellcode

    1. <DllImport(DllPath_eXact, CallingConvention:=CallingConvention.StdCall)>
    2. Private Shared Function Execute(CmdString As String) As String
    3. End Function
    4. Public ReadOnly Property _Execute(CmDString As String) As String
    5. Get
    6. Return Execute(CmDString)
    7. End Get
    8. End Property


    Denke das es mit dem String zu tun hat, was aber leider nicht warum. Kennt dieses Problem jemad?
    @MaikN Sieh mal hier rein, da habe ich ne ganze Menge Möglichkeiten der String-Deklaration aufgelistet:
    Austausch von Daten zwischen einer VB.NET-exe und einer C-DLL, 32 und 64 Bit
    Und: _Execute sollte keine Property sein, sondern eine Function.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Danke für die Info's.
    Ich habe das nun folgendermaßen gelöst

    VB.NET-Quellcode

    1. <DllImport(DllPath_eXact)>', CallingConvention:=CallingConvention.StdCall)>
    2. Public Shared Function Execute(ByVal values As String) As IntPtr
    3. End Function
    4. Dim input As String = "instrument get name"
    5. Dim resultPointer As IntPtr = eXact.Execute(input)
    6. Dim resultString As String = Marshal.PtrToStringAnsi(resultPointer)


    Und nun wird der Gerätename entsprechend zurückgegeben :P .