Imported C-function works in C# but not in VB6 - c#

I'm working on a problem for a few days now and can't seem to find the answer. I have a third party dll written in C, which i have to use in an VB6 application.
The function inside dll looks something like this:
someFunction(WContext* context, const unsigned char* seed, int seedLength, const unsigned char* name, int nameLength,
const unsigned char* pin, int pinLength, const char* description)
I have an example written in c#. I tried it out and it works just fine. This is what it looks like in C#
[DllImport("Filename.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int someFunction(IntPtr context, byte[] seed, int seedLength, byte[] name, int nameLength,
byte[] pin, int pinLength, string description)
This is later used in the example like this:
byte[] seed = Encoding.ASCII.GetBytes("seed")
byte[] name = Encoding.ASCII.GetBytes("name")
byte[] pin = Encoding.ASCII.GetBytes("1234")
string description = "description"
int result = someFunction(context, seed, seed.length, name, name.Length, pin, pin.Length, description)
Now this works just fine in C#. I get 0 as a result which means in that case that the operation was a success.
I want to make this work in VB6. I tried it with some other functions of the dll and they work just like they should. This one gives me a headache. Here is what I tried just like with any other function:
First I imported the function into my code so I could use it later. I did this with a few other functions the same way and it worked fine.
Private Declare Function someFunction Lib "C:\DllPath\Filename.dll" (ByVal context As Long, ByRef seed as Byte, _
ByVal seedLength As Integer, ByRef name As Byte, _
ByVal nameLength As Integer, ByRef pin As Byte, _
ByVal pinLength As Integer, ByVal description As String) As Integer
Next Step was for me to call the function. I did it this way:
(I do get the context from another function earlier so this already has a value. Other functions work fine with that variable)
Dim seed() As Byte
Dim seedLength As Integer
Dim name() As Byte
Dim nameLength As Integer
Dim pin() As Byte
Dim pin As Integer
Dim description As String
Dim result as Integer
seed = StrConv("seed", vbFromUnicode)
seedLength = UBound(seed) + 1
name = StrConv("name", vbFromUnicode)
nameLength = UBound(name) + 1
pin = StrConv("1234", vbFromUnicode)
pinLength = UBound(pin) + 1
description = "description"
result = someFunction(context, seed(0), seedLength, name(0), nameLength, pin(0), pinLength, description)
The value for result is 1. By the documentation I got this means invalid parameter. Now I researched a lot. Read that in VB6 I have to give the first element of the byte array just like I did in my code. Tried it first with the whole array, got the same result. I think it has something to do with the arrays since its the first function that I've taken over to my code that had those. I'm also not really that native with VB6 but I have to do this. Maybe some of you guys know why this doesn't work. Probably just a minor mistake by myself.

In VB6 it's as simple as this
Option Explicit
Private Declare Function someFunction Lib "C:\DllPath\Filename.dll" (ByVal context As Long, ByVal seed As String, _
ByVal seedLength As Long, ByVal name As String, _
ByVal nameLength As Long, ByVal pin As String, _
ByVal pinLength As Long, ByVal description As String) As Long
Private Sub Form_Load()
Dim context As Long
Dim seed As String
Dim name As String
Dim pin As String
Dim description As String
Dim result As Long
seed = "seed"
name = "name"
pin = "1234"
description = "description"
result = someFunction(context, seed, Len(seed), name, Len(name), pin, Len(pin), description)
End Sub
Just don't use Integer at all (only Longs) use ByVal ... As String for the runtime to do the Unicode->ANSI conversion and be done with it.
The original API is weirdly declared with unsigned char * pointer and separate int length parameter probably because the seed, name and pin strings can contain \0 embedded while description is plain zero-terminated string which explains the PITA w/ the C/C++ prototype.
VB6 strings are length-prefixed (and zero-terminated) from get go and can contain Chr$(0) by design so there is no need to take any additional measures like in C# sample w/ explicit byte[] arrays conversion and function prototype signature fiddling. Just use ByVal ... As String in the API declare.

When calling a declared API, VB6 will convert a String to an ANSI byte array automatically, so you can declare seed, name, and pin as ByVal Strings.
Description is a bit confusion to me though, since I don't see a length being passed for that one. Is this really a null-terminated string (pszDescription)? How does the API you are calling know how long this character buffer is?

You can try to change the function declaration in VB, making seed, name, and pin ByRef As Byte(),
note the parentheses:
Private Declare Function someFunction Lib "C:\DllPath\Filename.dll" (ByVal context As Long, ByRef seed as Byte(), _
ByVal seedLength As Integer, ByRef name As Byte(), _
ByVal nameLength As Integer, ByRef pin As Byte(), _
ByVal pinLength As Integer, ByVal description As String) As Integer
Then, when calling the function, pass the entire arrays, not the first elements:
result = someFunction(context, seed, seedLength, name, nameLength, pin, pinLength, description)

Related

How to close all anonym, running Excel applications without killing [duplicate]

I want to use something similar to
GetObject(,"Excel.Application") to get back the application I created.
I call CreateObject("Excel.Application") to create Excel instances. Later if the VBA project resets, due to debugging and coding, the Application object variables are lost but the Excel instances are running in the background. Kind of a memory leak situation.
I want to re-attach to either re-use (preferred way) or close them.
To list the running instances of Excel:
#If VBA7 Then
Private Declare PtrSafe Function AccessibleObjectFromWindow Lib "oleacc" ( _
ByVal hwnd As LongPtr, ByVal dwId As Long, riid As Any, ppvObject As Object) As Long
Private Declare PtrSafe Function FindWindowExA Lib "user32" ( _
ByVal hwndParent As LongPtr, ByVal hwndChildAfter As LongPtr, _
ByVal lpszClass As String, ByVal lpszWindow As String) As LongPtr
#Else
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" ( _
ByVal hwnd As Long, ByVal dwId As Long, riid As Any, ppvObject As Object) As Long
Private Declare Function FindWindowExA Lib "user32" ( _
ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Long
#End If
Sub Test()
Dim xl As Application
For Each xl In GetExcelInstances()
Debug.Print "Handle: " & xl.ActiveWorkbook.FullName
Next
End Sub
Public Function GetExcelInstances() As Collection
Dim guid&(0 To 3), acc As Object, hwnd, hwnd2, hwnd3
guid(0) = &H20400
guid(1) = &H0
guid(2) = &HC0
guid(3) = &H46000000
Set GetExcelInstances = New Collection
Do
hwnd = FindWindowExA(0, hwnd, "XLMAIN", vbNullString)
If hwnd = 0 Then Exit Do
hwnd2 = FindWindowExA(hwnd, 0, "XLDESK", vbNullString)
hwnd3 = FindWindowExA(hwnd2, 0, "EXCEL7", vbNullString)
If AccessibleObjectFromWindow(hwnd3, &HFFFFFFF0, guid(0), acc) = 0 Then
GetExcelInstances.Add acc.Application
End If
Loop
End Function
This would be best as a comment on Florent B.'s very useful function that returns a collection of the open Excel instances, but I don't have sufficient reputation to add comments. In my tests, the collection contained "repeats" of the same Excel instances i.e. GetExcelInstances().Count was larger than it should have been. A fix for that is the use of the AlreadyThere variable in the version below.
Private Function GetExcelInstances() As Collection
Dim guid&(0 To 3), acc As Object, hwnd, hwnd2, hwnd3
guid(0) = &H20400
guid(1) = &H0
guid(2) = &HC0
guid(3) = &H46000000
Dim AlreadyThere As Boolean
Dim xl As Application
Set GetExcelInstances = New Collection
Do
hwnd = FindWindowExA(0, hwnd, "XLMAIN", vbNullString)
If hwnd = 0 Then Exit Do
hwnd2 = FindWindowExA(hwnd, 0, "XLDESK", vbNullString)
hwnd3 = FindWindowExA(hwnd2, 0, "EXCEL7", vbNullString)
If AccessibleObjectFromWindow(hwnd3, &HFFFFFFF0, guid(0), acc) = 0 Then
AlreadyThere = False
For Each xl In GetExcelInstances
If xl Is acc.Application Then
AlreadyThere = True
Exit For
End If
Next
If Not AlreadyThere Then
GetExcelInstances.Add acc.Application
End If
End If
Loop
End Function
#PGS62/#Philip Swannell has the correct answer for returning a Collection; I can iterate all instances; and it is brilliant, as #M1chael comment.
Let's not confuse Application objects with Workbook objects... ...Of
course it would be possible to write a nested loop that loops over the
workbooks collection of each application object
This is the nested loop implemented and fully functional:
Sub Test2XL()
Dim xl As Excel.Application
Dim i As Integer
For Each xl In GetExcelInstances()
Debug.Print "Handle: " & xl.Application.hwnd
Debug.Print "# workbooks: " & xl.Application.Workbooks.Count
For i = 1 To xl.Application.Workbooks.Count
Debug.Print "Workbook: " & xl.Application.Workbooks(i).Name
Debug.Print "Workbook path: " & xl.Application.Workbooks(i).path
Next i
Next
Set xl = Nothing
End Sub
And, for Word instances, the nested loop:
Sub Test2Wd()
Dim wd As Word.Application
Dim i As Integer
For Each wd In GetWordInstancesCol()
Debug.Print "Version: " & wd.System.Version
Debug.Print "# Documents: " & wd.Application.Documents.Count
For i = 1 To wd.Application.Documents.Count
Debug.Print "Document: " & wd.Application.Documents(i).Name
Debug.Print "Document path: " & wd.Application.Documents(i).path
Next i
Next
Set wd = Nothing
End Sub
For Word you have to use what is explained in the end of this thread
I use the following to check if two instances are running, and display a message. It could be altered to close other instance... This may be of help... I need code to return a specific instance, and return for use similar to GetObject(,"Excel.Application")... I don't think it possible though
If checkIfExcelRunningMoreThanOneInstance() Then Exit Function
In module (some of the declarations are possible used for other code):
Const MaxNumberOfWindows = 10
Const HWND_TOPMOST = -1
Const SWP_NOSIZE = &H1
Const SWP_NOMOVE = &H2
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Public Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Global ret As Integer
Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Public Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Declare Function GetKeyNameText Lib "user32" Alias "GetKeyNameTextA" (ByVal lParam As Long, ByVal lpBuffer As String, ByVal nSize As Long) As Long
Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function FindWindow Lib "user32" _
Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Private Const VK_CAPITAL = &H14
Private Declare Function GetKeyState Lib "user32" _
(ByVal nVirtKey As Long) As Integer
Private Declare Function OpenProcess Lib "kernel32" ( _
ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long) As Long
Private Declare Function EnumProcesses Lib "PSAPI.DLL" ( _
lpidProcess As Long, ByVal cb As Long, cbNeeded As Long) As Long
Private Declare Function EnumProcessModules Lib "PSAPI.DLL" ( _
ByVal hProcess As Long, lphModule As Long, ByVal cb As Long, lpcbNeeded As Long) As Long
Private Declare Function GetModuleBaseName Lib "PSAPI.DLL" Alias "GetModuleBaseNameA" ( _
ByVal hProcess As Long, ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long
Private Const PROCESS_VM_READ = &H10
Private Const PROCESS_QUERY_INFORMATION = &H400
Global ExcelWindowName$ 'Used to switch back to later
Function checkIfExcelRunningMoreThanOneInstance()
'Check instance it is 1, else ask user to reboot excel, return TRUE to abort
ExcelWindowName = excel.Application.Caption 'Used to switch back to window later
If countProcessRunning("excel.exe") > 1 Then
Dim t$
t = "Two copies of 'Excel.exe' are running, which may stop in cell searching from working!" & vbCrLf & vbCrLf & "Please close all copies of Excel." & vbCrLf & _
" (1 Then press Alt+Ctrl+Del to go to task manager." & vbCrLf & _
" (2 Search the processes running to find 'Excel.exe'" & vbCrLf & _
" (3 Select it and press [End Task] button." & vbCrLf & _
" (4 Then reopen and use PostTrans"
MsgBox t, vbCritical, ApplicationName
End If
End Function
Private Function countProcessRunning(ByVal sProcess As String) As Long
Const MAX_PATH As Long = 260
Dim lProcesses() As Long, lModules() As Long, N As Long, lRet As Long, hProcess As Long
Dim sName As String
countProcessRunning = 0
sProcess = UCase$(sProcess)
ReDim lProcesses(1023) As Long
If EnumProcesses(lProcesses(0), 1024 * 4, lRet) Then
For N = 0 To (lRet \ 4) - 1
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, lProcesses(N))
If hProcess Then
ReDim lModules(1023)
If EnumProcessModules(hProcess, lModules(0), 1024 * 4, lRet) Then
sName = String$(MAX_PATH, vbNullChar)
GetModuleBaseName hProcess, lModules(0), sName, MAX_PATH
sName = Left$(sName, InStr(sName, vbNullChar) - 1)
If Len(sName) = Len(sProcess) Then
If sProcess = UCase$(sName) Then
countProcessRunning = countProcessRunning + 1
End If
End If
End If
End If
CloseHandle hProcess
Next N
End If
End Function
The I found:
Dim xlApp As Excel.Application
Set xlApp = GetObject("ExampleBook.xlsx").Application
Which gets the object if you know the name of the sheet currently active in Excel instance. I guess this could be got from the application title using the first bit of code. In my app I do know the filename.
This can accomplish what you want.
Determine if an instance of Excel is open:
Dim xlApp As Excel.Application
Set xlApp = GetObject(, "Excel.Application")
If an instance is running you can access it using the xlApp object. If an instance is not running you will get a run-time error (you might need/want an error handler). The GetObject function gets the first instance of Excel that had been loaded. You can do your job with it, and to get to others, you can close that one and then try GetObject again to get the next one, etc.
So you will be attaining your ok-but-second-preferred objective
(taken from http://excelribbon.tips.net/T009452_Finding_Other_Instances_of_Excel_in_a_Macro.html).
For attaining your preferred objective, I think that https://stackoverflow.com/a/3303016/2707864 shows you how.
Create an array of objects and store the newly created Excel.Application in the array. That way you can reference them as and when you need. Let's take a quick example:
In a module:
Dim ExcelApp(2) As Object
Sub Test()
Set ExcelApp(1) = CreateObject("Excel.Application")
ExcelApp(1).Visible = True
Set ExcelApp(2) = CreateObject("Excel.Application")
ExcelApp(2).Visible = True
End Sub
Sub AnotherTest()
ExcelApp(1).Quit
ExcelApp(2).Quit
End Sub
Run Test() macro and you should see two Excel Applications pop up. Then run AnotherTest() and the Excel Applications will quit. You can even set the array to Nothing after you are done.
You can get handle of running Excel applications using the script published on http://www.ozgrid.com/forum/showthread.php?t=182853. That should get you where you want to go.
You should use this code every time you need an Excel application object. This way, your code will only ever work with one application object or use a pre-existing one. The only way you could end up with more than one is if the user started more than one. This is both the code to open Excel and attach and reuse, like you want.
Public Function GetExcelApplication() As Object
On Error GoTo openExcel
Set GetExcelApplication = GetObject(, "Excel.Application")
Exit Function
openExcel:
If Err.Number = 429 Then
Set GetExcelApplication = CreateObject("Excel.Application")
Else
Debug.Print "Unhandled exception: " & Err.Number & " " & Err.Description
End If
End Function
If you wanted to close multiple instances you would need to call GetObject followed by .Close in a loop until it throws the error 429.
The details can be found in this Article

Robert Giesecke's Unmanaged Exports - OUT strings

I'm working from VBA into .NET.
I have a working version of an interface using CLI and stdcall
I'm trying to remove the resulting dependency on the C++ 2015 runtime, and it looks like I can do it using UnmanagedExports.
But I have a couple of questions.
Can I just use "ref string" as a parameter and have it work?
If so, can I replace it with "out string"?
In either cases, do I have to do any string/string length management?
I currently pass a couple of callbacks in as "int". From an example I saw elsewhere, it looks like on the C# side, using this, I should be able to replace those parameters with Func for a callback such as Function A(p1 as String, p2 as Long, p3 as String) as Long
Any advice would be much appreciated.
You need a combination of StrPtr, possibly StrConv on the Access side, and IntPtr on the .NET side:
'VBA7
Private Declare PtrSafe Function Command Lib "External.dll" (ByVal CommandName As String, ByVal Result As LongPtr, ByRef ResultLength As Long) As Long
'VBA pre7
Private Declare Function Command Lib "External.dll" (ByVal CommandName As String, ByVal Result As Long, ByRef ResultLength As Long) As Long
'Example to use.
'Result will be up to "i" characters - no new string involved
Dim i As Long, x As Long, strResult As String
i = 100
strResult = Space(i)
x = Command(CommandName, Arguments, StrPtr(strResult), i)
If you use StrConv, the string type is up to you. If you don't, the pointer will be pointing to a Unicode array.
C# side:
[DllExport("Command", CallingConvention.StdCall)]
public static int Command(string commandName, string arguments, IntPtr result, out /*or ref*/ int resultLength)
{
string inputStr = Marshal.PtrToStringUni(result); //Unicode
resultLength = inputStr.Length;
int x = MainFunc.Command(commandName, arguments, ref inputStr);
if(null == inputStr)
{
inputStr = "";
}
if(inputStr.Length > resultLength)
{
inputStr = inputStr.Substring(0, resultLength);
}
byte[] outputBytes = Encoding.Unicode.GetBytes(inputStr);
Marshal.Copy(outputBytes, 0, result, outputBytes.Length);
resultLength = inputStr.Length;
return x;
}

Assignment Expression in VB.Net

Unlike a = b = 5 in VB.NET - impossible?,
I am specifically asking for an extension method to overcome this.
In C#, you can do something like this, which is very helpful:
a = b = c = 16;
All variables end up being 16.
One of the answers in Why do assignment statements return a value? gives reasons why this is handy.
But in VB.Net, if you do:
Dim a, b, c As Integer
a = b = c = 16
All you get are 0's for a, b, and c.
I want to defeat this limitation by an extension method. Can this be done?
EDIT:
Here is the closest answer I personally could come up with:
<System.Runtime.CompilerServices.Extension()>
Public Function Assign(ByRef Operand1 As Object, ByRef Operand2 As Object) As Object
Operand1 = Operand2
Return Operand1
End Function
Even though it allows you do do this,
Dim a, b, c As Integer
a.Assign(b.Assign(c.Assign(16)))
it sure is clunky and imo harder to follow, but it's the closest thing to an direct answer to my actual question I could find. I welcome any improvements.
As mentioned in a = b = 5 in VB.NET = impossible? by γηράσκωδ'αείπολλάδιδασκόμε, VB uses the same operator for assignment and equality, and you can't make extension operators per Tim's comment, so the only way to do this is through an extension method like you have found.
The syntax of your extension method can be cleaner if you overload it to accept multiple arguments; I'll guess that 3 assignments is enough. Here it's written for the Integer type so you don't have to bother casting, but use Object if you prefer.
<System.Runtime.CompilerServices.Extension> _
Public Sub Assign(ByRef aInt As Integer, ByRef newInt As Integer)
newInt = aInt
End Sub
<System.Runtime.CompilerServices.Extension> _
Public Sub Assign(ByRef aInt As Integer, ByRef newInt1 As Integer, ByRef newInt2 As Integer)
newInt1 = aInt
newInt2 = aInt
End Sub
<System.Runtime.CompilerServices.Extension> _
Public Sub Assign(ByRef aInt As Integer, ByRef newInt1 As Integer, ByRef newInt2 As Integer, ByRef newInt3 As Integer)
newInt1 = aInt
newInt2 = aInt
newInt3 = aInt
End Sub
Usage:
Dim a, b, c, d As Integer
a = 16
a.Assign(b)
a.Assign(c, d)
Console.Write("b = {0}; c = {1}; d = {2}", New Object() {b, c, d})
a = 99
a.Assign(b, c, d)
Console.Write("b = {0}; c = {1}; d = {2}", New Object() {b, c, d})
You could keep going and add more overloads if you like, including one with an array or list if you want N assignments.

How to call this DLL function from either C++ / C#

I'm taking a lot of time trying to figure this out, so I thought I could get some help here.
Basically I have a DLL function declared like this in IDL:
[id(1), helpstring("method findFile")] HRESULT findFile(
[in] BSTR fileName,
[out] LONG* someValue
);
How exactly do I declare and invoke from either C++ / C#?
Note: there is a VB6 app that successfully invokes the function. Declaration is:
Private Declare Function findFile Lib "thedll.dll" ( _
ByVal fileName As String, _
ByRef someValueAs Long _
)
The call:
Dim a As String
Dim b As Long
Dim r As long
a = "image.jpg"
b = -1
r = findFile(a, b)
Addendum:
I cannot guarantee that the VB6 code looks like that because I have the executable, I was only told what that portion looks like, so maybe you guys are right and it doesn't match. I did author the C++ DLL, and now I need to get together some code myself that successfully calls the DLL in order to try out stuff and not depend on that exe.
C++ implementation of the DLL function looks like this:
STDMETHODIMP CFinder::findFile(BSTR fileName, LONG* someValue)
{
*someValue = 8;
return S_OK;
}
Untested C# declaration:
[DllImport("thedll.dll", SetLastError=true)]
static extern int findFile([MarshalAs(UnmanagedType.BStr)]string fileName, out int someValue);

Converting a function from Visual Basic 6.0 to C# is throwing AccessViolationException

I'm converting a function from Visual Basic 6.0 as:
Declare Function RequestOperation Lib "archivedll" (ByVal dth As Long, ByVal searchRequestBuf As String, ByVal buflen As Long, ByVal FieldNum As Long, ByVal OP As Long, ByVal value As String) As Long
In C#, I'm declare the function as:
[DllImport("archivedll")]
public static extern int RequestOperation(int dth ,StringBuilder searchRequestBuf, int bufferLen, int fieldNum, int op, string value);
When call RequestOperation from C#, it throws an exception:
[System.AccessViolationException] =
{"Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt."}
I have successful in calling many other functions like this, but only this function throws the exception.
This function is clearly not throwing an AccessViolationException - instead, it is generating an access violation fault by "attempting to read or write protected memory". .NET is translating that fault into an AccessViolationException.
You'll have to go figure out why it is "attempting to read or write protected memory". In particular, did you initialize the StringBuilder you are passing to it? Please post the code you use to call this method.
I think the StringBuilder in the function declaration has something to do with it. You should use just plain String instead.
/// Return Type: int
///dth: int
///searchRequestBuf: BSTR->OLECHAR*
///buflen: int
///FieldNum: int
///OP: int
///value: BSTR->OLECHAR*
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="RequestOperation")]
public static extern int RequestOperation(int dth, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.BStr)] string searchRequestBuf, int buflen, int FieldNum, int OP, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.BStr)] string value) ;

Categories

Resources