JavaScript调用ActiveX问题

lsy229199496 2008-12-22 09:35:46
最近做了一个ActiveX放在web上,用来录音的。但是出现问题如下:
1. 在第一次正常录音之后,需要关闭浏览器然后重新打开才能再执行
2. 如果去掉录音功能,以上问题就不存在了。
看了一些资料说是资源的问题,刚接触这方面不了解,请指点。代码如下
<HTML>
<HEAD>
<TITLE>Spring</TITLE>
<OBJECT id=Lsy align="CENTER" WIDTH=0 HEIGHT=0 codeBase="Spring.CAB#version=9,0,0,1" classid="CLSID:0264FD8A-953F-4B39-A881-336A79297008"></OBJECT>
<script language="javascript">
function doTest() {
var result = Lsy.Getsound();//这个是ActiveX的录音函数,如果把函数里的录音部分去掉就一点问题没有
alert(result);
}
</script>
</HEAD>
<input type="button" value="R.s" id="btnOK" onclick="doTest();"></input>
</HTML>

请指点。
...全文
246 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
lsy229199496 2008-12-22
  • 打赏
  • 举报
回复
这个dll只是最初用来测试的,呵呵,是的,你说的那些都没有呢,是打算一层一层做,所以这个dll基本上没有任何容错功能。改进ing呵呵,先把资源的问题处理掉。

对了,还想问你一些东西,就是我释放资源应该是在web里释放还是在ActiveX里还是在dll里直接最声卡资源进行释放?
这个不是很清楚。麻烦了
toury 2008-12-22
  • 打赏
  • 举报
回复
大致看了一下你的DLL代码,还是个“raw code”。容错、格式转换都没做。特别是容错,这样的应用没更详细的容错机制是不稳定的,例如,机器无声卡,有声卡但驱动错误,声卡被独占等等。。。

还有就是格式转换,建议你加上MP3格式,否则没有实用价值,呵呵
toury 2008-12-22
  • 打赏
  • 举报
回复
顺便说一下,如果你不加释放的话,时间长了会“伤害”到声卡:))
toury 2008-12-22
  • 打赏
  • 举报
回复
呵呵,是这个问题。
调用之后一定要关闭的。通常都在[停止录音]按钮下面写出释放代码。
时间久了,我忘记具体的写法了,你查一下wavein()、waveout()API的文档,加上就可以了
lsy229199496 2008-12-22
  • 打赏
  • 举报
回复
对!我突然想明白为什么了!我测试的是利用控制台,每次测试之后就会关闭了,自然就释放资源了!但是在web上一直没有关闭,肯定就没有释放!
对~~~是你说的那样!但是现在有什么办法解决呢?
问题出在哪里?
lsy229199496 2008-12-22
  • 打赏
  • 举报
