'"InvalidParam" result when calling the Nikon Image SDK "OpenSession" command from C#
I'm trying to implement the Nikon Image SDK, which is a dll, from C# so I can read and manipulate their NEF raw image files. I have successfully implemented their dlls (separate camera SDK) to connect to my camera and read images directly from it, and now I'm trying to use the Image SDK to edit the images after importing to the computer.
The SDK has an "entry point" method that you call, and pass a command and a pointer to a data object that differs depending on the command:
unsigned long Nkfl_Entry( unsigned long ulCommand, void* pData )
Per Nikon's documentation, first you call the "OpenLibrary" command, which I can do successfully using this entry point from C# and structs based on their c header file (This question PInvoke Nikon c++ DLL Function from c# helped me open the library successfully):
[DllImport("NkImgSDK.dll", EntryPoint = "Nkfl_Entry")]
public static extern ReturnCode kNkfl_Cmd_OpenLibrary(ImageSDKCommand ulCommand, ref NkflLibraryParam data);
public unsafe struct NkflLibraryParam
{
public UInt32 ulSize; // Size of structure
public UInt32 ulVersion; // Version
public UInt32 ulVMMemorySize; // Size of vertual memory
public IntPtr pNkflPtr; // Pointer of StratoObject //IntPtr=void*
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAX_PATH)]
public byte[] VMFileInfo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAX_PATH)]
public byte[] DefProfPath;
}
public ReturnCode OpenLibraryAsync()
{
NkflLibraryParam nkflLibraryParam = new NkflLibraryParam();
nkflLibraryParam.ulSize = (uint)Marshal.SizeOf(nkflLibraryParam);
nkflLibraryParam.ulVersion = 0x01000000;
nkflLibraryParam.VMFileInfo = new byte[260];
Encoding.ASCII.GetBytes("VMFile.dat").CopyTo(nkflLibraryParam.VMFileInfo, 0);
nkflLibraryParam.pNkflPtr = IntPtr.Zero;
ReturnCode returnCode = kNkfl_Cmd_OpenLibrary(
ImageSDKCommand.OpenLibrary,
ref nkflLibraryParam
);
Debug.Print($"OpenLibrary: {returnCode}");
return returnCode;
}
Notes about the above:
- I created the "ReturnCode" enum used in the entry point, and it marshals successfully.
- The "VMFile.dat" file gets created in the working folder, so I know the SDK has opened the library successfully
Per the documentation, after opening the library, you call the "OpenSession" command to open an image for manipulation. This is what is failing with return code "InvalidParam":
[DllImport("NkImgSDK.dll", EntryPoint = "Nkfl_Entry")]
public static extern ReturnCode kNkfl_Cmd_OpenSession(ImageSDKCommand ulCommand, ref NkflSessionParam data);
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Ansi)]
public unsafe struct NkflSessionParam
{
public UInt32 ulSize; // Size of structure
public UInt32 ulSessionID; // ID value of session
public UInt32 ulType; // File type (eNkflSource)
public IntPtr pFileInfo; // File Name or file Memory //IntPtr=void*
public UInt32 ulFileSize; // Memory size
}
public enum eNkflSource : UInt32
{
FileName = 0x0001, //kNkfl_Source_FileName
//FSSpec = 0x0002, //kNkfl_Source_FSSpec //deprecated, Mac only
Memory = 0x0004, //kNkfl_Source_Memory
FileName_UTF8 = 0x0008,// SDK-319: Added for Win //kNkfl_Source_FileName_UTF8
}
public unsafe ReturnCode OpenSession(string fileLocation)
{
var sessionParam = new NkflSessionParam();
sessionParam.ulSize = (uint)Marshal.SizeOf(sessionParam);
sessionParam.ulType = (UInt32)eNkflSource.FileName;
ReturnCode returnCode;
byte[] fileNameBytes = new byte[260];
Encoding.ASCII.GetBytes(fileLocation).CopyTo(fileNameBytes, 0);
var fileNameHandle = GCHandle.Alloc(fileNameBytes, GCHandleType.Pinned);
try
{
sessionParam.pFileInfo = fileNameHandle.AddrOfPinnedObject();
//>>>>>>>>>> THIS IS WHERE I GET InvalidParam <<<<<<<<<<<<<<<<<<<<
returnCode = kNkfl_Cmd_OpenSession(
ImageSDKCommand.OpenSession,
ref sessionParam
);
}
finally
{
fileNameHandle.Free();
}
Debug.Print($"OpenSession: {returnCode}");
if (returnCode == ReturnCode.None)
_openImageSessions.Add((uint)returnCode);
return returnCode;
}
Here is the Nikon documentation for the OpenSession command:
kNkfl_Cmd_OpenSession
This command establishes a session for a specified image file. When issuing this command, an application must perform the following settings. If the file cannot be found, the Image SDK Library returns kNkfl_Code_Err_FileNotFound.
Setting of the Entry function parameter
ulCommand: kNkfl_Cmd_OpenSession
pData: Pointer to the NkflSessionParam structure
Setting of the NkflSessionParam structure
ulSize: Size of this structure
ulType: Method of specifying the target image file. Specify one from among eNkflSource.
pFileInfo: Image file information. The contents differ according to ulType. When ulType is kNkfl_Source_FileName or kNkfl_Source_FileName_UTF8, a pointer to the image file name should be set in pFileInfo. When ulType is kNkfl_Source_FSSpec, the AliasHandle of the image file should be set in pFileInfo. When ulType is kNkfl_Source_Memory, a pointer to the image file on the memory should be set.
ulFileSize: Size of the image file. This field needs to be set when ulType is kNkfl_Source_Memory.
The Image SDK Library establishes a session for the specified file. The following value will be returned to the application.
ulSessionID: ID value of the established session.
* This command returns kNkfl_Code_Warn_ OptionalPictureControlNotApplicable when you issue to NEF applied OPC which is not installed. But there is no problem in the work. In this case, this library applys the default condition of “Standard” in PictureControl instead of OPC to NEF.
Notes:
* When you issue this command to NEF, which is shot with “D2XMODE”, with “Latest” color reproduction process, kNkfl_Code_Warn_D2XmodeNotApplicable is returned and “Standard” is applied instead of “D2XMODE”.
* A setting of kNkfl_Source_FSSpec is invalid from Ver.1.11. When you set kNkfl_Source_FSSpec, kNkfl_Code_Err_InvalidParam is returned.
* When kNkfl_Source_FileName is set, the file name is encoded in ANSI in Windows version and UTF-8 in Mac version.
* Returns kNkfl_Code_Err_NotSupported when issued to a High efficiency compressed NEF on a 32-bit version of Windows.
Things I have tried:
- calling with ulType = Filename, Filename_UTF8 and using the matching charater engodings for the string
- using Memory and passing the ulFileSize parameter (different version of the C# OpenSession method where I load the image bytes before calling and pass the pointer)
- putting the image file in the same folder as the exe, and using a full path to the image file (it's a NEF, which is the Nikon raw image format), and just the bare file name which presumably reads from the current folder because passing a bare file name to VMFileInfo during OpenLibrary creates the VM file in the working folder
- getting the pointer to the file name into pFileInfo in various ways, including Marshal.StringToHGlobalAnsi, Marshal.StringToHGlobalUni, GCHandle.AddrOfPinnedObject, etc, but I know the method used in the snippet I'm using works for passing the VMFileInfo for OpenLibrary so I'm sticking with that and assuming that's not the issue
- using a pointer to managed memory and unmanaged memory for pFileInfo
- using a pointer to a fixed length byte array for pFileInfo (as in the current version of the method I posted here) as well as a pointer to the string from Marshal.StringToHGlobalAnsi/Marshal.StringToHGlobalUni
- Calling OpenSession without calling OpenLibrary first, just to see if I get a different result code
- different ways of invoking the external Entry method (which all work for calling the OpenLibrary command), including:
var entryPointPointer = Kernel32.GetProcAddress(_sdkLibraryHandle, _defaultSDKEntryPointName);
if (entryPointPointer == IntPtr.Zero)
{
throw new Exception($"Failed to find the SDK entry point \"{_defaultSDKEntryPointName}\" in the file \"{_sdkFile}\".");
}
_sdkEntryPoint = (ImageSDKEntryDelegate)Marshal.GetDelegateForFunctionPointer(entryPointPointer, typeof(ImageSDKEntryDelegate));
...
//data = IntPtr
_sdkEntryPoint(command, data)
The correct result would return the result code "None", but the only result code I get is InvalidParam regardless of what I try. I never get FileNotFound or NotSupported or Unexpected, and the call never raises an exception.
The only other related post I can find is this Cant get Nikons Raw SDK to load in Production environment but it doesn't appear to help me.
Does anyone have any experience with this SDK who can point me in the right direction??
Thanks in advance
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
