1
votes

I'm trying to access the Nikon image SDK(for those interested see: 1) to implement access to *.nef file in a programm. I'm stuck at a return code from the dll which should be interpreted as "invalid parameter" and I'm running out of ideas.

Yes I know the chance, that somebody is exactly using this dll is sparse, but I'm rather looking for "writing"/"thinking" errors... I'm still learning (so excuse to any wrong used terms, etc...) and also for this reason this is a little "longer" post (some "aloud thinking" on my side ;-) )

1.) the dll has an entry function where you pass a identifier and a struct as parameter. The identifier stands for a specific command (like open,close,etc....). The struct is used for data exchange with the camera.

2.) I do have everything together and working (since, I'm getting a "return code") but I can't figure out the reason for the return code (maybe some datatype is incompatible?)

So first the "C++"-part:

c++ function definition:

extern "C" unsigned long __declspec(dllexport) WINAPI Nkfl_Entry(unsigned long ulCommand, void* pParam );

this is stdcall, so I do need to worry about any further options to dllimport, since usigned long(c++) corresponds to uint(c#) i get two uints one "out" and one "in"...

c++ struct defintion:

typedef struct tagNkflLibraryParam
{
     unsigned long  ulSize;         // Size of structure
     unsigned long  ulVersion;      // Version
     unsigned long  ulVMMemorySize;     // Size of vertual memory
     NkflPtr* pNkflPtr;                 // Pointer of StratoObject
     unsigned char  VMFileInfo[ MAX_PATH ]; // Swap file info
} NkflLibraryParam, *NkflLibraryPtr;

so I do need to pass 3 times uints, one pointer to an "StratoObject" ((1.) the doc says "typedef void* NkflPtr" so this is "just" a void* pointer 2.) the doc says if this is zero it will be filled up by the sdk) and finally one byte (since unsigned char(c++) corresponds to byte(c#)).

So first question: Is this correct?

Then going to the "coding-part":

c# struct defintion:

namespace NikonStruct
{
    [StructLayout(LayoutKind.Sequential)]
    public struct NkflLibraryParam
    {
        public uint ulSize;          // size of the NkflLibraryParam structure
        public uint ulVersion;       // version number of the interface specification
        public uint ulVMMMemorySize; // upper limit of the physical memory that can be used
        public IntPtr pNkflPtr;      // pointer to the StratoManager object
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
        public byte[] VMFileInfo;      // swap file information
    }
}

now this should correspond to my defintions above...

c# Program class:

class Program
{
    public enum eNkflCommand : int
    {
        kNkfl_Cmd_OpenLibrary = 1,
        kNkfl_Cmd_CloseLibrary = 2,
    };

    [DllImport("NkImgSDK.dll", EntryPoint = "Nkfl_Entry")]
    public static extern uint kNkfl_Cmd_OpenLibrary(eNkflCommand ulCommand, ref NikonStruct.NkflLibraryParam data);

    [DllImport("NkImgSDK.dll", EntryPoint = "Nkfl_Entry")]
    public static extern uint kNkfl_Cmd_CloseLibrary(eNkflCommand ulCommand, IntPtr close);

    static void Main(string[] args)
    {
        try
        {
            // specify return value of entry function
            uint result1, result2;

            /// call the kNkfl_Cmd_OpenLibrary Function 
            // generate data structure, which is used to communicate with kNkfl_Cmd_OpenLibrary function
            NikonStruct.NkflLibraryParam _NkflLibraryParam = new NikonStruct.NkflLibraryParam();
            // fill the fields of _NkflLibraryParam structure for kNkfl_Cmd_OpenLibrary function
            _NkflLibraryParam.ulVersion = 16777216;
            _NkflLibraryParam.ulSize = ((uint)Marshal.SizeOf(_NkflLibraryParam)); ;
            // call the entry function with parameters for kNkfl_Cmd_OpenLibrary 
            result1 = kNkfl_Cmd_OpenLibrary(eNkflCommand.kNkfl_Cmd_OpenLibrary, ref _NkflLibraryParam);

            Console.WriteLine(result1);

            /// call the kNkfl_Cmd_CloseLibrary Function
            result2 = kNkfl_Cmd_CloseLibrary(eNkflCommand.kNkfl_Cmd_CloseLibrary, IntPtr.Zero);

            Console.WriteLine(result2);
        }
        catch
        {
            string errorMsg = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()).Message;
            throw new ArgumentException(errorMsg);
        }
    }
}

So nothing specific here:

  • eNkflCommand is from the doc
  • the structure is passed by reference so ref...
  • the "close" function expects "null pointer" (according to doc)
  • ulVersion is 0x01000000 (according to doc)
  • all other struct values are not set (and are zero by default if I understood the clr doc correctly)

Compiles and runs as already mentioned but result1 returns wrong "status-code" which translates to "invalid param" as already mentioned.

Any help appreciated....

1
I don't know if you mention it in your post, but why are you only setting ulVersion and ulSize in your struct? Are the other parameters not necessary?jszigeti
@jszigeti: <snip>(...) all other struct values are not set (and are zero by default if I understood the clr doc correctly) (...)</snap> :-)Resu
Another shot in the dark: are you able to test this code in C++ to confirm that the SDK is actually operational? (and more importantly, that it works the way you think it does)jszigeti
@jszigeti: haven't done that (yet...) - "hoped" for some kind of typo or the like...Resu
VMFileInfo clearly does not match. Why did you do that?David Heffernan

1 Answers

2
votes

FOUND IT:

never trust a documentation of a software developer: there was actually a missing parameter (not declared in the documentation BUT in an additional header definition file which was in another sub-directory of the sdk-package...)

so actually the struct defintion in the c# should be:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct struktur
{
    public uint ulSize;          // size of the NkflLibraryParam structure
    public uint ulVersion;       // version number of the interface specification
    public uint ulVMMMemorySize; // upper limit of the physical memory that can be used
    public IntPtr pNkflPtr;      // pointer to the StratoManager object
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
    public byte[] VMFileInfo;      // swap file information
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
    public byte[] DefProfPath; // <- this one is not included in the doc of NIKON (I still don't now what this should hold but it works if it's empty...)
}

Thanks to jszigeti and DavidHeffernan for trying...