回复
接下来的是录音的函数了,就是在录音的dll里面。这些就是源代码了,我只是多加了一个加法函数进行别的测试。请指点:
#include <iostream>
#include <windows.h>
#include <Mmsystem.h>
using namespace std;
#define DLL_EXPORT
#include "h_file.h"
#pragma comment(lib, "winmm.lib")
extern "C"
{
DECLDIR DWORD FCC(LPCWSTR lpcwStr)
{
DWORD Number = lpcwStr[0] + lpcwStr[1] *0x100 + lpcwStr[2] *0x10000 + lpcwStr[3] *0x1000000 ;
return Number;
}
DECLDIR int Add(int a , int b)
{
CreateMutexW (NULL , false , L"MyMutex"); //生成线程做什么?一定要生成线程么?
if( GetLastError() == ERROR_ALREADY_EXISTS )
{ ExitProcess(NULL);
MessageBoxW (NULL ,L"Exists and Exit" ,L"R.s" , MB_OK);
}
WORD datasize = 48000;
WAVEFORMATEX waveformat;
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.nChannels = 1;
waveformat.nSamplesPerSec = 8000;
waveformat.nAvgBytesPerSec = 8000;
waveformat.nBlockAlign = 1;
waveformat.wBitsPerSample = 8;
waveformat.cbSize = 0;
MessageBoxW ( NULL , L"Ensure to Create a HWAVEIN?" , L"R.s" , MB_OK);
HWAVEIN m_hWaveIn;
if ( waveInGetNumDevs() )
{MessageBoxW (NULL, L"Get the Equipment for Recording!" , L"R.s" , MB_OK);
}
else
{MessageBoxW (NULL, L"There isn't Equipment for Recording!" , L"R.s" , MB_OK);
}
//Find the Equipment , then open it!
int res = waveInOpen( &m_hWaveIn ,WAVE_MAPPER ,&waveformat ,(DWORD)NULL ,0L , CALLBACK_WINDOW);
if ( res == MMSYSERR_NOERROR)
{ MessageBoxW (NULL , L"Open the waveIn Successed!" , L"R.s" , MB_OK);
}
else
{MessageBoxW (NULL , L"Open the waveIn Failed!" , L"R.s" , MB_OK);
}
/////////////////////////////打开录音设备完成//////////////////////////////////////
MessageBoxW (NULL , L"Ensure to Define the header!" , L"R.s" , MB_OK);
WAVEHDR m_pWaveHdr; //定义了 用来确定波形缓冲区的 头
m_pWaveHdr.lpData /*指向波形缓冲区的指针*/
= (char *)GlobalLock(GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, datasize)); //用指针来开辟内存, 这里, datasize就确定了开辟多大的内存!
memset(m_pWaveHdr.lpData , 0 , datasize);
m_pWaveHdr.dwBufferLength = datasize;/*定义缓冲区的长度*/ //上面不是已经用到了 datasize 了么? 那么上面的datasize用来做什么呢?
m_pWaveHdr.dwBytesRecorded = 0;/*已经录音的字节长度*/
m_pWaveHdr.dwUser = 0;/*用户数据*/
m_pWaveHdr.dwFlags = 0;/*标记缓冲区的信息*/
m_pWaveHdr.dwLoops = 0;/*循环播放的次数,只适用在播放*/
///////////////////////////////定义缓冲区头文件完成/////////////////////////////////////////
int resPrepare = waveInPrepareHeader( m_hWaveIn , &m_pWaveHdr , sizeof(WAVEHDR) );
//准备一块录音缓冲区头文件
if ( resPrepare == MMSYSERR_NOERROR ) /*如果没有error*/
{MessageBoxW (NULL , L"Buffer is OK!" , L"R.s" , MB_OK);
}
else
{MessageBoxW (NULL , L"Buffer Error!" , L"R.s" , MB_OK);
return 0;
}
//准备录音头文件完毕
//在确定无错误之后,将内存交给音频输入设备
resPrepare = waveInAddBuffer( m_hWaveIn , &m_pWaveHdr , sizeof(WAVEHDR));
if ( resPrepare == MMSYSERR_NOERROR)
{MessageBoxW (NULL , L"Buffer has been Prepared" , L"R.s" , MB_OK);
}
else
{MessageBoxW (NULL , L"Sorry,Buffer can't be Prepared" , L"R.s" , MB_OK);
return 0;
} // End of 验证开辟缓冲
//以上检查缓冲区和准备缓冲区都完成了,接下来就开始录音了
MessageBoxW (NULL , L"按OK后开始录音" , L"R.s" , MB_OK);
if ( !waveInStart(m_hWaveIn) )
{ }
else
{MessageBoxW (NULL , L"无法录音" , L"R.s" , MB_OK);
}
Sleep(3200);
MMTIME mmt;
mmt.wType = TIME_BYTES;
if( !waveInGetPosition(m_hWaveIn , &mmt , sizeof(MMTIME) ) )
{MessageBoxW ( NULL , L"Get the wave Position!" , L"R.s" , MB_OK);
}
else
{MessageBoxW (NULL , L"Lost the Position of the wave!" , L"R.s" , MB_OK);
}
if (mmt.wType == TIME_BYTES)
{MessageBoxW (NULL , L"得到的 TIME_BYTES 格式的音频长度" , L"R.s" ,MB_OK);
}
else
{ MessageBoxW (NULL , L"指定的 TIME_BYTES 格式音频长度不支持!" , L"R.s" , MB_OK);
}
if ( !waveInReset(m_hWaveIn/*输入设备的句柄*/) )
/*停止输入设备的录制,并且将当前位置置为0 注意了,这里用到了输入设备的句柄,应该是岁输入设备进行操作的*/
MessageBoxW (NULL , L"Restart Buffer OK!" , L"R.s" , MB_OK);
else
{MessageBoxW (NULL , L"Restart Buffer Failed!" , L"R.s" , MB_OK);
}
m_pWaveHdr.dwBytesRecorded = mmt.u.cb;
//经过上述的所有步骤,现在的录音就完成了 , 都在内存里了 , 接下来就要保存进wav文件
DWORD NumToWrite=0; DWORD dwNumber = 0;
MessageBoxW (NULL , L"RECORD FINISH!" , L"R.s" , MB_OK);
HANDLE FileHandle =
CreateFileW( L"myTest.wav",GENERIC_WRITE, FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL);
dwNumber = FCC(L"RIFF");
WriteFile(FileHandle, &dwNumber, 4, &NumToWrite, NULL);
dwNumber = m_pWaveHdr.dwBytesRecorded + 18 + 20;
WriteFile(FileHandle, &dwNumber, 4, &NumToWrite, NULL);
dwNumber = FCC(L"WAVE");
WriteFile(FileHandle, &dwNumber, 4, &NumToWrite, NULL);
dwNumber = FCC(L"fmt ");
WriteFile(FileHandle, &dwNumber, 4, &NumToWrite, NULL);
dwNumber = 18L;
WriteFile(FileHandle, &dwNumber, 4, &NumToWrite, NULL);
WriteFile(FileHandle, &waveformat, sizeof(WAVEFORMATEX), &NumToWrite, NULL);
dwNumber = FCC(L"data");
WriteFile(FileHandle, &dwNumber, 4, &NumToWrite, NULL);
dwNumber = m_pWaveHdr.dwBytesRecorded;
WriteFile(FileHandle, &dwNumber, 4, &NumToWrite, NULL);
WriteFile(FileHandle, m_pWaveHdr.lpData, m_pWaveHdr.dwBytesRecorded, &NumToWrite, NULL);
SetEndOfFile(FileHandle);
CloseHandle( FileHandle ); FileHandle = INVALID_HANDLE_VALUE; // 收尾关闭句柄
//以上这些是写文件了
//完成写入文件之后 就要清理缓冲区了!
if ( !waveInUnprepareHeader(m_hWaveIn/*输入设备句柄*/, &m_pWaveHdr/*缓冲区指针*/, sizeof(WAVEHDR)/*清理的大小*/) )
MessageBoxW (NULL , L"Un_Prepare Header 成功" , L"R.s" ,MB_OK);
else
{MessageBoxW (NULL , L"Un_Prepare Header 失败!" , L"R.s" , MB_OK);
}
if ( !GlobalFree/*释放原来申请的内存空间*/
(GlobalHandle( m_pWaveHdr.lpData ))/*全局内存地址句柄*/)
MessageBoxW(NULL ,L"Global Free 成功!" , L"R.s" , MB_OK);
else
{MessageBoxW (NULL , L"Global Free 失败!" , L"R.s" , MB_OK);
}
if ( res == MMSYSERR_NOERROR ) //关闭录音设备
if (waveInClose(m_hWaveIn)==MMSYSERR_NOERROR)
MessageBoxW(NULL , L"正常关闭录音设备" , L"R.s" , MB_OK);
else
{MessageBoxW (NULL , L"非正常关闭录音设备" , L"R.s" , MB_OK);
}
//关闭设备完毕
return 0;
}
DECLDIR void Function(void)
{
cout<<"DLL Called!"<<endl;
}
}
lsy229199496 2008-12-22
  • 打赏
  • 举报
