Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Hi,

I got a function with the following signature:

 

SCCRTN SccHistory(
 LPVOID pvContext,
 HWND hWnd,
 LONG nFiles,
 LPCSTR* lpFileNames,
 LONG fOptions,
 LPCMDOPTS pvOptions
);

 

(this function resides in SSSCC.DLL)

 

I can't figure out how should I pass the required array of file names from C# to the lpFileNames argument. Any help will be appreciated. Googling for "LPCSTR* C#" gives 1 or 2 meaningfull rezults, but no one of them helps :(

 

Thank you.

Posted

UnmanagedType.LPArray and UnmanagedType.LPStr

 

For the string array, try:

 

[MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] String[] lpFileNames

 

Good luck :cool:

Never trouble another for what you can do for yourself.
Posted

Thanks, it works!

 

Meanwhile, I found out another solution - but it's much more heavy:

 

IntPtr[] lpFileNamesEx = new IntPtr[fileLocalFullNames.Length];

for (int i = 0; i < fileLocalFullNames.Length; i++)

{

lpFileNamesEx = Marshal.StringToCoTaskMemAnsi(fileLocalFullNames);

}

fixed (IntPtr* p = &lpFileNamesEx[0])

{

int nRes = SccHistory(pContext,

ownerHwnd,

lpFileNamesEx.Length,

p,

iOptions,

&lOptions);

if (nRes != 0)

{

throw new Exception("SccHistory() call failed with error code " + nRes.ToString());

}

}

 

Here fileLocalFullNames is the string array of file names. And the function should be declared like this:

 

[DllImport(@"C:\Program Files\Microsoft Visual Studio\COMMON\VSS\win32\ssscc.dll")]

private static extern int SccHistory(IntPtr ppContext,

IntPtr hWnd,

int nFiles,

IntPtr* lpFileNames,

int fOptions,

long* pvOptions);

 

So thanks once more!

Posted (edited)

Function declaration

 

Personally, I think you should avoid using pointers and other unsafe code in C# whenever possible. In this case the function could be declared as:

 

[DllImport(@"C:\Program Files\Microsoft Visual Studio\COMMON\VSS\win32\ssscc.dll")]
private static extern int SccHistory(
   IntPtr ppContext,
   IntPtr hWnd,
   int nFiles,
   [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)]
   String[] lpFileNames,
   int fOptions,
   ref CmdOpts pvOptions
);

 

The declaration of the last parameter depends on whether the CmdOpts type is declared as a value type (struct) or reference type (class) in C#. If it is a struct then you need the ref modifier as shown, so that a pointer is passed. If it is a class, then you must omit the ref as classes are always passed by reference. If it is a struct, you may have to specify MarshalAs for some of the members, though I assume you've already got that sorted.

 

Good luck :cool:

Edited by MrPaul
Never trouble another for what you can do for yourself.
Posted

Well, I would be happy not to use unsafe code, but I couldn't declare the function

 
===== C++ Declaration: =====
SCCRTN SccInitialize(
 LPVOID* ppvContext,
 HWND hWnd,
 LPCSTR lpCallerName,
 LPSTR lpSccName,
 LPLONG lpSccCaps,
 LPSTR lpAuxPathLabel,
 LPLONG pnCheckoutCommentLen,
 LPLONG pnCommentLen
);

other than

 
[[color=teal]DllImport[/color]([color=darkred]@"C:\Program Files\Microsoft Visual Studio\COMMON\VSS\win32\ssscc.dll"[/color])]
[color=blue]private static extern int[/color] SccInitialize(
 [color=teal]IntPtr*[/color] ppContext,
 [color=teal]IntPtr[/color] hWnd,
 [color=teal]String[/color] lpCallerName,
 [color=blue]byte[/color][] lpSccName,
 [color=blue]long[/color]* lpSccCaps,
 [color=blue]byte[/color][] lpAuxPathLabel,
 [color=blue]long[/color]* CheckoutCommentLen,
 [color=blue]long[/color]* CommentLen
);

I tried other ways but failed. So I had to start using unsafe code and pointers.

 

Besides, I have no idea what should LPCMDOPTS look like in C#. I only know that I will never pass anything to the pvOptions argument and that in SSC.H there's a following definition:

typedef LPVOID LPCMDOPTS;

It doesn't really matter how this will be declared in C# - I only need to have a possibility to supply null or zero for the pvOptions argument.

Posted

Safe function declarations

 

An equivalent declare might be

 

[DllImport(@"C:\Program Files\Microsoft Visual Studio\COMMON\VSS\win32\ssscc.dll")]
private static extern int SccInitialize(
 ref IntPtr ppContext,
 IntPtr hWnd,
 [MarshalAs(UnmanagedType.LPStr)] String lpCallerName,
 byte[] lpSccName,              /* Could also use StringBuilder */
 ref int lpSccCaps,             /* C++ LONG == C# int */
 byte[] lpAuxPathLabel,         /* Could also use StringBuilder */
 ref int CheckoutCommentLen,    /* C++ LONG == C# int */
 ref int CommentLen             /* C++ LONG == C# int */
);

 

In this case we're just replacing the pointers with ref parameters, as it achieves the same thing. If you need to use the returned ppContext structure, you can use Marshal.PtrToStructure. There are very few functions which cannot be declared in safe code. Of course if you're happy using unsafe code blocks then there is no problem, but you are very rarely forced to.

 

As for the lpCmdOpts parameter in the previous post, if you do not intend to use it then you may be able to get away with declaring it as IntPtr pvOptions and then passing IntPtr.Zero when you call it.

 

Good luck :)

Never trouble another for what you can do for yourself.
Posted

Thanks a lot!

At last I managed to call several dialogs from the SSSCC.DLL. And all code is unsafe now.

Anyone who is interested in working with this library (and that's the access to MS SourceSafe thru MSSCCI interface) - plz review the C# solution at this link.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...