> =Groups("\\myserver","user") && display global groups >>or
> =Groups("\\myserver","user",.T.) && display local groups >>
>*** GROUPS.PRG *** >PARAMETERS cServer, cUser, local > > DECLARE INTEGER NetApiBufferFree IN netapi32 INTEGER Buffer > > DECLARE INTEGER NetUserGetLocalGroups IN netapi32 ; > string @ servername, ; > string @ username, ; > integer lvl, ; > integer flags, ; > integer @ buffer, ; > integer maxlen, ; > integer @ entriesread, ; > integer @ total > > DECLARE INTEGER NetUserGetGroups IN netapi32 ; > string @ servername, ; > string @ username, ; > integer lvl, ; > integer @ buffer, ; > integer maxlen, ; > integer @ entriesread, ; > integer @ total > > DECLARE RtlMoveMemory IN kernel32 ; > STRING @ Destination, INTEGER Source, INTEGER nLength > > #DEFINE GROUPINFO_0_SIZE 4 > #DEFINE MAX_PREFERRED_LENGTH -1 > #DEFINE StrBufferLength 250StrBufferLength may need to be significantly larger, since the buffer will hold a Unicode string for a group, which might be as long as 256 characters (a Unicode character is two bytes long) plus a trailing double null. I'd try 514 instead.
> > STORE 0 TO lnBuffer, lnEntriesRead, lnTotalEntries > > cServer = STRCONV(cServer, 5) > cUser = STRCONV(cUser,5)These really should be STRCONV(STRCONV(VFP string,1),5) since it's likely that VFP is using the ANSI single-byte representation, and I'd explicitly add CHR(0)+CHR(0) to the end of each string to ensure that the string is null-terminated properly - VFP may not append the needed trailing null characters. VFP's internal strings are not LPSTR datatypes; the NTI contains the actual length of the array of characters assigned to the string variable, which permits us to embed arbitrary binary content to string variables, binary character fields and binary memo fields.
> IF local > lnResult = NetUserGetLocalGroups(cServer , ; > cUser, ; > 0,; > 0, ; > @lnBuffer, ; > MAX_PREFERRED_LENGTH, ; > @lnEntriesRead , ; > @lnTotalEntries) > ELSE > lnResult = NetUserGetGroups(cServer , ; > cUser, ; > 0,; > @lnBuffer, ; > MAX_PREFERRED_LENGTH, ; > @lnEntriesRead , ; > @lnTotalEntries) > ENDIF > > IF lnResult != 0 > ? "Error code:", lnResult > RETURN > ENDIF > > lcBuffer = Repli (Chr(0),StrBufferLength) > = RtlMoveMemory (@lcBuffer, lnBuffer, StrBufferLength) > > * scanning returned entries > FOR lnEntry = 1 TO lnEntriesRead > * copying the UserInfo structure to a VFP string > lcGroupInfo = SUBSTR (lcBuffer,; > (lnEntry-1)*GROUPINFO_0_SIZE+1, GROUPINFO_0_SIZE) > > lpwstrGroupname = buf2dword (SUBSTR(lcGroupInfo, 1,4)) > > * copying data from pointers to VFP strings > lcGroupname = getStrFromMem (lpwstrGroupname) > > ? "Member of group:", lcGroupName > ENDFOR > > * this buffer is allocated by the system and must be freed > = NetApiBufferFree (lnBuffer) > >RETURN > >FUNCTION getStrFromMem (lnMemBlock) > * converting allocated in memory Unicode string to a VFP string > LOCAL lcBuffer > lcBuffer = SPACE(StrBufferLength) > = RtlMoveMemory (@lcBuffer, lnMemBlock, StrBufferLength)You can use lstrcpyW() instead of RtlMoveMemory() to handle copying Unicode strings, making life a lot easier. You can template lstrcpyW() from the lstrcpy() code in the GetMemString() UDF in ClsHeap.
> lcBuffer = SUBSTR (lcBuffer, 1, AT(Chr(0)+Chr(0),lcBuffer)-1) >RETURN STRTRAN(lcBuffer, Chr(0),"")Rather than this, use STRCONV(STRCONV(lcBuufer,6),2). Better et, implement and use WideCharToMultiByte() from the Platform SDK to do the whole thing for you, an API call offered by KERNEL32.DLL; if you use a Win9x OS, you may need to add UnicoWS.dll - the Microsoft Layer for Unicode DLL, and may need to make additional code changes; there's a whole section on Unicode issues with Win9x/ME in the MSDN docs. WideCharToMultiByte would look like:
DEFINE INTEGER WideCharToMultiByte IN KERNEL32 ; INTEGER CodePage, ; INTEGER dwFlags, ; INTEGER lpWideCharStr, ; INTEGER cchWideChar, ; STRING @ lpMultiByteStr, ; INTEGER cbMultiByte, ; INTEGER lpDefaultChar, ; INTEGER @ lpUsedDefaultCharlpWideCharStr should be the pointer to the Group Name in lnMemBlock, ccWideChar should be 0, indicating it is null-terminated, lpMultiByteString should be a pre-inited VFP string variable, cbMultiByte it's length. I use codepage 437 in general; YMMV. All other values should be 0, so:
cMyBuff = SPACE(257) nResult=WideCharToMultiByte(437,0,lnMemBlock,0,@cMyBuff,257,0,0)
> >FUNCTION buf2dword (lcBuffer) > RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ; > Asc(SUBSTR(lcBuffer, 2,1)) * 256 +; > Asc(SUBSTR(lcBuffer, 3,1)) * 65536 +; > Asc(SUBSTR(lcBuffer, 4,1)) * 16777216 >Rather than this, I'd use the conversion DWORDToNum() from my ClsHeap class because of both speed and casting issues with a pointer address which uses the high-order bit; you could recast by wrapping the return value with BITOR(your return value,0)
>*** end GROUPS.PRG ***
>