回复
我的做法是在一个dll里调用win32 API的wave函数, 然后用ActiveX调用这个dll 然后再把ActiveX放进web里,测试的是录音的dll,在本地进行
一下的是ActiveX的代码:
头文件的内容
class ATL_NO_VTABLE CRs :

public IObjectSafetyImpl<CRs, INTERFACESAFE_FOR_UNTRUSTED_CALLER| INTERFACESAFE_FOR_UNTRUSTED_DATA>,


public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CRs, &CLSID_Rs>,
public IConnectionPointContainerImpl<CRs>,
public CProxy_IRsEvents<CRs>,
public IObjectWithSiteImpl<CRs>,
public IDispatchImpl<IRs, &IID_IRs, &LIBID_Spring_RsLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:

typedef int (*AddFunc)(int,int); //类型定义,对应DLL ADD方法。Func自定义,随便写。

HINSTANCE hInstLibrary;

AddFunc _AddFunc; //类映射


CRs()
{
hInstLibrary = LoadLibrary(L"testing_dll.dll");

if (hInstLibrary == NULL)

{

FreeLibrary(hInstLibrary);//资源释放

}else{



}

//调用方法,返回方法句柄。

_AddFunc = (AddFunc)GetProcAddress(hInstLibrary, "Add");
}


cpp里的内容

