Click here to Skip to main content
15,885,985 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

Thank you very much for your kind help the other day.

Last time I got stuck in the method of outputting in the BSTR structure and passing it to VB, but this time I got stuck in the method of passing it from VB to VC++ as input.
I thought I should do the opposite of what I did last time, but maybe because I'm inexperienced, it didn't go so easily...So, if you don't mind, can I ask for your help?



<What I want to do>
I would like to know how to pass a structure marshaled in VB to VC++ as a BSTR structure.

 VB(screen/FORM):Structure(MarshalAs(UnmanagedType.Bstr)
 ↓
 VC++(DLL):typedef(BSTR)




<Development Environment>
 Windows7(32bit)
 VisualStudio2008(VB/VC++)


<Execution Environment>
 Windows7(32bit)



Thank you.

What I have tried:

I tried the following source code with reference to the previous solution, but an error occurred when the Bstr structure was referenced on the VC++ side.

I want to call the function with the "tpNonPosDet2" structure on the VB side as an argument and receive the data as the "NPOS_DETAIL_UPD2" structure on the VC++ side.

【esql_com.h】
C++
typedef struct {
	char	szFunctionFlag[2];
	char	szServiceNo[16];
	char	szPosNo[6];
	char	szSeqNo[6];
	char	szCreateDate[10];
	char	szCreateTime[6];
	char	szSalMoney[13];
	char	szRiyuCode[4];
	char	szServiceRank[4];
	char	szServiceRankAdd[4];
	char	szServiceTime[6];
	char	szChangeTime[6];
	char	szTantoCode[10];
	char	szCustKubn[4];
	char	szKozaNo[27];
	char	szKozaType[4];
} NPOS_DETAIL_UPD;

typedef struct {
	BSTR	szFunctionFlag;
	BSTR	szServiceNo;
	BSTR	szPosNo;
	BSTR	szSeqNo;
	BSTR	szCreateDate;
	BSTR	szCreateTime;
	BSTR	szSalMoney;
	BSTR	szRiyuCode;
	BSTR	szServiceRank;
	BSTR	szServiceRankAdd;
	BSTR	szServiceTime;
	BSTR	szChangeTime;
	BSTR	szTantoCode;
	BSTR	szCustKubn;
	BSTR	szKozaNo;
	BSTR	szKozaType;
} NPOS_DETAIL_UPD2;



__declspec(dllexport) int __stdcall Esql_UpNonPos(PS_HEADER_UPD *lpHeader, long *nIndexNum, NPOS_DETAIL_UPD2 *lpDetail);




【Esql_com.sc】
C++
// I used SAFEARRAY in VC++6.0, but I can't find a method that works well in VC++9.0, so I used another method.
//__declspec(dllexport) int __stdcall Esql_UpNonPos
//                           (PS_HEADER_UPD *lpHeader, long *nIndexNum, LPSAFEARRAY *lpDetail)
__declspec(dllexport) int __stdcall Esql_UpNonPos
                           (PS_HEADER_UPD *lpHeader, long *nIndexNum, NPOS_DETAIL_UPD2 *lpDetail)
{
	long	lCount=0;
	int		ii;
	int		nSqlstate;                   // SQL Return Code
	char	*work;                       // WorkArea
	PS_HEADER_UPD		wk_Header;       // Header Information
	NPOS_DETAIL_UPD		wk_Detail;       // Detail Information
	long				iRet;            // Return Code
	NPOS_DETAIL_UPD2	npos;				// For structure reference
//	LPSAFEARRAY			psa = *lpDetail;	// For structure reference
	int					idx[1], lb, ub;		// For structure reference
	static char			bufa[1024];			// For structure reference
	static wchar_t		bufw[1024];			// For structure reference
	static size_t		st;					// Work Area
	static char     	mbs[256];           // Test Area For MessageBox


//*****************************************************************************
//	Processing start setting
//*****************************************************************************

	EXEC SQL WHENEVER SQLERROR  GOTO :SQL_ERROR;

	EXEC SQL SET TRANSACTION READ WRITE;

//*****************************************************************************
//	SQL
//*****************************************************************************
  	MessageBox( NULL, TEXT("Esql_UpNonPos"), TEXT("Esql_com.sc"), MB_OK);
  	MessageBox( NULL, TEXT(lpHeader->szServiceNo), TEXT("Esql_com.sc"), MB_OK);



//	Setting for structure reference
//================================
	setlocale(LC_ALL,"Japanese");
//	SafeArrayLock(psa);
//	SafeArrayGetLBound(psa, 1, &lb);
//	SafeArrayGetUBound(psa, 1, &ub);
//	idx[0] = lb;
	idx[0] = 0;



//	Setting for detail information
//================================
	EXEC SQL WHENEVER NOT FOUND CONTINUE;
	for(ii=0; ii<*nIndexNum; ii++) {
		// I used SAFEARRAY in VC++6.0, but I can't find a method that works well in VC++9.0, so I used another method.
//		SafeArrayGetElement(psa, &idx[0], &npos);
		npos = lpDetail[idx[0]];    //←I get an error here. 

		// Reference of processing flag [add/delete etc] (obtained from argument structure)
		MessageBox( NULL, TEXT(" 0.1  START"), TEXT("Esql_UpNonPos"), MB_OK);
		*bufa = 0x00;
		wcsncpy_s(bufw, 1024, npos.szFunctionFlag, 2);
		wcstombs_s(&st, NULL,     0,  &bufw, 1024);
		wcstombs_s(&st, &bufa[0], st, &bufw, 1024);
		memset(wk_Detail.szFunctionFlag, '\0', sizeof(wk_Detail.szFunctionFlag));
		strncpy_s(wk_Detail.szFunctionFlag, sizeof(wk_Detail.szFunctionFlag), bufa, 2-1);
		MessageBox( NULL, TEXT(" 0.1  END"), TEXT("Esql_UpNonPos"), MB_OK);
		MessageBox( NULL, TEXT(wk_Detail.szFunctionFlag), TEXT("Esql_UpNonPos Structure  1"), MB_OK);
・
・
・




【API_Refer.vb】
VB
<DllImport("Esql_DLL.dll", CharSet:=CharSet.Ansi)> _
Public Function Esql_UpNonPos(<[In]()> ByVal Up_dtpPSHead As tpPS_Hed2, ByRef RecordCnt As Long, <[In]()> ByVal Up_dtpNonPosDet() As tpNonPosDet2) As Integer
End Function




【mdlPkSrv.vb】
VB
 <StructLayout(LayoutKind.Sequential)> _
 Structure tpNonPosDet2
     <MarshalAs(UnmanagedType.BStr)> Dim strShoriFlg As String
     <MarshalAs(UnmanagedType.BStr)> Dim strSrvNo As String
     <MarshalAs(UnmanagedType.BStr)> Dim strPosNo As String
     <MarshalAs(UnmanagedType.BStr)> Dim strTuuban As String
     <MarshalAs(UnmanagedType.BStr)> Dim strToriDate As String
     <MarshalAs(UnmanagedType.BStr)> Dim strToriTime As String
     <MarshalAs(UnmanagedType.BStr)> Dim strKingaku As String
     <MarshalAs(UnmanagedType.BStr)> Dim strRiyuCd As String
     <MarshalAs(UnmanagedType.BStr)> Dim strSrvRank As String
     <MarshalAs(UnmanagedType.BStr)> Dim strAddSrvRank As String
     <MarshalAs(UnmanagedType.BStr)> Dim strSrvTime As String
     <MarshalAs(UnmanagedType.BStr)> Dim strChgTime As String
     <MarshalAs(UnmanagedType.BStr)> Dim strHanbaiinCd As String
     <MarshalAs(UnmanagedType.BStr)> Dim strCostomKbn As String
     <MarshalAs(UnmanagedType.BStr)> Dim strKozaNo As String
     <MarshalAs(UnmanagedType.BStr)> Dim strKozaSbh As String
End Structure




【frmPkSrv1.vb】
VB
Ret = Esql_UpNonPos(dtp_GotHedData, RecordCnt, dtp_NonPosDet)
Posted
Updated 30-Nov-22 6:56am
v4
Comments
Richard Deeming 25-Nov-22 5:04am    
"... an error occurred ..."
You need to provide the full details of the error.
Dave Kreskowiak 25-Nov-22 12:22pm    
It's not a "BSTR structure". It's a structure containing BSTRs. Yes, it matters.
Marino_Y0301 28-Nov-22 3:13am    
I'm sorry. and thank you for pointing that out.
longjmp 25-Nov-22 21:29pm    
I have updated a new demo at:
http://ladder.42web.io/src/CppSvc2.7z[^]

please look at the two projects:
VBClient\CppDll.
the key is to give the buffer size (count of structs) to Marshal service.
Marino_Y0301 30-Nov-22 3:35am    
Thank you for your kindness.
I checked two projects, but I can't understand how to setting keys.
How can I count the buffer size (count of structs)?
In the project you gave me, it seemed to display the received value by using "CString". For example, is it possible to modify this example to get the value with "wcsncpy_s" instead of "CString" and use "strncpy_s" to store the value in another struct containing a Char?
That's what I want to do...

1 solution

hi Marino_Y0301:
I checked two projects, but I can't understand how to setting keys.


VB
<DllImport("CppDll.dll", SetLastError:=False, CharSet:=CharSet.Unicode)> _
    Private Shared Function GetDatFromVB(<[In](), [MarshalAs](UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal rIn As MyStruct(), _
        ByVal iLen As Integer, _
        <[Out]()> ByRef rOut As MyStruct) As Integer
    End Function


set the array size like this:
UnmanagedType.LPArray
means this parameter is an struct-array but not one struct,
and
SizeParamIndex:=1
tells marshal service that next parameter (the 1st parameter) is the size of array.

is it possible to modify this example to get the value with "wcsncpy_s" instead of "CString" and use "strncpy_s" to store the value in another struct containing a Char?


CString can be converted to a LPCTSTR like this:
C++
CString s(L"XXX");
static_cast<lpctstr>(s); 
<pre>

you can also reference the BSTR/LPTSTR/WCHAR[] members of the struct,
Marshal service make sure they hold the correct strings.

if you want to convert a unicode string to mbcs string, use W2A_CP with a codepage,
then you can invoke strncpy_s with that mbcs string.

the new example CppSvc3.7z:
<a href="http://ladder.42web.io/src/CppSvc3.7z">http://ladder.42web.io/src/CppSvc3.7z</a>[<a href="http://ladder.42web.io/src/CppSvc3.7z" target="_blank" title="New Window">^</a>]
 
Share this answer
 
Comments
Marino_Y0301 13-Dec-22 3:40am    
Sorry for the late reply. Thanks for the detailed explanation.
For DB reasons, the source extension cannot be changed from ".sc" to ".cpp".
Unfortunately the method you taught didn't work for me.
longjmp 13-Dec-22 4:28am    
I understand that you need to put some c++ code in .sc files instead of .cpp files, if that's the case, it's no problem, the VC++ compiler provides the option to treat any file as a c++ source file, and you can set /Tp filename.sc to do that.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900