I'm attempting to call a method on the ssdeep fuzzy.dll
The .h file is here and a friendly reference is here
Specifically, I'm trying to call this method....
int fuzzy_hash_filename (
const char * filename,
char * result
)
I've got the following...
<DllImport("C:\SSDeep\Fuzzy.dll", EntryPoint:="fuzzy_hash_filename")>
Private Shared Function fuzzy_hash_filename(
<InAttribute(),
MarshalAsAttribute(UnmanagedType.LPStr)>
ByVal Filename As String, ByVal Result As StringBuilder) As Integer
End Function
Public Shared Function FuzzyHash(Filename As String) As String
Dim Ret As New StringBuilder
Ret.Capacity = NativeConstants.FUZZY_MAX_RESULT
Dim Success = fuzzy_hash_filename(Filename, Ret)
If Success <> 0 Then
Throw New Exception("SSDeep fuzzy hashing failed")
End If
Return Ret.ToString
End Function
If I run this code, VS gives me a modal dialogue
A call to PInvoke function '(Blah)::fuzzy_hash_filename' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
(FWIW The call seems to succeed if I ignore the warning so I must be close)
What change do I need to make to my definition to get this going?
I found someone that had the same issue on MSDN forums:
Concerning the PInvokeStackImbalance.
1.1 This is usually due to mismatch of the calling convention used by the API and that declared for the API in the C# code.
1.2 By default, if the CallingConvention argument for the DllImportAttribute is not set, then StdCall is used by default.
1.3 If the DoSomething() API is to use __cdecl (as is the default in C++ projects), then you should use the following declaration for
DoSomething() in the C# code : [DllImport(#"dll.dll",
CallingConvention=CallingConvention.Cdecl)]
1.4 Also, I suggest that you declare the API as extern "C" otherwise it will be subject to name mangling by the C++ compiler.
The accepted answer appears to have solved the original asker's problem, but the equivalent code in c# did not work for me. After trying increasingly complex annotations, going back to basics eventually did work. For everyone's reference, I include the declaration for three of the interface functions and working code (built against ssdeep version 2.9).
//Note: StringBuilder here is the standard way to do it, but is a perf hit because unicode stringbuilder can't be pinned when martialling char*.
//See http://msdn.microsoft.com/en-us/magazine/cc164193.aspx#S4
//int fuzzy_hash_buf(const unsigned char *buf, uint32_t buf_len, char *result)
[DllImport("fuzzy.dll")]
public static extern int fuzzy_hash_buf(StringBuilder buf, int buf_len, StringBuilder result);
//int fuzzy_hash_filename(const char* filename, char* result)
[DllImport("fuzzy.dll")]
static extern int fuzzy_hash_filename(string filename, StringBuilder result);
//int fuzzy_compare (const char *sig1, const char *sig2)
[DllImport("fuzzy.dll")]
static extern int fuzzy_compare(string sig1, string sig2);
static void Main(string[] args)
{
StringBuilder buf = new StringBuilder("test");
StringBuilder result0 = new StringBuilder(150);
fuzzy_hash_buf(buf, 4, result0);
Console.WriteLine(result0);
string filename = "test.txt";
StringBuilder result1 = new StringBuilder(150);
fuzzy_hash_filename(filename, result1);
Console.WriteLine(result1);
int matchScore = fuzzy_compare(result0.ToString(), result1.ToString());
Console.WriteLine("MatchScore: " + matchScore);
}
Output:
ssdeeptest.exe
3:Hn:Hn
24:gRnIM7stweRp+fEWU1XRk+/M98D6Dv3JrEeEnD/MGQbnEWqv3JW:gRIMwtrMU1Bk2I3Jrg53JW
MatchScore: 0
Related
I'm trying to call a native Windows API from managed C++/CLI. One of the arguments is a void**. The idea is that the function will allocate a memory structure and return a void pointer to the caller, which should be passed back to the API on the next call. So I need to allocate storage for a pointer on the managed side and pass a reference to the C API. I can't figure out how to do this.
I've tried declaring a void * in the caller and passing a reference via various operators: &, internal_ptr<>, pin_ptr<>. I did the same with an IntPtr. I get errors saying the compiler can't convert this to a void**.
Here's one attempt using IntPtr and pin_ptr. I get the following compile error on line 28 (the line that declares the pin_ptr):
E0144 a value of type "interior_ptr<System::IntPtr>" cannot be used to initialize an entity of type "cli::pin_ptr<void *>"
#include <msclr\marshal.h>
using namespace msclr::interop;
using namespace System;
namespace CLRStorage
{
public ref class CompoundFile
{
private:
String ^ pathname;
IntPtr pRootStorage;
public:
CompoundFile CompoundFile::Create(String^ path)
{
STGOPTIONS stgOptions;
stgOptions.usVersion = 1;
stgOptions.reserved = 0;
stgOptions.ulSectorSize = 4096;
stgOptions.pwcsTemplateFile = NULL;
auto cf = gcnew CompoundFile();
cf->pathname = path;
marshal_context^ context = gcnew marshal_context();
pin_ptr<void*> ppRootStorage = &cf->pRootStorage;
StgCreateStorageEx(
context->marshal_as<WCHAR*>(path),
STGM_READWRITE & STGM_CREATE,
STGFMT_DOCFILE,
0,
&stgOptions,
NULL,
IID_IStorage,
ppRootStorage);
}
};
}
IntPtr can be converted to and from void*, but it isn't the same type.
Since the parameter is out-only, the simple solution is just to use a temporary:
void* pRootStorage;
StgCreateStorageEx(
context->marshal_as<WCHAR*>(path),
STGM_READWRITE & STGM_CREATE,
STGFMT_DOCFILE,
0,
&stgOptions,
NULL,
IID_IStorage,
&pRootStorage);
cf->pRootStorage = IntPtr(pRootStorage);
This will actually be a tiny bit faster as well, because no pinning is needed.
You also have a separate problem with bad member function syntax. You want
static CompoundFile^ Create(String^ path)
instead of
CompoundFile CompoundFile::Create(String^ path)
and don't forget to
return cf;
Then, marshal_context is not a ref class, so this line is wrong:
marshal_context^ context = gcnew marshal_context();
Instead use
marshal_context context;
and since it is not a pointer,
context.marshal_as<WCHAR*>(path)
I have a "CLock.dll" have some functions
For example: This is document for a function
__int16 __stdcall dv_get_auth_code(unsigned char* auth);
Function
To gain authorization code of setup card.
Parameters
auth:[out] Return authorization code, 6 characters.
Return
Succeed then return 0.
I need to call this dll in my winform application. I try
[DllImport("CLock.dll",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int dv_get_auth_code([Out]StringBuilder auth);`
and in Main()
My code:
StringBuilder sb = new StringBuilder();
int result = dv_get_auth_code(sb);
But it's working. What should i do? Thank you and have a nice day !
There are two mistakes in the code as presented. The return type is wrong, and no buffer is allocated.
The return type is a 16 bit type, in C# that is short:
[DllImport("Clock.dll")]
public static extern short dv_get_auth_code(StringBuilder auth);
Then to call the function you need to allocate a buffer. I don't know how large that buffer should be, presumably you know that.
StringBuilder sb = new StringBuilder(bufferLengtg);
short result = dv_get_auth_code(sb);
It is always wise for such an API to pass the length of the buffer to the function. Then it can make sure it does not overrun the buffer.
Is there any way to use the Interlocked.CompareExchange(); and Interlocked.Increment(); methods against values stored in a memory-mapped file?
I'd like to implement a multi-threaded service that will store its data in a memory-mapped file, but since it's multi-threaded I need to prevent conflicting writes, therefore I wonder about the Interlocked operations rather than using explicit locks.
I know it's possible with native code, but can it be done in managed code on .NET 4.0?
OK, this is how you do it! We had to figure this out, and I figured we could give some back to stackoverflow!
class Program
{
internal static class Win32Stuff
{
[DllImport("kernel32.dll", SetLastError = true)]
unsafe public static extern int InterlockedIncrement(int* lpAddend);
}
private static MemoryMappedFile _mmf;
private static MemoryMappedViewStream _mmvs;
unsafe static void Main(string[] args)
{
const int INT_OFFSET = 8;
_mmf = MemoryMappedFile.CreateOrOpen("SomeName", 1024);
// start at offset 8 (just for example)
_mmvs = _mmf.CreateViewStream(INT_OFFSET, 4);
// Gets the pointer to the MMF - we dont have to worry about it moving because its in shared memory
var ptr = _mmvs.SafeMemoryMappedViewHandle.DangerousGetHandle();
// Its important to add the increment, because even though the view says it starts at an offset of 8, we found its actually the entire memory mapped file
var result = Win32Stuff.InterlockedIncrement((int*)(ptr + INT_OFFSET));
}
}
This does work, and works across multiple processes! Always enjoy a good challenge!
TravisWhidden, actually you can use Interlocked.Increment Static method as dan-gph said, you just have to be careful with pointer casting and operator priority, plus parenthesis usage, in facts...
You'll cast a memory pointer (plus the desired offset), into a pointer to an int variable, then you'll use that pointer as a variable. Then you'll have to use it as a variable reference.
Below you'll find the corresponding snippet of yours using .net library instead of external static import.
P&L
class Program
{
private static MemoryMappedFile _mmf;
private static MemoryMappedViewStream _mmvs;
static void Main(string[] args)
{
const int INT_OFFSET = 8;
_mmf = MemoryMappedFile.CreateOrOpen("SomeName", 1024);
_mmvs = _mmf.CreateViewStream(INT_OFFSET, 4);
unsafe
{
IntPtr ptr = _mmvs.SafeMemoryMappedViewHandle.DangerousGetHandle();
Interlocked.Increment(ref (*((int*)(ptr + INT_OFFSET)))
}
}
}
In NTFS, I can prefix a path with the \\?\ character sequence to denote that it is a path that exceeds the 260-character limit; as such, the file system will interpret the path correctly and avoid raising PathTooLongException.
(see http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx#maxpath for more information)
Is there a .NET API that will prefix my path strings with this sequence, or am I stuck writing my own?
In essence, I am looking for a method that is equivalent to the following.
static string ToExtendedPath(string path)
{
if(Path.IsPathRooted(path))
{
return #"\\?\" + path;
}
return Path.Combine(#"\\?\", path);
}
No, there is no .NET API that translates a given "normal" path into the extended syntax. You have to roll your own (which is trivial, by the way).
Please note: As Cody Gray and Hans Passant mentioned, the .NET framework does not support long (extended) paths. If you want to work with them, you need to use the API directly. And not all API functions support long paths either. Generally, the low-level functions do. Consult the MSDN documentation.
What I have done is write wrapper functions for the relevant API functions (e.g. CreateFile) and call those wrappers instead of the .NET file system functions.
As, #helge-klein pointed out there is no .Net API to work around the limitation of 260 characters, that feature is totally OS dependant, some of which support a Registry based override of the 260 max_path limitation.
[Edit] DotNet 4.6.2 onwards support: System.IO.LongPath, Blog and sample
Windows 10 Creators Update has extended the kernel (and command prompt) to have MoveFileExW, but as is evident in the dotnetReferenceSource no use of the extended kernel is included in the DotNet Framework System.IO.File:
#if FEATURE_CORESYSTEM
[DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)]
[ResourceExposure(ResourceScope.Machine)]
private static extern bool MoveFileEx(String src, String dst, uint flags);
internal static bool MoveFile(String src, String dst)
{
return MoveFileEx(src, dst, 2 /* MOVEFILE_COPY_ALLOWED */);
}
#else // FEATURE_CORESYSTEM
[DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern bool MoveFile(String src, String dst);
#endif // FEATURE_CORESYSTEM
An example LinqPad program to wrap MoveFile (others can be found on pinvoke)
void Main()
{
//Create 3 files: in c:\temp\test\
//testsrc0.txt, testsrc1.txt and testsrc2.txt
//"\\?\UNC\server\share",
string src0File = #"\\?\UNC\127.0.0.1\c$\temp\test\testsrc0.txt";
string dst0File = #"\\?\UNC\127.0.0.1\c$\temp\test\testdst0.txt";
string dst0FileDotNet = #"c:\temp\test\testdst0.txt";
string src1File = #"\\?\c:\temp\test\testsrc1.txt";
string dst1File = #"\\?\c:\temp\test\testdst1.txt";
string dst1FileDotNet = #"c:\temp\test\testdst1.txt";
string src2File = #"\\?\\127.0.0.1\c$\temp\test\testsrc2.txt";
string dst2File = #"\\?\\127.0.0.1\c$\temp\test\testdst2.txt";
string dst2FileDotNet = #"c:\temp\test\testdst2.txt";
MoveFileEx(src0File, dst0File, MoveFileFlags.MOVEFILE_REPLACE_EXISTING);
System.IO.File.Exists(dst0File).Dump("File0 Exists");//FALSE
System.IO.File.Exists(dst0FileDotNet).Dump("File0 Exists");//TRUE
MoveFileEx(src1File, dst1File, MoveFileFlags.MOVEFILE_REPLACE_EXISTING);
System.IO.File.Exists(dst1File).Dump("File1 Exists");//FALSE
System.IO.File.Exists(dst1FileDotNet).Dump("File1 Exists");//TRUE
MoveFileEx(src2File, dst2File, MoveFileFlags.MOVEFILE_REPLACE_EXISTING);
System.IO.File.Exists(dst2File).Dump("File2 Exists");//FALSE
System.IO.File.Exists(dst2FileDotNet).Dump("File2 Exists");//FALSE - as missing UNC keyword
System.Runtime.InteropServices.Marshal.GetLastWin32Error().Dump("ERROR:");//3 == ERROR_PATH_NOT_FOUND
}
[Flags]
enum MoveFileFlags
{
MOVEFILE_REPLACE_EXISTING = 0x00000001,
MOVEFILE_COPY_ALLOWED = 0x00000002,
MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004,
MOVEFILE_WRITE_THROUGH = 0x00000008,
MOVEFILE_CREATE_HARDLINK = 0x00000010,
MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020
}
// Define other methods and classes here
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags);
Paths with a drive and UNC path need the keyword "UNC". \?\UNC\
can any body tell How to convert System::IntPtr to char* in managed c++
this is my main function
int main(void)
{
String* strMessage = "Hello world";
CManagedClass* pCManagedClass = new CManagedClass();//working
pCManagedClass->ShowMessage(strMessage);//working
****above said error here***
char* szMessage = (char*)Marshal::StringToHGlobalAnsi(strMessage);
CUnmanagedClass cUnmanagedClass; cUnmanagedClass.ShowMessageBox(szMessage);
Marshal::FreeHGlobal((int)szMessage);
return 0;
}
thanks in advance
I'm not a huge C++/CLI programmer, but the following should work just fine.
IntPtr p = GetTheIntPtr();
char* pChar = reinterpret_cast<char*>(p.ToPointer());
The IntPtr class has a method called ToPointer which returns the address as a void* type. That will be convertible to char* in C++/CLI.
EDIT
Verified this works on VS2008 and VS2015
Instead of
char* szMessage = (char*)Marshal::StringToHGlobalAnsi(strMessage).ToPointer();
Marshal::FreeHGlobal((int)szMessage);
Use
marshal_context conversions.
const char* szMessage = conversions.marshal_as<const char*>(strMessage);
It cleans itself up, the magic of C++ RAII.
Attention!
I want to add something to JaredPar answer.I don't know where your IntPtr is coming from but you should also use pin_ptr in order to prevent the garbage collector from messing up your memory. I did lot of CLR/Native inter op in the past and using pin_ptr is one of those things that I learnt to do in the hard way.
read the following:
click me