STDMETHODIMP CRs::GetContent(LONG A, LONG B, LONG* out)
{
// TODO: Add your implementation code here

int sum = this->_AddFunc(static_cast<int>(A),static_cast<int>(B));

*out = static_cast<LONG>(sum);

this->_AtlFinalRelease();

return S_OK;
}
toury 2008-12-22
  • 打赏
  • 举报
回复
你的DLL是如何实现录音的?是用底层函数写的,还是简单的调用表层API实现的?两者之间无论是效果还是稳定性都
差远了去了....
toury 2008-12-22
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 lsy229199496 的回复:]
如果对声卡的操作不关闭的话,我在本地用程序对录音的dll进行测试,为什么又能多次正常录音呢?这点我觉得很奇怪···

还有别的可能的原因么?
[/Quote]

你在本地是如何测试的?把代码贴贴呢?

你是不是在SERVER端测试的DLL?
lsy229199496 2008-12-22
  • 打赏
  • 举报
回复
如果对声卡的操作不关闭的话,我在本地用程序对录音的dll进行测试,为什么又能多次正常录音呢?这点我觉得很奇怪···

还有别的可能的原因么?
luck_man911 2008-12-22
  • 打赏
  • 举报
回复
给Getsound()添加一个全局参数,最好是常用类型。。
每次点击的时候判断。
看这样能不能实现录音的停止功能。
lsy229199496 2008-12-22
  • 打赏
  • 举报
回复

我再试试
lsy229199496 2008-12-22
  • 打赏
  • 举报
回复
ActiveX构成是这样的,写了一个录音的dll,然后ActiveX影射录音dll里的方法,
在本地测试程序上测试录音dll(不包含ActiveX)的时候,一点问题没有。



但是我把录音dll的录音部分去掉,ActiveX不变,这样在web上进行测试又没有问题。如果ActiveX有问题,为什么在没有录音的情况下能正常执行呢?
这点也是我没明白的。


PS:ActiveXObject 的参数怎么设定?
toury 2008-12-22
  • 打赏
  • 举报
回复
有录音函数,没有停止录音函数吗?

不是第2次录音就JS不正常,而是插件之所以可以录音是因为它操作了声卡;你关了网页相当于插件自动释放了相关资源。因此关键在于你开始第2次录音以前要先停止以释放声卡资源
luck_man911 2008-12-22
  • 打赏
  • 举报
回复
应该和开始录音的方法相反,
就像连接数据库一样,
链接后,都有个关闭数据库的方法close();
如果没有,你自己想办法,在录音后调用一个函数。。
zjsfdxbao 2008-12-22
  • 打赏
  • 举报
回复
要不你试下每次点击时创建一次新对象
var obj = new ActiveXObject("你的Active引用");
然后引用方法obj.Getsound()

PS 我还是觉得你的ActiveX里没有很好的结束,Getsound()里面返回结果前没把状态恢复到可以接收下次声音
lsy229199496 2008-12-22
  • 打赏
  • 举报
回复
还是···不行···有别的办法么?
我觉得应该是JavaScript没有释放资源,不然关闭浏览器再开就没有问题了···
lsy229199496 2008-12-22
  • 打赏
  • 举报
回复
你的意思是说 ActiveX里没有正常结束?
ActiveX里的结束具体应该怎么做呢?
luck_man911 2008-12-22
  • 打赏
  • 举报
回复
function doTest() {

var obj=document.getElementById("Lsy");
var result = obj.Getsound();//这个是ActiveX的录音函数,如果把函数里的录音部分去掉就一点问题没有
alert(result);
}
试试。。
zjsfdxbao 2008-12-22
  • 打赏
  • 举报
回复
是不是你的ActiveX里没有正常结束
加载更多回复(3)

87,919

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